diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..645c171a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/briefcase.yml b/.github/workflows/briefcase.yml index 99d6a6f2..3236d71c 100644 --- a/.github/workflows/briefcase.yml +++ b/.github/workflows/briefcase.yml @@ -16,8 +16,10 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -r src/requirements.txt - pip install briefcase + pip install pip-tools briefcase + pip-compile --generate-hashes --output-file=requirements.lock src/requirements.txt + git diff --exit-code requirements.lock + pip install --require-hashes -r requirements.lock - name: Build with Briefcase run: briefcase build - name: Upload artifacts diff --git a/.github/workflows/dependency-audit.yml b/.github/workflows/dependency-audit.yml new file mode 100644 index 00000000..d00033aa --- /dev/null +++ b/.github/workflows/dependency-audit.yml @@ -0,0 +1,27 @@ +name: Dependency Audit + +on: + schedule: + - cron: '0 0 * * 0' + workflow_dispatch: + +permissions: + contents: read + +jobs: + audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pip-tools pip-audit + pip-compile --generate-hashes --output-file=requirements.lock src/requirements.txt + git diff --exit-code requirements.lock + pip install --require-hashes -r requirements.lock + - name: Run pip-audit + run: pip-audit -r requirements.lock --ignore-vuln GHSA-wj6h-64fc-37mp diff --git a/.github/workflows/installer-smoke.yml b/.github/workflows/installer-smoke.yml new file mode 100644 index 00000000..51cca5c8 --- /dev/null +++ b/.github/workflows/installer-smoke.yml @@ -0,0 +1,125 @@ +name: Installer Smoke + +on: + pull_request: + paths: + - "scripts/install.sh" + - "scripts/install.ps1" + - "scripts/installer_smoke_unix.sh" + - "scripts/installer_smoke_windows.ps1" + - ".github/workflows/installer-smoke.yml" + workflow_dispatch: + schedule: + - cron: "17 4 * * *" + +jobs: + smoke_pr: + if: github.event_name == 'pull_request' + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + branch: beta + mode: tui + - os: windows-latest + branch: beta + mode: tui + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Unix installer smoke + if: runner.os != 'Windows' + run: | + set -euo pipefail + mkdir -p artifacts/installer-smoke + bash scripts/installer_smoke_unix.sh "${{ matrix.branch }}" "${{ matrix.mode }}" 2>&1 | tee "artifacts/installer-smoke/${{ runner.os }}-${{ matrix.branch }}-${{ matrix.mode }}.log" + + - name: Windows installer smoke + if: runner.os == 'Windows' + shell: pwsh + run: | + New-Item -ItemType Directory -Force -Path artifacts/installer-smoke | Out-Null + $log = "artifacts/installer-smoke/${{ runner.os }}-${{ matrix.branch }}-${{ matrix.mode }}.log" + & ./scripts/installer_smoke_windows.ps1 -Branch "${{ matrix.branch }}" -Mode "${{ matrix.mode }}" *>&1 | Tee-Object -FilePath $log + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + + - name: Upload installer smoke logs + if: always() + uses: actions/upload-artifact@v4 + with: + name: installer-smoke-logs-${{ runner.os }}-${{ matrix.branch }}-${{ matrix.mode }}-pr + path: artifacts/installer-smoke/*.log + if-no-files-found: warn + + smoke_full: + if: github.event_name != 'pull_request' + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + branch: main + mode: tui + - os: ubuntu-latest + branch: beta + mode: tui + - os: ubuntu-latest + branch: beta + mode: both + - os: macos-latest + branch: main + mode: tui + - os: macos-latest + branch: beta + mode: tui + - os: macos-latest + branch: beta + mode: both + - os: windows-latest + branch: main + mode: tui + - os: windows-latest + branch: beta + mode: tui + - os: windows-latest + branch: beta + mode: both + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Unix installer smoke + if: runner.os != 'Windows' + run: | + set -euo pipefail + mkdir -p artifacts/installer-smoke + bash scripts/installer_smoke_unix.sh "${{ matrix.branch }}" "${{ matrix.mode }}" 2>&1 | tee "artifacts/installer-smoke/${{ runner.os }}-${{ matrix.branch }}-${{ matrix.mode }}.log" + + - name: Windows installer smoke + if: runner.os == 'Windows' + shell: pwsh + run: | + New-Item -ItemType Directory -Force -Path artifacts/installer-smoke | Out-Null + $log = "artifacts/installer-smoke/${{ runner.os }}-${{ matrix.branch }}-${{ matrix.mode }}.log" + & ./scripts/installer_smoke_windows.ps1 -Branch "${{ matrix.branch }}" -Mode "${{ matrix.mode }}" *>&1 | Tee-Object -FilePath $log + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + + - name: Upload installer smoke logs + if: always() + uses: actions/upload-artifact@v4 + with: + name: installer-smoke-logs-${{ runner.os }}-${{ matrix.branch }}-${{ matrix.mode }}-full + path: artifacts/installer-smoke/*.log + if-no-files-found: warn diff --git a/.github/workflows/python-ci.yml b/.github/workflows/python-ci.yml index fd0608fe..ac312725 100644 --- a/.github/workflows/python-ci.yml +++ b/.github/workflows/python-ci.yml @@ -9,6 +9,20 @@ on: - cron: '0 3 * * *' jobs: + secret-scan: + name: Secret Scan + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' || github.event_name == 'schedule' + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Run gitleaks + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITLEAKS_CONFIG: .gitleaks.toml + build: strategy: matrix: @@ -59,18 +73,18 @@ jobs: uses: actions/cache@v3 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('src/requirements.txt') }} + key: ${{ runner.os }}-pip-${{ hashFiles('requirements.lock') }} restore-keys: | ${{ runner.os }}-pip- - - name: Set up Python dependencies - id: deps + - name: Verify lockfile and install dependencies run: | python -m pip install --upgrade pip - pip install -r src/requirements.txt - - name: Run pip-audit - run: | - pip install pip-audit - pip-audit -r requirements.lock --ignore-vuln GHSA-wj6h-64fc-37mp + pip install pip-tools + pip-compile --generate-hashes --output-file=requirements.lock src/requirements.txt + git diff --exit-code requirements.lock + pip install --require-hashes -r requirements.lock + - name: Run dependency scan + run: scripts/dependency_scan.sh --ignore-vuln GHSA-wj6h-64fc-37mp - name: Determine stress args shell: bash run: | diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..96660a7e --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,40 @@ +name: Tests + +on: + push: + branches: ["**"] + pull_request: + branches: ["**"] + +jobs: + test: + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ["3.10", "3.11", "3.12"] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install Poetry + run: pipx install poetry + - name: Install dependencies + run: poetry install + - name: Check formatting + run: poetry run black --check . + - name: Run security audit + run: | + poetry run pip-audit || echo "::warning::pip-audit found vulnerabilities" + shell: bash + - name: Run tests with coverage + run: | + poetry run coverage run -m pytest + poetry run coverage xml + - name: Upload coverage report + uses: actions/upload-artifact@v4 + with: + name: coverage-${{ matrix.os }}-py${{ matrix.python-version }} + path: coverage.xml + diff --git a/.gitignore b/.gitignore index c67b1b0d..c5d426df 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ node_modules/ # Ignore virtual environment directory venv/ +.venv/ # Ignore context tool directory context_tool/ @@ -48,3 +49,5 @@ src/seedpass.egg-info/top_level.txt # Allow vendored dependencies to be committed !src/vendor/ +torch/node_modules +torch/torch/ diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 00000000..d1b755ad --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,8 @@ +title = "SeedPass gitleaks config" + +[allowlist] + description = "Paths and patterns to ignore when scanning for secrets" + # Add file paths that contain test data or other non-sensitive strings + paths = [] + # Add regular expressions that match false positive secrets + regexes = [] diff --git a/AGENTS.md b/AGENTS.md index 2671cec4..889b2c42 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,6 +2,60 @@ This project is written in **Python**. Follow these instructions when working with the code base. +## Installation Quickstart for AI Agents + +### Prerequisites + +Ensure the system has the required build tools and Python headers. Examples: + +```bash +# Ubuntu/Debian +sudo apt update && sudo apt install -y \ + build-essential \ + libffi-dev \ + pkg-config \ + python3.11-dev \ + curl \ + git + +# CentOS/RHEL +sudo yum install -y gcc gcc-c++ libffi-devel pkgconfig python3-devel curl git + +# macOS +brew install python@3.11 libffi pkg-config git +``` + +### Installation + +Run the installer script to fetch the latest release: + +```bash +# Stable release +bash -c "$(curl -sSL https://raw.githubusercontent.com/PR0M3TH3AN/SeedPass/main/scripts/install.sh)" + +# Beta branch +bash -c "$(curl -sSL https://raw.githubusercontent.com/PR0M3TH3AN/SeedPass/main/scripts/install.sh)" _ -b beta +``` + +### Environment Layout + +- Virtual environment: `~/.seedpass/app/venv/` +- Entry point: `~/.seedpass/app/src/main.py` + +### Verification + +```bash +cd ~/.seedpass/app && source venv/bin/activate +cd src && python main.py --version # Expected: SeedPass v[version] +``` + +### Running SeedPass + +```bash +cd ~/.seedpass/app && source venv/bin/activate +cd src && python main.py +``` + ## Running Tests 1. Set up a virtual environment and install dependencies: @@ -9,7 +63,7 @@ This project is written in **Python**. Follow these instructions when working wi ```bash python3 -m venv venv source venv/bin/activate - pip install -r src/requirements.txt + pip install --require-hashes -r requirements.lock ``` 2. Run the test suite using **pytest**: @@ -39,6 +93,19 @@ This project is written in **Python**. Follow these instructions when working wi Following these practices helps keep the code base consistent and secure. +## Deterministic Artifact Generation + +- All generated artifacts (passwords, keys, TOTP secrets, etc.) must be fully deterministic across runs and platforms. +- Randomness is only permitted for security primitives (e.g., encryption nonces, in-memory keys) and must never influence derived artifacts. + +## Legacy Index Migration + +- Always provide a migration path for index archives and import/export routines. +- Support older SeedPass versions whose indexes lacked salts or password-based encryption by detecting legacy formats and upgrading them to the current schema. +- Ensure migrations unlock older account indexes and allow Nostr synchronization. +- Add regression tests covering these migrations whenever the index format or encryption changes. + + ## Integrating New Entry Types SeedPass supports multiple `kind` values in its JSON entry files. When adding a diff --git a/README.md b/README.md index 8396f57e..ad2c6361 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,14 @@ This software was not developed by an experienced security expert and should be used with caution. There may be bugs and missing features. Each vault chunk is limited to 50 KB and SeedPass periodically publishes a new snapshot to keep accumulated deltas small. The security of the program's memory management and logs has not been evaluated and may leak sensitive information. Loss or exposure of the parent seed places all derived passwords, accounts, and other artifacts at risk. +**🚨 Breaking Change** + +Recent releases derive passwords and other artifacts using a fully deterministic algorithm that behaves consistently across Python versions. This improvement means artifacts generated with earlier versions of SeedPass will not match those produced now. Regenerate any previously derived data or retain the old version if you need to reproduce older passwords or keys. + +**⚠️ First Run Warning** + +Use a dedicated BIP-39 seed phrase exclusively for SeedPass. Offline Mode is **ON by default**, keeping all Nostr syncing disabled until you explicitly opt in. To synchronize with Nostr, disable offline mode through the Settings menu or by running `seedpass config toggle-offline` and choosing to turn syncing on. + --- ### Supported OS @@ -28,6 +36,7 @@ SeedPass now uses the `portalocker` library for cross-platform file locking. No - [2. Create a Virtual Environment](#2-create-a-virtual-environment) - [3. Activate the Virtual Environment](#3-activate-the-virtual-environment) - [4. Install Dependencies](#4-install-dependencies) + - [Optional GUI](#optional-gui) - [Usage](#usage) - [Running the Application](#running-the-application) - [Managing Multiple Seeds](#managing-multiple-seeds) @@ -36,6 +45,7 @@ SeedPass now uses the `portalocker` library for cross-platform file locking. No - [Building a standalone executable](#building-a-standalone-executable) - [Packaging with Briefcase](#packaging-with-briefcase) - [Security Considerations](#security-considerations) +- [Dependency Updates](#dependency-updates) - [Contributing](#contributing) - [License](#license) - [Contact](#contact) @@ -44,7 +54,7 @@ SeedPass now uses the `portalocker` library for cross-platform file locking. No - **Deterministic Password Generation:** Utilize BIP-85 for generating deterministic and secure passwords. - **Encrypted Storage:** All seeds, login passwords, and sensitive index data are encrypted locally. -- **Nostr Integration:** Post and retrieve your encrypted password index to/from the Nostr network. +- **Nostr Integration:** Post and retrieve your encrypted password index to/from the Nostr network. See [Nostr Setup](docs/nostr_setup.md) for relay configuration and event details. - **Chunked Snapshots:** Encrypted vaults are compressed and split into 50 KB chunks published as `kind 30071` events with a `kind 30070` manifest and `kind 30072` deltas. The manifest's `delta_since` field stores the UNIX timestamp of the latest delta event. - **Automatic Checksum Generation:** The script generates and verifies a SHA-256 checksum to detect tampering. - **Multiple Seed Profiles:** Manage separate seed profiles and switch between them seamlessly. @@ -77,32 +87,31 @@ before fading. SeedPass follows a layered design. The **`seedpass.core`** package exposes the `PasswordManager` along with service classes (e.g. `VaultService` and -`EntryService`) that implement the main API used across interfaces. -The command line tool in **`seedpass.cli`** is a thin adapter built with Typer -that delegates operations to this API layer. +`EntryService`) that implement the main API used across interfaces. Both the +command line tool in **`seedpass.cli`** and the FastAPI server in +**`seedpass.api`** delegate operations to this core. The BeeWare desktop +interface (`seedpass_gui.app`) and an optional browser extension reuse these +services, with the extension communicating through the API layer. -The BeeWare desktop interface lives in **`seedpass_gui.app`** and can be -started with either `seedpass-gui` or `python -m seedpass_gui`. It reuses the -same service objects to unlock the vault, list entries and search through them. - -An optional browser extension can communicate with the FastAPI server exposed by -`seedpass.api` to manage entries from within the browser. +Nostr synchronisation lives in the **`nostr`** modules. The core services call +into these modules to publish or retrieve encrypted snapshots and deltas from +configured relays. ```mermaid graph TD - core["seedpass.core"] cli["CLI"] api["FastAPI server"] - gui["BeeWare GUI"] - ext["Browser Extension"] + core["seedpass.core"] + nostr["Nostr client"] + relays["Nostr relays"] cli --> core - gui --> core api --> core - ext --> api + core --> nostr + nostr --> relays ``` -See `docs/ARCHITECTURE.md` for details. +See `docs/ARCHITECTURE.md` and [Nostr Setup](docs/nostr_setup.md) for details. ## Prerequisites @@ -114,29 +123,44 @@ See `docs/ARCHITECTURE.md` for details. ### Quick Installer Use the automated installer to download SeedPass and its dependencies in one step. -The scripts also install the correct BeeWare backend for your platform automatically. -If the GTK `gi` bindings are missing, the installer attempts to install the -necessary system packages using `apt`, `yum`, `pacman`, or Homebrew. +The default `tui` mode installs only the text interface, so it runs headlessly and works well in CI or other automation. GUI backends are optional and must be explicitly requested (`--mode gui` or `--mode both` on Linux/macOS, `-IncludeGui` on Windows). If the GTK `gi` bindings are missing, the installer attempts to install the +necessary system packages using `apt`, `yum`, `pacman`, or Homebrew. When no display server is detected, GUI components are skipped automatically. + +For installer validation workflows and local smoke tests, see [Installer Testing](docs/installer_testing.md). **Linux and macOS:** ```bash -SEEDPASS_HEADLESS=1 bash -c "$(curl -sSL https://raw.githubusercontent.com/PR0M3TH3AN/SeedPass/main/scripts/install.sh)" +# TUI-only/agent install (headless default) +bash -c "$(curl -sSL https://raw.githubusercontent.com/PR0M3TH3AN/SeedPass/main/scripts/install.sh)" _ --mode tui ``` *Install the beta branch:* ```bash bash -c "$(curl -sSL https://raw.githubusercontent.com/PR0M3TH3AN/SeedPass/main/scripts/install.sh)" _ -b beta ``` Make sure the command ends right after `-b beta` with **no trailing parenthesis**. +*Install with GUI support:* +```bash +bash -c "$(curl -sSL https://raw.githubusercontent.com/PR0M3TH3AN/SeedPass/main/scripts/install.sh)" _ --mode gui +``` **Windows (PowerShell):** ```powershell +# TUI-only/agent install (default) Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; $scriptContent = (New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/PR0M3TH3AN/SeedPass/main/scripts/install.ps1'); & ([scriptblock]::create($scriptContent)) ``` +*Install with the optional GUI:* +```powershell +Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; $scriptContent = (New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/PR0M3TH3AN/SeedPass/main/scripts/install.ps1'); & ([scriptblock]::create($scriptContent)) -IncludeGui +``` Before running the script, install **Python 3.11** or **3.12** from [python.org](https://www.python.org/downloads/windows/) and tick **"Add Python to PATH"**. You should also install the [Visual Studio Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) with the **C++ build tools** workload so dependencies compile correctly. The Windows installer will attempt to install Git automatically if it is not already available. It also tries to install Python 3 using `winget`, `choco`, or `scoop` when Python is missing and recognizes the `py` launcher if `python` isn't on your PATH. If these tools are unavailable you'll see a link to download Python directly from . When Python 3.13 or newer is detected without the Microsoft C++ build tools, the installer now attempts to download Python 3.12 automatically so you don't have to compile packages from source. **Note:** If this fallback fails, install Python 3.12 manually or install the [Microsoft Visual C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) and rerun the installer. +#### Installer Dependency Checks + +The installer verifies that core build toolingβ€”C/C++ build tools, Rust, CMake, and the imaging/GTK librariesβ€”are available before completing. Use `--mode gui` to install only the graphical interface or `--mode both` to install both interfaces (default: `tui`). On Linux, ensure `xclip` or `wl-clipboard` is installed for clipboard support. + #### Windows Nostr Sync Troubleshooting When backing up or restoring from Nostr on Windows, a few issues are common: @@ -197,18 +221,64 @@ Follow these steps to set up SeedPass on your local machine. ```bash python -m pip install --upgrade pip - python -m pip install -r src/requirements.txt + python -m pip install --require-hashes -r requirements.lock python -m pip install -e . ``` -// πŸ”§ merged conflicting changes from codex/locate-command-usage-issue-in-seedpass vs beta After reinstalling, run `which seedpass` on Linux/macOS or `where seedpass` on Windows to confirm the command resolves to your virtual environment's `seedpass` executable. #### Linux Clipboard Support -On Linux, `pyperclip` relies on external utilities like `xclip` or `xsel`. SeedPass will attempt to install **xclip** automatically if neither tool is available. If the automatic installation fails, you can install it manually: +On Linux, `pyperclip` relies on external utilities like `xclip` or `xsel`. SeedPass no longer installs these tools automatically. To enable clipboard features such as secret mode, install **xclip** manually: ```bash -sudo apt-get install xclip +sudo apt install xclip +``` + +After installing `xclip`, restart SeedPass to enable clipboard support. + +### Optional GUI + +SeedPass ships with a GTK-based desktop interface that is still in development +and not currently functional. GUI backends are optionalβ€”run the installer with +`--mode gui` or install the Python extras below to add them. Install the packages +for your platform before adding the Python GUI dependencies. + +- **Debian/Ubuntu** + ```bash + sudo apt install libgirepository1.0-dev libcairo2-dev libpango1.0-dev libwebkit2gtk-4.0-dev + ``` +- **Fedora** + ```bash + sudo dnf install gobject-introspection-devel cairo-devel pango-devel webkit2gtk4.0-devel + ``` +- **Arch Linux** + ```bash + sudo pacman -S gobject-introspection cairo pango webkit2gtk + ``` +- **macOS (Homebrew)** + ```bash + brew install pygobject3 gtk+3 adwaita-icon-theme librsvg webkitgtk + ``` + +With the system requirements in place, install the Python GUI extras for your +platform: + +```bash +# Linux +pip install .[gui-gtk] + +# Windows +pip install .[gui-win] + +# macOS +pip install .[gui-mac] +``` + +CLI-only users can skip these steps and install just the core package for a +lightweight, headless setup compatible with CI/automation: + +```bash +pip install . ``` ## Quick Start @@ -227,10 +297,10 @@ You can then launch SeedPass and create a backup: seedpass # Export your index -seedpass export --file "~/seedpass_backup.json" +seedpass vault export --file "~/seedpass_backup.json" # Later you can restore it -seedpass import --file "~/seedpass_backup.json" +seedpass vault import --file "~/seedpass_backup.json" # Quickly find or retrieve entries seedpass search "github" @@ -251,7 +321,7 @@ seedpass util generate-password --length 20 --special-mode safe --exclude-ambigu # on an external drive. ``` -For additional command examples, see [docs/advanced_cli.md](docs/advanced_cli.md). Details on the REST API can be found in [docs/api_reference.md](docs/api_reference.md). +For additional command examples, see [docs/docs/content/01-getting-started/01-advanced_cli.md](docs/docs/content/01-getting-started/01-advanced_cli.md). Details on the REST API can be found in [docs/docs/content/01-getting-started/02-api_reference.md](docs/docs/content/01-getting-started/02-api_reference.md). ### Getting Started with the GUI @@ -264,24 +334,30 @@ python -m seedpass_gui seedpass-gui ``` -Only `toga-core` and the headless `toga-dummy` backend are included by default. -The quick installer automatically installs the correct BeeWare backend so the -GUI works out of the box. If you set up SeedPass manually, install the backend -for your platform: +GUI dependencies are optional. Install them alongside SeedPass with the +extra for your platform: ```bash # Linux -pip install toga-gtk - -# If you see build errors about "cairo" on Linux, install the cairo -# development headers using your package manager, e.g.: -sudo apt-get install libcairo2 libcairo2-dev +pip install "seedpass[gui-gtk]" # Windows -pip install toga-winforms +pip install "seedpass[gui-win]" # macOS -pip install toga-cocoa +pip install "seedpass[gui-mac]" + +# or when working from a local checkout +pip install -e ".[gui-gtk]" # Linux +pip install -e ".[gui-win]" # Windows +pip install -e ".[gui-mac]" # macOS +``` + +If you see build errors about "cairo" on Linux, install the cairo development +headers using your package manager, e.g.: + +```bash +sudo apt-get install libcairo2 libcairo2-dev ``` The GUI works with the same vault and configuration files as the CLI. @@ -359,14 +435,49 @@ If this command displays `usage: main.py` instead of the Typer help output, an o ```bash python -m pip install -e . ``` -// πŸ”§ merged conflicting changes from codex/locate-command-usage-issue-in-seedpass vs beta You can confirm which executable will run with: ```bash which seedpass # or 'where seedpass' on Windows ``` -For a full list of commands see [docs/advanced_cli.md](docs/advanced_cli.md). The REST API is described in [docs/api_reference.md](docs/api_reference.md). +For a full list of commands see [docs/docs/content/01-getting-started/01-advanced_cli.md](docs/docs/content/01-getting-started/01-advanced_cli.md). The REST API is described in [docs/docs/content/01-getting-started/02-api_reference.md](docs/docs/content/01-getting-started/02-api_reference.md). + +### Agent Mode (Non-Interactive) + +SeedPass now includes an additive `agent` command group for automation and CI. +This does not replace or modify the regular human-facing TUI flow. + +1. Initialize a profile non-interactively: + +```bash +export SEEDPASS_PASSWORD='your-strong-password' +seedpass agent init --generate-seed +``` + +Or use an existing seed from a file: + +```bash +export SEEDPASS_PASSWORD='your-strong-password' +seedpass agent init --seed-file /secure/path/seed.txt --switch-existing +``` + +2. Configure agent policy (kind allow-list and private-kind deny-list): + +```bash +seedpass agent policy-set --allow-kind password --allow-kind totp --deny-private-kind seed +seedpass agent policy-show +``` + +3. Retrieve a secret as JSON with lease metadata: + +```bash +export SEEDPASS_PASSWORD='your-strong-password' +seedpass -f agent get github --ttl 30 +``` + +By default, agent policy blocks private key/seed-style entry kinds from being +revealed through `agent get`. ### Running the Application @@ -377,6 +488,16 @@ For a full list of commands see [docs/advanced_cli.md](docs/advanced_cli.md). Th ``` *(or `python src/main.py` when running directly from the repository)* + To restore a previously backed up index at launch, provide the backup path + and fingerprint: + + ```bash + seedpass --restore-backup /path/to/backup.json.enc --fingerprint + ``` + + Without the flag, the startup prompt offers a **Restore from backup** option + before the vault is initialized. + 2. **Follow the Prompts:** - **Seed Profile Selection:** If you have existing seed profiles, you'll be prompted to select one or add a new one. @@ -558,24 +679,36 @@ The default configuration uses **50,000** PBKDF2 iterations. Increase this value ### Recovery If you previously backed up your vault to Nostr you can restore it during the -initial setup: +initial setup. You must provide both your 12‑word master seed and the master +password that encrypted the vault; without the correct password the retrieved +data cannot be decrypted. + +Alternatively, a local backup file can be loaded at startup. Launch the +application with `--restore-backup --fingerprint ` or choose the +**Restore from backup** option presented before the vault initializes. 1. Start SeedPass and choose option **4** when prompted to set up a seed. -2. Paste your BIP-85 seed phrase when asked. -3. SeedPass initializes the profile and attempts to download the encrypted vault - from the configured relays. -4. A success message confirms the vault was restored. If no data is found a +2. Paste your BIP‑85 seed phrase when asked. +3. Enter the master password associated with that seed. +4. SeedPass initializes the profile and attempts to download the encrypted + vault from the configured relays. +5. A success message confirms the vault was restored. If no data is found a failure message is shown and a new empty vault is created. ## Running Tests -SeedPass includes a small suite of unit tests located under `src/tests`. **Before running `pytest`, be sure to install the test requirements.** Activate your virtual environment and run `pip install -r src/requirements.txt` to ensure all testing dependencies are available. Then run the tests with **pytest**. Use `-vv` to see INFO-level log messages from each passing test: +SeedPass includes a small suite of unit tests located under `src/tests`. **Before running `pytest`, be sure to install the test requirements.** Activate your virtual environment and run `pip install --require-hashes -r requirements.lock` to ensure all testing dependencies are available. Then run the tests with **pytest**. Use `-vv` to see INFO-level log messages from each passing test: ```bash -pip install -r src/requirements.txt +pip install --require-hashes -r requirements.lock pytest -vv ``` +For AI-agent driven interactive testing and current test command tiers, see: + +- `docs/ai_agent_tui_testing.md` +- `docs/agent_testing_roadmap.md` + ### Exploring Nostr Index Size Limits `test_nostr_index_size.py` demonstrates how SeedPass rotates snapshots after too many delta events. Each chunk is limited to 50 KB, so the test gradually grows the vault to observe when a new snapshot is triggered. Use the `NOSTR_TEST_DELAY` environment variable to control the delay between publishes when experimenting with large vaults. @@ -636,7 +769,7 @@ Mutation testing is disabled in the GitHub workflow due to reliability issues an 1. Install all development dependencies: ```bash -pip install -r src/requirements.txt +pip install --require-hashes -r requirements.lock ``` 2. When `src/runtime_requirements.txt` changes, rerun: @@ -706,16 +839,61 @@ You can also launch the GUI directly with `seedpass gui` or `seedpass-gui`. - **Backup Your Data:** Regularly back up your encrypted data and checksum files to prevent data loss. - **Backup the Settings PIN:** Your settings PIN is stored in the encrypted configuration file. Keep a copy of this file or remember the PIN, as losing it will require deleting the file and reconfiguring your relays. - **Protect Your Passwords:** Do not share your master password or seed phrases with anyone and ensure they are strong and unique. -- **Revealing the Parent Seed:** The `vault reveal-parent-seed` command and `/api/v1/parent-seed` endpoint print your seed in plain text. Run them only in a secure environment. +- **Backing Up the Parent Seed:** Use the CLI `vault reveal-parent-seed` command or the `/api/v1/vault/backup-parent-seed` endpoint with explicit confirmation to create an encrypted backup. The API does not return the seed directly. - **No PBKDF2 Salt Needed:** SeedPass deliberately omits an explicit PBKDF2 salt. Every password is derived from a unique 512-bit BIP-85 child seed, which already provides stronger per-password uniqueness than a conventional 128-bit salt. - **Checksum Verification:** Always verify the script's checksum to ensure its integrity and protect against unauthorized modifications. - **Potential Bugs and Limitations:** Be aware that the software may contain bugs and lacks certain features. Snapshot chunks are capped at 50 KB and the client rotates snapshots after enough delta events accumulate. The security of memory management and logs has not been thoroughly evaluated and may pose risks of leaking sensitive information. +- **Best-Effort Memory Zeroization:** Sensitive data is wiped from memory when possible, but Python may retain copies of decrypted values. - **Multiple Seeds Management:** While managing multiple seeds adds flexibility, it also increases the responsibility to secure each seed and its associated password. - **No PBKDF2 Salt Required:** SeedPass deliberately omits an explicit PBKDF2 salt. Every password is derived from a unique 512-bit BIP-85 child seed, which already provides stronger per-password uniqueness than a conventional 128-bit salt. - **Default KDF Iterations:** New profiles start with 50,000 PBKDF2 iterations. Adjust this with `seedpass config set kdf_iterations`. - **KDF Iteration Caution:** Lowering `kdf_iterations` makes password cracking easier, while a high `backup_interval` leaves fewer recent backups. - **Offline Mode:** When enabled, SeedPass skips all Nostr operations so your vault stays local until syncing is turned back on. - **Quick Unlock:** Stores a hashed copy of your password in the encrypted config so you only need to enter it once per session. Avoid this on shared computers. +- **Prompt Rate Limiting:** Seed and password prompts enforce a configurable attempt limit with exponential backoff to slow brute-force attacks. Adjust or disable the limit for testing via the `--max-prompt-attempts` CLI option or the `SEEDPASS_MAX_PROMPT_ATTEMPTS` environment variable. + +### Secure Deployment + +Always deploy SeedPass behind HTTPS. Place a TLS‑terminating reverse proxy such as Nginx in front of the FastAPI server or configure Uvicorn with certificate files. Example Nginx snippet: + +``` +server { + listen 443 ssl; + ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; + + location / { + proxy_pass http://127.0.0.1:8000; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} +``` + +For local testing, Uvicorn can run with TLS directly: + +``` +uvicorn seedpass.api:app --ssl-certfile=cert.pem --ssl-keyfile=key.pem +``` + +## Dependency Updates + +Automated dependency updates are handled by [Dependabot](https://docs.github.com/en/code-security/dependabot). +Every week, Dependabot checks Python packages and GitHub Actions used by this repository and opens pull requests when updates are available. + +To review and merge these updates: + +1. Review the changelog and release notes in the Dependabot pull request. +2. Run the test suite locally: + ```bash + python3 -m venv venv + source venv/bin/activate + pip install --require-hashes -r requirements.lock + pytest + ``` +3. Merge the pull request once all checks pass. + +A scheduled **Dependency Audit** workflow also runs [`pip-audit`](https://github.com/pypa/pip-audit) weekly to detect vulnerable packages. Address any reported issues promptly to keep dependencies secure. ## Contributing diff --git a/TODO.md b/TODO.md new file mode 100644 index 00000000..fbba9358 --- /dev/null +++ b/TODO.md @@ -0,0 +1,48 @@ +# SeedPass TODO + +This file tracks the remaining work from the latest bug search and security evaluation. + +## Security + +- [ ] Upgrade vulnerable runtime dependencies in lockfiles and packaging inputs: + - `aiohttp` -> `>=3.13.3` + - `cryptography` -> `>=46.0.5` + - `starlette` -> `>=0.49.1` + - `python-multipart` -> `>=0.0.22` + - `urllib3` -> `>=2.6.3` + - `pynacl` -> `>=1.6.2` + - `pillow` -> `>=12.1.1` + - `orjson`, `pyasn1`, `cbor2` and other `pip-audit` findings +- [ ] Regenerate `requirements.lock` after upgrades and re-run the full test suite. +- [ ] Re-run `pip-audit -r requirements.lock` and ensure zero actionable runtime vulnerabilities. +- [ ] Evaluate the `Crypto.*` imports in `src/seedpass/core/password_generation.py` and either: + - keep `pycryptodome` intentionally with explicit documentation, or + - migrate RSA generation to `cryptography` APIs. + +## Robustness + +- [ ] Replace broad `except Exception: pass` blocks with explicit exceptions + logging: + - `src/main.py` + - `src/seedpass/core/manager.py` + - `src/seedpass/core/menu_handler.py` +- [ ] Add telemetry-safe logs for swallowed error paths without exposing secrets. + +## Tests To Add + +- [ ] Add deterministic tests for `derive_pgp_key(..., key_type="rsa")` covering: + - stable output across repeated runs + - key fingerprint format and validity +- [ ] Add API rate-limit tests for: + - per-client isolation + - window expiry behavior + - restart/reset behavior after `start_server()` +- [ ] Add API import tests for boundary conditions: + - exactly-at-limit upload size + - malformed multipart payload + - invalid JSON body for path-based import +- [ ] Add regression tests for manager notification/logging fallback paths currently guarded by broad exception handling. + +## Documentation + +- [ ] Document API import upload limit (`SEEDPASS_MAX_IMPORT_BYTES`) in user docs. +- [ ] Add a security maintenance section describing dependency-audit cadence and update policy. diff --git a/artifacts/agent_tui_test/20260223T185715Z/report.json b/artifacts/agent_tui_test/20260223T185715Z/report.json new file mode 100644 index 00000000..e951e897 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T185715Z/report.json @@ -0,0 +1,39 @@ +{ + "timestamp_utc": "20260223T185715Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-maymnzvh", + "duration_sec": 0.846, + "seedpass_exit_code": 0, + "status": "failed", + "failure": "Process exited before pattern appeared: 'Select entry type or press Enter to go back:'", + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "failed", + "duration_sec": 0.8458661840013519, + "detail": "Process exited before pattern appeared: 'Select entry type or press Enter to go back:'" + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "add_password_quick": false, + "invalid_length_validation": false, + "retrieve_entry": false, + "search_entries": false, + "list_entries": false, + "modify_entry": false, + "archive_restore": false, + "totp_empty_state": false, + "settings_stats": false, + "graceful_exit": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T185715Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T185715Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T185715Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T185715Z/transcript.clean.txt new file mode 100644 index 00000000..b81068f5 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T185715Z/transcript.clean.txt @@ -0,0 +1,47 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): Your new BIP-85 seed phrase is: +crane occur rapid use globe hockey slight strike evidence whale radio guard +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Enter a new password: Confirm your password: c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-maymnzvh/.seedpass/0D51417FDC8605A2/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. +cSeed Profile: 0D51417FDC8605A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T185715Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T185715Z/transcript.raw.txt new file mode 100644 index 00000000..b81068f5 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T185715Z/transcript.raw.txt @@ -0,0 +1,47 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): Your new BIP-85 seed phrase is: +crane occur rapid use globe hockey slight strike evidence whale radio guard +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Enter a new password: Confirm your password: c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-maymnzvh/.seedpass/0D51417FDC8605A2/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. +cSeed Profile: 0D51417FDC8605A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T185847Z/report.json b/artifacts/agent_tui_test/20260223T185847Z/report.json new file mode 100644 index 00000000..dff797d5 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T185847Z/report.json @@ -0,0 +1,39 @@ +{ + "timestamp_utc": "20260223T185847Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-enqviadh", + "duration_sec": 27.165, + "seedpass_exit_code": -9, + "status": "failed", + "failure": "Timed out waiting for pattern: 'Reveal hidden fields\\\\? \\\\(y/N\\\\):'\nRecent output:\nckup created successfully at '/tmp/seedpass-agent-home-enqviadh/.seedpass/BC38AA2208EE8682/backups/entries_db_backup_1771873128.json.enc'.\r\n[+] Entry added successfully at index 0.\r\n\r\n[+] Password generated and indexed with ID 0.\r\n\r\nPassword for agent.example: ^4/02KXLxu'w\r\n\r\nPress Enter to continue...\r\n\u001bcSeed Profile: BC38AA2208EE8682 > Main Menu\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 2\r\n\u001bcSeed Profile: BC38AA2208EE8682 > Main Menu > Retrieve Entry\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\nEnter the index number of the entry to retrieve: 0\r\nRetrieving password for 'agent.example' with length 12.\r\nUsername: agent\r\nURL: https://agent.example\r\n\r\n[+] Retrieved Password for agent.example:\r\n\r\nPassword: ^4/02KXLxu'w\r\nAssociated Username: agent\r\nAssociated URL: https://agent.example\r\nArchived Status: Active\r\nPress Enter to continue...", + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "failed", + "duration_sec": 25.6549951579982, + "detail": "Timed out waiting for pattern: 'Reveal hidden fields\\\\? \\\\(y/N\\\\):'\nRecent output:\nckup created successfully at '/tmp/seedpass-agent-home-enqviadh/.seedpass/BC38AA2208EE8682/backups/entries_db_backup_1771873128.json.enc'.\r\n[+] Entry added successfully at index 0.\r\n\r\n[+] Password generated and indexed with ID 0.\r\n\r\nPassword for agent.example: ^4/02KXLxu'w\r\n\r\nPress Enter to continue...\r\n\u001bcSeed Profile: BC38AA2208EE8682 > Main Menu\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 2\r\n\u001bcSeed Profile: BC38AA2208EE8682 > Main Menu > Retrieve Entry\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\nEnter the index number of the entry to retrieve: 0\r\nRetrieving password for 'agent.example' with length 12.\r\nUsername: agent\r\nURL: https://agent.example\r\n\r\n[+] Retrieved Password for agent.example:\r\n\r\nPassword: ^4/02KXLxu'w\r\nAssociated Username: agent\r\nAssociated URL: https://agent.example\r\nArchived Status: Active\r\nPress Enter to continue..." + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "add_password_quick": true, + "invalid_length_validation": true, + "retrieve_entry": false, + "search_entries": false, + "list_entries": false, + "modify_entry": false, + "archive_restore": false, + "totp_empty_state": false, + "settings_stats": false, + "graceful_exit": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T185847Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T185847Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T185847Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T185847Z/transcript.clean.txt new file mode 100644 index 00000000..6718247c --- /dev/null +++ b/artifacts/agent_tui_test/20260223T185847Z/transcript.clean.txt @@ -0,0 +1,113 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +fine uncover evoke humble middle forum prevent live trick output crunch high +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-enqviadh/.seedpass/BC38AA2208EE8682/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: BC38AA2208EE8682 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: BC38AA2208EE8682 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-enqviadh/.seedpass/BC38AA2208EE8682/backups/entries_db_backup_1771873128.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: ^4/02KXLxu'w + +Press Enter to continue... +cSeed Profile: BC38AA2208EE8682 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: BC38AA2208EE8682 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: ^4/02KXLxu'w +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T185847Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T185847Z/transcript.raw.txt new file mode 100644 index 00000000..6718247c --- /dev/null +++ b/artifacts/agent_tui_test/20260223T185847Z/transcript.raw.txt @@ -0,0 +1,113 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +fine uncover evoke humble middle forum prevent live trick output crunch high +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-enqviadh/.seedpass/BC38AA2208EE8682/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: BC38AA2208EE8682 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: BC38AA2208EE8682 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-enqviadh/.seedpass/BC38AA2208EE8682/backups/entries_db_backup_1771873128.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: ^4/02KXLxu'w + +Press Enter to continue... +cSeed Profile: BC38AA2208EE8682 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: BC38AA2208EE8682 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: ^4/02KXLxu'w +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T185928Z/report.json b/artifacts/agent_tui_test/20260223T185928Z/report.json new file mode 100644 index 00000000..2f305743 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T185928Z/report.json @@ -0,0 +1,39 @@ +{ + "timestamp_utc": "20260223T185928Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-rs93rbie", + "duration_sec": 30.029, + "seedpass_exit_code": -9, + "status": "failed", + "failure": "Timed out waiting for pattern: 'Enter your choice \\\\(1-8\\\\) or press Enter to exit:'\nRecent output:\ntries: 1\r\n password: 1\r\n totp: 0\r\n ssh: 0\r\n seed: 0\r\n pgp: 0\r\n nostr: 0\r\n key_value: 0\r\n managed_account: 0\r\nRelays configured: 3\r\nBackups: 1 (dir: /tmp/seedpass-agent-home-rs93rbie/.seedpass/225E9E8635B1BEA4/backups)\r\nSchema version: 4\r\nDatabase checksum ok: no\r\nScript checksum ok: yes\r\nSnapshot chunks: 0\r\nPending deltas: 0\r\nNo 2FA entries found.\r\nPress Enter to continue.\r\n\r\n\u001bcSeed Profile: Main Menu > Settings\r\n\r\n\r\nSettings:\r\n1. Profiles\r\n2. Nostr\r\n3. Change password\r\n4. Verify Script Checksum\r\n5. Generate Script Checksum\r\n6. Backup Parent Seed\r\n7. Export database\r\n8. Import database\r\n9. Export 2FA codes\r\n10. Set additional backup location\r\n11. KDF strength & benchmark\r\n12. Set inactivity timeout\r\n13. Lock Vault\r\n14. Stats\r\n15. Toggle Secret Mode\r\n16. Toggle Offline Mode (default ON)\r\n17. Toggle Quick Unlock\r\nSelect an option or press Enter to go back: \r\n\u001bcSeed Profile: 225E9E8635B1BEA4 > Main Menu\r\nNo 2FA entries found.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: ", + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "failed", + "duration_sec": 28.518274590001965, + "detail": "Timed out waiting for pattern: 'Enter your choice \\\\(1-8\\\\) or press Enter to exit:'\nRecent output:\ntries: 1\r\n password: 1\r\n totp: 0\r\n ssh: 0\r\n seed: 0\r\n pgp: 0\r\n nostr: 0\r\n key_value: 0\r\n managed_account: 0\r\nRelays configured: 3\r\nBackups: 1 (dir: /tmp/seedpass-agent-home-rs93rbie/.seedpass/225E9E8635B1BEA4/backups)\r\nSchema version: 4\r\nDatabase checksum ok: no\r\nScript checksum ok: yes\r\nSnapshot chunks: 0\r\nPending deltas: 0\r\nNo 2FA entries found.\r\nPress Enter to continue.\r\n\r\n\u001bcSeed Profile: Main Menu > Settings\r\n\r\n\r\nSettings:\r\n1. Profiles\r\n2. Nostr\r\n3. Change password\r\n4. Verify Script Checksum\r\n5. Generate Script Checksum\r\n6. Backup Parent Seed\r\n7. Export database\r\n8. Import database\r\n9. Export 2FA codes\r\n10. Set additional backup location\r\n11. KDF strength & benchmark\r\n12. Set inactivity timeout\r\n13. Lock Vault\r\n14. Stats\r\n15. Toggle Secret Mode\r\n16. Toggle Offline Mode (default ON)\r\n17. Toggle Quick Unlock\r\nSelect an option or press Enter to go back: \r\n\u001bcSeed Profile: 225E9E8635B1BEA4 > Main Menu\r\nNo 2FA entries found.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: " + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "add_password_quick": true, + "invalid_length_validation": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_empty_state": true, + "settings_stats": true, + "graceful_exit": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T185928Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T185928Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T185928Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T185928Z/transcript.clean.txt new file mode 100644 index 00000000..37fdc80b --- /dev/null +++ b/artifacts/agent_tui_test/20260223T185928Z/transcript.clean.txt @@ -0,0 +1,421 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +situate goat cinnamon bag olive sausage analyst neutral seminar stay page deal +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-rs93rbie/.seedpass/225E9E8635B1BEA4/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-rs93rbie/.seedpass/225E9E8635B1BEA4/backups/entries_db_backup_1771873169.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: pyA7,8j&;F3L + +Press Enter to continue... +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: pyA7,8j&;F3L +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 225E9E8635B1BEA4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-rs93rbie/.seedpass/225E9E8635B1BEA4/backups/entries_db_backup_1771873169.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: pyA7,8j&;F3L +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 225E9E8635B1BEA4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-rs93rbie/.seedpass/225E9E8635B1BEA4/backups/entries_db_backup_1771873169.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 225E9E8635B1BEA4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-rs93rbie/.seedpass/225E9E8635B1BEA4/backups/entries_db_backup_1771873169.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 1 + password: 1 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 1 (dir: /tmp/seedpass-agent-home-rs93rbie/.seedpass/225E9E8635B1BEA4/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +No 2FA entries found. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T185928Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T185928Z/transcript.raw.txt new file mode 100644 index 00000000..37fdc80b --- /dev/null +++ b/artifacts/agent_tui_test/20260223T185928Z/transcript.raw.txt @@ -0,0 +1,421 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +situate goat cinnamon bag olive sausage analyst neutral seminar stay page deal +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-rs93rbie/.seedpass/225E9E8635B1BEA4/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-rs93rbie/.seedpass/225E9E8635B1BEA4/backups/entries_db_backup_1771873169.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: pyA7,8j&;F3L + +Press Enter to continue... +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: pyA7,8j&;F3L +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 225E9E8635B1BEA4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-rs93rbie/.seedpass/225E9E8635B1BEA4/backups/entries_db_backup_1771873169.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: pyA7,8j&;F3L +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 225E9E8635B1BEA4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-rs93rbie/.seedpass/225E9E8635B1BEA4/backups/entries_db_backup_1771873169.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 225E9E8635B1BEA4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-rs93rbie/.seedpass/225E9E8635B1BEA4/backups/entries_db_backup_1771873169.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 225E9E8635B1BEA4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 1 + password: 1 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 1 (dir: /tmp/seedpass-agent-home-rs93rbie/.seedpass/225E9E8635B1BEA4/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +No 2FA entries found. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 225E9E8635B1BEA4 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T190048Z/report.json b/artifacts/agent_tui_test/20260223T190048Z/report.json new file mode 100644 index 00000000..5055b98e --- /dev/null +++ b/artifacts/agent_tui_test/20260223T190048Z/report.json @@ -0,0 +1,39 @@ +{ + "timestamp_utc": "20260223T190048Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-vbcpszl5", + "duration_sec": 3.555, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 3.487188208997395, + "detail": null + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "add_password_quick": true, + "invalid_length_validation": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_empty_state": true, + "settings_stats": true, + "graceful_exit": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T190048Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T190048Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T190048Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T190048Z/transcript.clean.txt new file mode 100644 index 00000000..1dea678c --- /dev/null +++ b/artifacts/agent_tui_test/20260223T190048Z/transcript.clean.txt @@ -0,0 +1,422 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +this endorse approve viable despair stool tomato place salute cube expose diamond +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-vbcpszl5/.seedpass/00423691BE42D239/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 00423691BE42D239 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 00423691BE42D239 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vbcpszl5/.seedpass/00423691BE42D239/backups/entries_db_backup_1771873249.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: Ur$qK5!0-Q2x + +Press Enter to continue... +cSeed Profile: 00423691BE42D239 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 00423691BE42D239 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Ur$qK5!0-Q2x +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 00423691BE42D239 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 00423691BE42D239 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 00423691BE42D239 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 00423691BE42D239 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 00423691BE42D239 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 00423691BE42D239 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 00423691BE42D239 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 00423691BE42D239 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 00423691BE42D239 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 00423691BE42D239 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vbcpszl5/.seedpass/00423691BE42D239/backups/entries_db_backup_1771873249.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 00423691BE42D239 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 00423691BE42D239 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Ur$qK5!0-Q2x +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 00423691BE42D239 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vbcpszl5/.seedpass/00423691BE42D239/backups/entries_db_backup_1771873249.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 00423691BE42D239 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 00423691BE42D239 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 00423691BE42D239 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vbcpszl5/.seedpass/00423691BE42D239/backups/entries_db_backup_1771873249.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 00423691BE42D239 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 00423691BE42D239 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +cSeed Profile: 00423691BE42D239 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 1 + password: 1 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 1 (dir: /tmp/seedpass-agent-home-vbcpszl5/.seedpass/00423691BE42D239/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +No 2FA entries found. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 00423691BE42D239 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T190048Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T190048Z/transcript.raw.txt new file mode 100644 index 00000000..7e96abd9 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T190048Z/transcript.raw.txt @@ -0,0 +1,423 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +this endorse approve viable despair stool tomato place salute cube expose diamond +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-vbcpszl5/.seedpass/00423691BE42D239/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 00423691BE42D239 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 00423691BE42D239 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vbcpszl5/.seedpass/00423691BE42D239/backups/entries_db_backup_1771873249.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: Ur$qK5!0-Q2x + +Press Enter to continue... +cSeed Profile: 00423691BE42D239 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 00423691BE42D239 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Ur$qK5!0-Q2x +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 00423691BE42D239 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 00423691BE42D239 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 00423691BE42D239 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 00423691BE42D239 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 00423691BE42D239 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 00423691BE42D239 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 00423691BE42D239 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 00423691BE42D239 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 00423691BE42D239 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 00423691BE42D239 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vbcpszl5/.seedpass/00423691BE42D239/backups/entries_db_backup_1771873249.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 00423691BE42D239 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 00423691BE42D239 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Ur$qK5!0-Q2x +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 00423691BE42D239 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vbcpszl5/.seedpass/00423691BE42D239/backups/entries_db_backup_1771873249.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 00423691BE42D239 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 00423691BE42D239 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 00423691BE42D239 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vbcpszl5/.seedpass/00423691BE42D239/backups/entries_db_backup_1771873249.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 00423691BE42D239 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 00423691BE42D239 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +cSeed Profile: 00423691BE42D239 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 1 + password: 1 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 1 (dir: /tmp/seedpass-agent-home-vbcpszl5/.seedpass/00423691BE42D239/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +No 2FA entries found. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 00423691BE42D239 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T190106Z/report.json b/artifacts/agent_tui_test/20260223T190106Z/report.json new file mode 100644 index 00000000..cb7bd77f --- /dev/null +++ b/artifacts/agent_tui_test/20260223T190106Z/report.json @@ -0,0 +1,39 @@ +{ + "timestamp_utc": "20260223T190106Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-0vbtuv2t", + "duration_sec": 3.555, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 3.4901997710003343, + "detail": null + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "add_password_quick": true, + "invalid_length_validation": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_empty_state": true, + "settings_stats": true, + "graceful_exit": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T190106Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T190106Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T190106Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T190106Z/transcript.clean.txt new file mode 100644 index 00000000..af04b143 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T190106Z/transcript.clean.txt @@ -0,0 +1,422 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +reason reunion merry panda argue unhappy endorse slide vacuum year nature mango +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-0vbtuv2t/.seedpass/7489754F5EE1C709/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 7489754F5EE1C709 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 7489754F5EE1C709 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-0vbtuv2t/.seedpass/7489754F5EE1C709/backups/entries_db_backup_1771873267.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: K'y2pQ8|~1sR + +Press Enter to continue... +cSeed Profile: 7489754F5EE1C709 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 7489754F5EE1C709 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: K'y2pQ8|~1sR +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 7489754F5EE1C709 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 7489754F5EE1C709 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 7489754F5EE1C709 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 7489754F5EE1C709 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 7489754F5EE1C709 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 7489754F5EE1C709 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 7489754F5EE1C709 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 7489754F5EE1C709 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 7489754F5EE1C709 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 7489754F5EE1C709 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-0vbtuv2t/.seedpass/7489754F5EE1C709/backups/entries_db_backup_1771873267.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 7489754F5EE1C709 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 7489754F5EE1C709 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: K'y2pQ8|~1sR +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 7489754F5EE1C709 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-0vbtuv2t/.seedpass/7489754F5EE1C709/backups/entries_db_backup_1771873268.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 7489754F5EE1C709 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 7489754F5EE1C709 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 7489754F5EE1C709 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-0vbtuv2t/.seedpass/7489754F5EE1C709/backups/entries_db_backup_1771873268.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 7489754F5EE1C709 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 7489754F5EE1C709 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +cSeed Profile: 7489754F5EE1C709 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 1 + password: 1 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-0vbtuv2t/.seedpass/7489754F5EE1C709/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +No 2FA entries found. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 7489754F5EE1C709 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T190106Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T190106Z/transcript.raw.txt new file mode 100644 index 00000000..450f8122 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T190106Z/transcript.raw.txt @@ -0,0 +1,423 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +reason reunion merry panda argue unhappy endorse slide vacuum year nature mango +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-0vbtuv2t/.seedpass/7489754F5EE1C709/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 7489754F5EE1C709 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 7489754F5EE1C709 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-0vbtuv2t/.seedpass/7489754F5EE1C709/backups/entries_db_backup_1771873267.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: K'y2pQ8|~1sR + +Press Enter to continue... +cSeed Profile: 7489754F5EE1C709 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 7489754F5EE1C709 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: K'y2pQ8|~1sR +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 7489754F5EE1C709 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 7489754F5EE1C709 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 7489754F5EE1C709 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 7489754F5EE1C709 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 7489754F5EE1C709 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 7489754F5EE1C709 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 7489754F5EE1C709 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 7489754F5EE1C709 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 7489754F5EE1C709 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 7489754F5EE1C709 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-0vbtuv2t/.seedpass/7489754F5EE1C709/backups/entries_db_backup_1771873267.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 7489754F5EE1C709 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 7489754F5EE1C709 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: K'y2pQ8|~1sR +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 7489754F5EE1C709 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-0vbtuv2t/.seedpass/7489754F5EE1C709/backups/entries_db_backup_1771873268.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 7489754F5EE1C709 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 7489754F5EE1C709 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 7489754F5EE1C709 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-0vbtuv2t/.seedpass/7489754F5EE1C709/backups/entries_db_backup_1771873268.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 7489754F5EE1C709 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 7489754F5EE1C709 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +cSeed Profile: 7489754F5EE1C709 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 1 + password: 1 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-0vbtuv2t/.seedpass/7489754F5EE1C709/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +No 2FA entries found. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 7489754F5EE1C709 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191140Z/report.json b/artifacts/agent_tui_test/20260223T191140Z/report.json new file mode 100644 index 00000000..52c73214 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191140Z/report.json @@ -0,0 +1,39 @@ +{ + "timestamp_utc": "20260223T191140Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-uc4te8tp", + "duration_sec": 26.946, + "seedpass_exit_code": -9, + "status": "failed", + "failure": "Timed out waiting for pattern: 'Confirm your password:'\nRecent output:\nStartup Options:\r\n1. Continue\r\n2. Restore from backup\r\nSelect an option: 1\r\nInitialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'.\r\nChoose an option:\r\n1. Paste in an existing seed in full\r\n2. Enter an existing seed one word at a time\r\n3. Generate a new seed\r\n4. Restore from Nostr\r\n5. Restore from local backup\r\nEnter choice (1/2/3/4/5): 3\r\nYour new BIP-85 seed phrase is:\r\nglove climb common before valley gap firm outside consider farm chest broken\r\nPlease write this down and keep it in a safe place!\r\nDo you want to use this generated seed? (Y/N): Y\r\nEnter a new password: AgentPass123!\r\n", + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "failed", + "duration_sec": 25.36855878499773, + "detail": "Timed out waiting for pattern: 'Confirm your password:'\nRecent output:\nStartup Options:\r\n1. Continue\r\n2. Restore from backup\r\nSelect an option: 1\r\nInitialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'.\r\nChoose an option:\r\n1. Paste in an existing seed in full\r\n2. Enter an existing seed one word at a time\r\n3. Generate a new seed\r\n4. Restore from Nostr\r\n5. Restore from local backup\r\nEnter choice (1/2/3/4/5): 3\r\nYour new BIP-85 seed phrase is:\r\nglove climb common before valley gap firm outside consider farm chest broken\r\nPlease write this down and keep it in a safe place!\r\nDo you want to use this generated seed? (Y/N): Y\r\nEnter a new password: AgentPass123!\r\n" + } + ], + "coverage_points": { + "startup_onboarding": false, + "main_menu": false, + "add_password_quick": false, + "invalid_length_validation": false, + "retrieve_entry": false, + "search_entries": false, + "list_entries": false, + "modify_entry": false, + "archive_restore": false, + "totp_empty_state": false, + "settings_stats": false, + "graceful_exit": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191140Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191140Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191140Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T191140Z/transcript.clean.txt new file mode 100644 index 00000000..acb965e7 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191140Z/transcript.clean.txt @@ -0,0 +1,17 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +glove climb common before valley gap firm outside consider farm chest broken +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: AgentPass123! diff --git a/artifacts/agent_tui_test/20260223T191140Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T191140Z/transcript.raw.txt new file mode 100644 index 00000000..acb965e7 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191140Z/transcript.raw.txt @@ -0,0 +1,17 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +glove climb common before valley gap firm outside consider farm chest broken +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: AgentPass123! diff --git a/artifacts/agent_tui_test/20260223T191219Z/report.json b/artifacts/agent_tui_test/20260223T191219Z/report.json new file mode 100644 index 00000000..9fa1b77a --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191219Z/report.json @@ -0,0 +1,39 @@ +{ + "timestamp_utc": "20260223T191219Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-wgl_gstu", + "duration_sec": 3.567, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 3.4941302279985393, + "detail": null + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "add_password_quick": true, + "invalid_length_validation": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_empty_state": true, + "settings_stats": true, + "graceful_exit": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191219Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191219Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191219Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T191219Z/transcript.clean.txt new file mode 100644 index 00000000..68098674 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191219Z/transcript.clean.txt @@ -0,0 +1,422 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +dizzy drum girl fruit dash pact unfold join alcohol cabin crouch candy +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-wgl_gstu/.seedpass/C7EE4B50845B4316/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: C7EE4B50845B4316 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: C7EE4B50845B4316 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-wgl_gstu/.seedpass/C7EE4B50845B4316/backups/entries_db_backup_1771873940.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: `Q%29VpWte0% + +Press Enter to continue... +cSeed Profile: C7EE4B50845B4316 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: C7EE4B50845B4316 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: `Q%29VpWte0% +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: C7EE4B50845B4316 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: C7EE4B50845B4316 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: C7EE4B50845B4316 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: C7EE4B50845B4316 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: C7EE4B50845B4316 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: C7EE4B50845B4316 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: C7EE4B50845B4316 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: C7EE4B50845B4316 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: C7EE4B50845B4316 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: C7EE4B50845B4316 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-wgl_gstu/.seedpass/C7EE4B50845B4316/backups/entries_db_backup_1771873940.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: C7EE4B50845B4316 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: C7EE4B50845B4316 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: `Q%29VpWte0% +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: C7EE4B50845B4316 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-wgl_gstu/.seedpass/C7EE4B50845B4316/backups/entries_db_backup_1771873940.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: C7EE4B50845B4316 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: C7EE4B50845B4316 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: C7EE4B50845B4316 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-wgl_gstu/.seedpass/C7EE4B50845B4316/backups/entries_db_backup_1771873940.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: C7EE4B50845B4316 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: C7EE4B50845B4316 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +cSeed Profile: C7EE4B50845B4316 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 1 + password: 1 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 1 (dir: /tmp/seedpass-agent-home-wgl_gstu/.seedpass/C7EE4B50845B4316/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +No 2FA entries found. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: C7EE4B50845B4316 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T191219Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T191219Z/transcript.raw.txt new file mode 100644 index 00000000..f1bf6ae3 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191219Z/transcript.raw.txt @@ -0,0 +1,423 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +dizzy drum girl fruit dash pact unfold join alcohol cabin crouch candy +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-wgl_gstu/.seedpass/C7EE4B50845B4316/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: C7EE4B50845B4316 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: C7EE4B50845B4316 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-wgl_gstu/.seedpass/C7EE4B50845B4316/backups/entries_db_backup_1771873940.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: `Q%29VpWte0% + +Press Enter to continue... +cSeed Profile: C7EE4B50845B4316 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: C7EE4B50845B4316 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: `Q%29VpWte0% +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: C7EE4B50845B4316 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: C7EE4B50845B4316 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: C7EE4B50845B4316 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: C7EE4B50845B4316 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: C7EE4B50845B4316 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: C7EE4B50845B4316 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: C7EE4B50845B4316 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: C7EE4B50845B4316 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: C7EE4B50845B4316 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: C7EE4B50845B4316 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-wgl_gstu/.seedpass/C7EE4B50845B4316/backups/entries_db_backup_1771873940.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: C7EE4B50845B4316 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: C7EE4B50845B4316 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: `Q%29VpWte0% +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: C7EE4B50845B4316 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-wgl_gstu/.seedpass/C7EE4B50845B4316/backups/entries_db_backup_1771873940.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: C7EE4B50845B4316 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: C7EE4B50845B4316 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: C7EE4B50845B4316 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-wgl_gstu/.seedpass/C7EE4B50845B4316/backups/entries_db_backup_1771873940.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: C7EE4B50845B4316 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: C7EE4B50845B4316 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +cSeed Profile: C7EE4B50845B4316 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 1 + password: 1 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 1 (dir: /tmp/seedpass-agent-home-wgl_gstu/.seedpass/C7EE4B50845B4316/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +No 2FA entries found. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: C7EE4B50845B4316 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191334Z/report.json b/artifacts/agent_tui_test/20260223T191334Z/report.json new file mode 100644 index 00000000..7a37f31d --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191334Z/report.json @@ -0,0 +1,39 @@ +{ + "timestamp_utc": "20260223T191334Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-unuhkmru", + "duration_sec": 4.446, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 4.239846189000673, + "detail": null + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "add_password_quick": true, + "invalid_length_validation": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_empty_state": true, + "settings_stats": true, + "graceful_exit": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191334Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191334Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191334Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T191334Z/transcript.clean.txt new file mode 100644 index 00000000..cd55bf7a --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191334Z/transcript.clean.txt @@ -0,0 +1,422 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +phone essay chapter unlock layer tonight sword blast peanut creek tissue episode +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-unuhkmru/.seedpass/67CDEEA0560B53BA/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 67CDEEA0560B53BA > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-unuhkmru/.seedpass/67CDEEA0560B53BA/backups/entries_db_backup_1771874015.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: Kq[2[qF@33Hk + +Press Enter to continue... +cSeed Profile: 67CDEEA0560B53BA > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Kq[2[qF@33Hk +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 67CDEEA0560B53BA > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 67CDEEA0560B53BA > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 67CDEEA0560B53BA > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 67CDEEA0560B53BA > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 67CDEEA0560B53BA > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 67CDEEA0560B53BA > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-unuhkmru/.seedpass/67CDEEA0560B53BA/backups/entries_db_backup_1771874016.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 67CDEEA0560B53BA > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Kq[2[qF@33Hk +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 67CDEEA0560B53BA > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-unuhkmru/.seedpass/67CDEEA0560B53BA/backups/entries_db_backup_1771874016.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 67CDEEA0560B53BA > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 67CDEEA0560B53BA > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-unuhkmru/.seedpass/67CDEEA0560B53BA/backups/entries_db_backup_1771874017.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 67CDEEA0560B53BA > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +cSeed Profile: 67CDEEA0560B53BA > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 1 + password: 1 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 3 (dir: /tmp/seedpass-agent-home-unuhkmru/.seedpass/67CDEEA0560B53BA/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +No 2FA entries found. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 67CDEEA0560B53BA > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T191334Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T191334Z/transcript.raw.txt new file mode 100644 index 00000000..84917393 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191334Z/transcript.raw.txt @@ -0,0 +1,423 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +phone essay chapter unlock layer tonight sword blast peanut creek tissue episode +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-unuhkmru/.seedpass/67CDEEA0560B53BA/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 67CDEEA0560B53BA > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-unuhkmru/.seedpass/67CDEEA0560B53BA/backups/entries_db_backup_1771874015.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: Kq[2[qF@33Hk + +Press Enter to continue... +cSeed Profile: 67CDEEA0560B53BA > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Kq[2[qF@33Hk +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 67CDEEA0560B53BA > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 67CDEEA0560B53BA > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 67CDEEA0560B53BA > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 67CDEEA0560B53BA > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 67CDEEA0560B53BA > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 67CDEEA0560B53BA > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-unuhkmru/.seedpass/67CDEEA0560B53BA/backups/entries_db_backup_1771874016.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 67CDEEA0560B53BA > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Kq[2[qF@33Hk +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 67CDEEA0560B53BA > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-unuhkmru/.seedpass/67CDEEA0560B53BA/backups/entries_db_backup_1771874016.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 67CDEEA0560B53BA > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 67CDEEA0560B53BA > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-unuhkmru/.seedpass/67CDEEA0560B53BA/backups/entries_db_backup_1771874017.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 67CDEEA0560B53BA > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 67CDEEA0560B53BA > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +cSeed Profile: 67CDEEA0560B53BA > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 1 + password: 1 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 3 (dir: /tmp/seedpass-agent-home-unuhkmru/.seedpass/67CDEEA0560B53BA/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +No 2FA entries found. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 67CDEEA0560B53BA > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191339Z/report.json b/artifacts/agent_tui_test/20260223T191339Z/report.json new file mode 100644 index 00000000..dd819697 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191339Z/report.json @@ -0,0 +1,39 @@ +{ + "timestamp_utc": "20260223T191339Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-fjr8g0u7", + "duration_sec": 4.212, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 4.13329088500177, + "detail": null + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "add_password_quick": true, + "invalid_length_validation": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_empty_state": true, + "settings_stats": true, + "graceful_exit": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191339Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191339Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191339Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T191339Z/transcript.clean.txt new file mode 100644 index 00000000..cba87bac --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191339Z/transcript.clean.txt @@ -0,0 +1,422 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +ladder crisp where shrimp hidden hood scrub orphan spray prevent swim cigar +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-fjr8g0u7/.seedpass/CDB0DAE87DA85738/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: CDB0DAE87DA85738 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjr8g0u7/.seedpass/CDB0DAE87DA85738/backups/entries_db_backup_1771874020.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: Pxh,l3^T5P3, + +Press Enter to continue... +cSeed Profile: CDB0DAE87DA85738 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Pxh,l3^T5P3, +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: CDB0DAE87DA85738 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: CDB0DAE87DA85738 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: CDB0DAE87DA85738 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: CDB0DAE87DA85738 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: CDB0DAE87DA85738 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: CDB0DAE87DA85738 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjr8g0u7/.seedpass/CDB0DAE87DA85738/backups/entries_db_backup_1771874020.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: CDB0DAE87DA85738 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Pxh,l3^T5P3, +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: CDB0DAE87DA85738 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjr8g0u7/.seedpass/CDB0DAE87DA85738/backups/entries_db_backup_1771874021.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: CDB0DAE87DA85738 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: CDB0DAE87DA85738 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjr8g0u7/.seedpass/CDB0DAE87DA85738/backups/entries_db_backup_1771874021.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: CDB0DAE87DA85738 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +cSeed Profile: CDB0DAE87DA85738 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 1 + password: 1 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-fjr8g0u7/.seedpass/CDB0DAE87DA85738/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +No 2FA entries found. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: CDB0DAE87DA85738 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T191339Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T191339Z/transcript.raw.txt new file mode 100644 index 00000000..9d7fbbb6 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191339Z/transcript.raw.txt @@ -0,0 +1,423 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +ladder crisp where shrimp hidden hood scrub orphan spray prevent swim cigar +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-fjr8g0u7/.seedpass/CDB0DAE87DA85738/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: CDB0DAE87DA85738 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjr8g0u7/.seedpass/CDB0DAE87DA85738/backups/entries_db_backup_1771874020.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: Pxh,l3^T5P3, + +Press Enter to continue... +cSeed Profile: CDB0DAE87DA85738 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Pxh,l3^T5P3, +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: CDB0DAE87DA85738 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: CDB0DAE87DA85738 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: CDB0DAE87DA85738 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: CDB0DAE87DA85738 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: CDB0DAE87DA85738 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: CDB0DAE87DA85738 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjr8g0u7/.seedpass/CDB0DAE87DA85738/backups/entries_db_backup_1771874020.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: CDB0DAE87DA85738 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Pxh,l3^T5P3, +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: CDB0DAE87DA85738 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjr8g0u7/.seedpass/CDB0DAE87DA85738/backups/entries_db_backup_1771874021.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: CDB0DAE87DA85738 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: CDB0DAE87DA85738 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjr8g0u7/.seedpass/CDB0DAE87DA85738/backups/entries_db_backup_1771874021.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: CDB0DAE87DA85738 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: CDB0DAE87DA85738 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +cSeed Profile: CDB0DAE87DA85738 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 1 + password: 1 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-fjr8g0u7/.seedpass/CDB0DAE87DA85738/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +No 2FA entries found. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: CDB0DAE87DA85738 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191343Z/report.json b/artifacts/agent_tui_test/20260223T191343Z/report.json new file mode 100644 index 00000000..75a49d7a --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191343Z/report.json @@ -0,0 +1,39 @@ +{ + "timestamp_utc": "20260223T191343Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-7w23hsc4", + "duration_sec": 4.178, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 4.11195554400183, + "detail": null + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "add_password_quick": true, + "invalid_length_validation": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_empty_state": true, + "settings_stats": true, + "graceful_exit": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191343Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191343Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191343Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T191343Z/transcript.clean.txt new file mode 100644 index 00000000..1d1e70f8 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191343Z/transcript.clean.txt @@ -0,0 +1,422 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +suffer dentist figure fetch scare buffalo hand garlic meadow blossom toward lucky +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-7w23hsc4/.seedpass/1D20C2D407D11A95/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 1D20C2D407D11A95 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-7w23hsc4/.seedpass/1D20C2D407D11A95/backups/entries_db_backup_1771874024.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: P0=AsqA5&0y+ + +Press Enter to continue... +cSeed Profile: 1D20C2D407D11A95 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: P0=AsqA5&0y+ +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 1D20C2D407D11A95 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 1D20C2D407D11A95 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 1D20C2D407D11A95 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 1D20C2D407D11A95 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 1D20C2D407D11A95 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 1D20C2D407D11A95 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-7w23hsc4/.seedpass/1D20C2D407D11A95/backups/entries_db_backup_1771874025.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 1D20C2D407D11A95 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: P0=AsqA5&0y+ +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 1D20C2D407D11A95 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-7w23hsc4/.seedpass/1D20C2D407D11A95/backups/entries_db_backup_1771874025.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 1D20C2D407D11A95 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 1D20C2D407D11A95 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-7w23hsc4/.seedpass/1D20C2D407D11A95/backups/entries_db_backup_1771874025.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 1D20C2D407D11A95 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +cSeed Profile: 1D20C2D407D11A95 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 1 + password: 1 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-7w23hsc4/.seedpass/1D20C2D407D11A95/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +No 2FA entries found. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 1D20C2D407D11A95 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T191343Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T191343Z/transcript.raw.txt new file mode 100644 index 00000000..fc90f69e --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191343Z/transcript.raw.txt @@ -0,0 +1,423 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +suffer dentist figure fetch scare buffalo hand garlic meadow blossom toward lucky +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-7w23hsc4/.seedpass/1D20C2D407D11A95/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 1D20C2D407D11A95 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-7w23hsc4/.seedpass/1D20C2D407D11A95/backups/entries_db_backup_1771874024.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: P0=AsqA5&0y+ + +Press Enter to continue... +cSeed Profile: 1D20C2D407D11A95 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: P0=AsqA5&0y+ +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 1D20C2D407D11A95 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 1D20C2D407D11A95 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 1D20C2D407D11A95 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 1D20C2D407D11A95 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 1D20C2D407D11A95 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 1D20C2D407D11A95 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-7w23hsc4/.seedpass/1D20C2D407D11A95/backups/entries_db_backup_1771874025.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 1D20C2D407D11A95 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: P0=AsqA5&0y+ +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 1D20C2D407D11A95 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-7w23hsc4/.seedpass/1D20C2D407D11A95/backups/entries_db_backup_1771874025.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 1D20C2D407D11A95 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 1D20C2D407D11A95 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-7w23hsc4/.seedpass/1D20C2D407D11A95/backups/entries_db_backup_1771874025.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 1D20C2D407D11A95 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 1D20C2D407D11A95 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +cSeed Profile: 1D20C2D407D11A95 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 1 + password: 1 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-7w23hsc4/.seedpass/1D20C2D407D11A95/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +No 2FA entries found. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 1D20C2D407D11A95 > Main Menu +No 2FA entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191611Z/report.json b/artifacts/agent_tui_test/20260223T191611Z/report.json new file mode 100644 index 00000000..afc08d1f --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191611Z/report.json @@ -0,0 +1,40 @@ +{ + "timestamp_utc": "20260223T191611Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-gty9bhbq", + "duration_sec": 28.369, + "seedpass_exit_code": -9, + "status": "failed", + "failure": "Timed out waiting for pattern: 'Generated 2FA Codes:'\nRecent output:\n---] 30s\r\n\u001bcSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes\r\n\r\nPress Enter to return to the menu.\r\n\r\nImported 2FA Codes:\r\n[1] agent-totp: 108964 [--------------------] 29s\r\n\u001bcSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes\r\n\r\nPress Enter to return to the menu.\r\n\r\nImported 2FA Codes:\r\n[1] agent-totp: 108964 [#-------------------] 28s\r\n\u001bcSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes\r\n\r\nPress Enter to return to the menu.\r\n\r\nImported 2FA Codes:\r\n[1] agent-totp: 108964 [##------------------] 27s\r\n\u001bcSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes\r\n\r\nPress Enter to return to the menu.\r\n\r\nImported 2FA Codes:\r\n[1] agent-totp: 108964 [##------------------] 26s\r\n\u001bcSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes\r\n\r\nPress Enter to return to the menu.\r\n\r\nImported 2FA Codes:\r\n[1] agent-totp: 108964 [###-----------------] 25s\r\n\u001bcSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes\r\n\r\nPress Enter to return to the menu.\r\n\r\nImported 2FA Codes:\r\n[1] agent-totp: 108964 [####----------------] 24s\r\n\u001bcSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes\r\n\r\nPress Enter to return to the menu.\r\n\r\nImported 2FA Codes:\r\n[1] agent-totp: 108964 [####----------------] 23s\r\n", + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "failed", + "duration_sec": 26.85835266199865, + "detail": "Timed out waiting for pattern: 'Generated 2FA Codes:'\nRecent output:\n---] 30s\r\n\u001bcSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes\r\n\r\nPress Enter to return to the menu.\r\n\r\nImported 2FA Codes:\r\n[1] agent-totp: 108964 [--------------------] 29s\r\n\u001bcSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes\r\n\r\nPress Enter to return to the menu.\r\n\r\nImported 2FA Codes:\r\n[1] agent-totp: 108964 [#-------------------] 28s\r\n\u001bcSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes\r\n\r\nPress Enter to return to the menu.\r\n\r\nImported 2FA Codes:\r\n[1] agent-totp: 108964 [##------------------] 27s\r\n\u001bcSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes\r\n\r\nPress Enter to return to the menu.\r\n\r\nImported 2FA Codes:\r\n[1] agent-totp: 108964 [##------------------] 26s\r\n\u001bcSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes\r\n\r\nPress Enter to return to the menu.\r\n\r\nImported 2FA Codes:\r\n[1] agent-totp: 108964 [###-----------------] 25s\r\n\u001bcSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes\r\n\r\nPress Enter to return to the menu.\r\n\r\nImported 2FA Codes:\r\n[1] agent-totp: 108964 [####----------------] 24s\r\n\u001bcSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes\r\n\r\nPress Enter to return to the menu.\r\n\r\nImported 2FA Codes:\r\n[1] agent-totp: 108964 [####----------------] 23s\r\n" + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "add_password_quick": true, + "invalid_length_validation": true, + "add_totp": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": false, + "archive_restore": false, + "totp_codes_view": false, + "settings_stats": false, + "graceful_exit": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191611Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191611Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191611Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T191611Z/transcript.clean.txt new file mode 100644 index 00000000..79ff3ec3 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191611Z/transcript.clean.txt @@ -0,0 +1,445 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +control tattoo spice whisper scrap addict lonely essence supreme inch admit capable +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-gty9bhbq/.seedpass/FB55576035C58E02/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: FB55576035C58E02 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: FB55576035C58E02 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gty9bhbq/.seedpass/FB55576035C58E02/backups/entries_db_backup_1771874172.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: N;Pp5Xp$4}6p + +Press Enter to continue... +cSeed Profile: FB55576035C58E02 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: FB55576035C58E02 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: N;Pp5Xp$4}6p +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: FB55576035C58E02 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: FB55576035C58E02 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: FB55576035C58E02 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: FB55576035C58E02 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: FB55576035C58E02 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: FB55576035C58E02 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: FB55576035C58E02 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: FB55576035C58E02 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: FB55576035C58E02 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: FB55576035C58E02 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gty9bhbq/.seedpass/FB55576035C58E02/backups/entries_db_backup_1771874173.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=R62QZOJYRRIRXNC4R77TEU4APWZTWOPX&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–€β–€β–€β–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆβ–„β–€Β β–„Β β–„Β β–„β–€Β β–€Β β–€β–€Β β–ˆβ–„Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–€β–€Β β–€Β Β β–€β–ˆΒ β–€β–„β–€β–€Β β–€β–„Β Β β–€Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–ˆβ–€β–„β–€β–„Β β–„Β β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€Β β–€β–€β–„Β β–„Β β–ˆΒ β–„Β β–ˆβ–„β–„β–„β–„β–„β–ˆΒ β–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–„Β β–ˆΒ β–€β–€β–€β–„β–ˆΒ β–€Β β–ˆΒ Β β–€β–ˆβ–€Β Β Β β–„β–„β–ˆβ–„Β β–€β–€β–€β–ˆΒ β–€Β β–ˆβ–€β–„β–ˆβ–ˆ +β–ˆβ–€β–ˆβ–„β–„β–€β–„β–€Β β–ˆΒ β–„β–€β–ˆβ–„β–„β–„β–„β–ˆβ–ˆβ–ˆβ–ˆΒ β–€β–€β–„β–ˆβ–„β–ˆβ–„β–ˆΒ Β β–„β–„β–„Β β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€Β Β β–€β–ˆΒ β–ˆβ–„β–„Β Β Β β–„β–ˆβ–€β–„β–ˆβ–„β–ˆΒ Β β–€β–ˆβ–„Β β–€β–€β–€β–„Β β–€β–€Β β–„β–ˆ +β–ˆβ–„β–„β–„β–ˆβ–ˆΒ β–€β–„β–ˆΒ β–„β–„β–€β–„β–ˆΒ β–ˆβ–„β–€β–€β–„Β β–ˆβ–€β–„β–ˆβ–€β–„Β Β β–€β–ˆΒ β–ˆΒ β–ˆβ–ˆβ–ˆ +β–ˆβ–€Β β–ˆβ–„Β β–„β–€β–ˆβ–„β–€β–„β–„β–ˆΒ β–„β–ˆΒ β–€Β β–ˆβ–„β–ˆΒ β–€β–„β–„β–€Β β–€β–„Β β–ˆβ–„Β β–€β–„β–ˆβ–ˆ +β–ˆΒ β–€β–„β–€β–€Β β–€β–€β–€β–€β–ˆβ–€β–€β–ˆβ–€β–€β–ˆβ–„Β β–„β–ˆΒ β–€β–ˆβ–€β–ˆβ–„β–„β–€β–€Β β–ˆβ–ˆβ–ˆβ–ˆβ–€β–„β–ˆ +β–ˆβ–€β–„β–„Β β–€Β β–€β–„β–ˆβ–ˆβ–€β–„β–ˆβ–€β–€β–ˆΒ β–„Β β–ˆβ–€β–ˆβ–€Β β–ˆΒ β–„Β Β β–„β–€β–„β–„β–ˆβ–€β–„β–ˆβ–ˆ +β–ˆβ–€Β β–„β–€Β β–„β–€Β β–„β–€Β β–€β–„β–ˆβ–ˆΒ β–€β–ˆβ–ˆβ–€β–„Β β–„β–„β–„β–„β–€β–„β–ˆβ–„β–ˆβ–ˆΒ β–€Β β–ˆβ–„β–ˆ +β–ˆβ–„β–ˆβ–„β–„β–ˆβ–€β–€β–„β–„β–„β–ˆβ–„β–€β–ˆΒ β–€β–ˆβ–„Β β–€β–„β–€β–„β–„Β β–€β–€Β β–€β–ˆβ–„β–ˆΒ Β β–ˆβ–ˆβ–ˆβ–ˆ +β–ˆβ–€β–€β–„Β Β β–ˆβ–€β–ˆβ–„β–ˆβ–„β–„β–€β–€β–€β–„Β β–ˆβ–€β–€Β Β β–€β–ˆβ–„β–ˆβ–ˆβ–€β–€Β β–€β–€Β β–„Β β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ β–€β–€Β β–€β–„β–ˆβ–„β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆΒ β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ β–„β–€β–€Β β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–„β–ˆΒ β–€β–ˆβ–„Β β–ˆβ–„Β Β β–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–€β–€β–€Β β–€Β Β Β β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆΒ Β β–„β–ˆβ–„β–ˆβ–ˆΒ Β β–ˆβ–€Β β–ˆΒ β–„β–„β–„β–€β–„β–„Β Β Β β–ˆβ–ˆβ–„β–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„β–„Β β–ˆΒ Β β–€β–€β–€β–ˆΒ β–ˆΒ β–€β–„Β β–ˆβ–€Β β–ˆΒ Β β–ˆβ–€β–„β–„Β β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: R62QZOJYRRIRXNC4R77TEU4APWZTWOPX + +Press Enter to continue... +cSeed Profile: FB55576035C58E02 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [########------------] 17s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [#########-----------] 16s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [##########----------] 15s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [##########----------] 14s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [###########---------] 13s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [############--------] 12s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [############--------] 11s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [#############-------] 10s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [##############------] 9s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [##############------] 8s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [###############-----] 7s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [################----] 6s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [################----] 5s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [#################---] 4s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [##################--] 3s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [##################--] 2s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [###################-] 1s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [--------------------] 30s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [--------------------] 29s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [#-------------------] 28s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [##------------------] 27s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [##------------------] 26s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [###-----------------] 25s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [####----------------] 24s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [####----------------] 23s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [#####---------------] 22s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [######--------------] 21s diff --git a/artifacts/agent_tui_test/20260223T191611Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T191611Z/transcript.raw.txt new file mode 100644 index 00000000..42030450 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191611Z/transcript.raw.txt @@ -0,0 +1,445 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +control tattoo spice whisper scrap addict lonely essence supreme inch admit capable +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-gty9bhbq/.seedpass/FB55576035C58E02/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: FB55576035C58E02 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: FB55576035C58E02 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gty9bhbq/.seedpass/FB55576035C58E02/backups/entries_db_backup_1771874172.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: N;Pp5Xp$4}6p + +Press Enter to continue... +cSeed Profile: FB55576035C58E02 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: FB55576035C58E02 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: N;Pp5Xp$4}6p +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: FB55576035C58E02 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: FB55576035C58E02 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: FB55576035C58E02 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: FB55576035C58E02 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: FB55576035C58E02 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: FB55576035C58E02 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: FB55576035C58E02 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: FB55576035C58E02 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: FB55576035C58E02 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: FB55576035C58E02 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gty9bhbq/.seedpass/FB55576035C58E02/backups/entries_db_backup_1771874173.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=R62QZOJYRRIRXNC4R77TEU4APWZTWOPX&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–€β–€β–€β–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆβ–„β–€Β β–„Β β–„Β β–„β–€Β β–€Β β–€β–€Β β–ˆβ–„Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–€β–€Β β–€Β Β β–€β–ˆΒ β–€β–„β–€β–€Β β–€β–„Β Β β–€Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–ˆβ–€β–„β–€β–„Β β–„Β β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€Β β–€β–€β–„Β β–„Β β–ˆΒ β–„Β β–ˆβ–„β–„β–„β–„β–„β–ˆΒ β–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–„Β β–ˆΒ β–€β–€β–€β–„β–ˆΒ β–€Β β–ˆΒ Β β–€β–ˆβ–€Β Β Β β–„β–„β–ˆβ–„Β β–€β–€β–€β–ˆΒ β–€Β β–ˆβ–€β–„β–ˆβ–ˆ +β–ˆβ–€β–ˆβ–„β–„β–€β–„β–€Β β–ˆΒ β–„β–€β–ˆβ–„β–„β–„β–„β–ˆβ–ˆβ–ˆβ–ˆΒ β–€β–€β–„β–ˆβ–„β–ˆβ–„β–ˆΒ Β β–„β–„β–„Β β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€Β Β β–€β–ˆΒ β–ˆβ–„β–„Β Β Β β–„β–ˆβ–€β–„β–ˆβ–„β–ˆΒ Β β–€β–ˆβ–„Β β–€β–€β–€β–„Β β–€β–€Β β–„β–ˆ +β–ˆβ–„β–„β–„β–ˆβ–ˆΒ β–€β–„β–ˆΒ β–„β–„β–€β–„β–ˆΒ β–ˆβ–„β–€β–€β–„Β β–ˆβ–€β–„β–ˆβ–€β–„Β Β β–€β–ˆΒ β–ˆΒ β–ˆβ–ˆβ–ˆ +β–ˆβ–€Β β–ˆβ–„Β β–„β–€β–ˆβ–„β–€β–„β–„β–ˆΒ β–„β–ˆΒ β–€Β β–ˆβ–„β–ˆΒ β–€β–„β–„β–€Β β–€β–„Β β–ˆβ–„Β β–€β–„β–ˆβ–ˆ +β–ˆΒ β–€β–„β–€β–€Β β–€β–€β–€β–€β–ˆβ–€β–€β–ˆβ–€β–€β–ˆβ–„Β β–„β–ˆΒ β–€β–ˆβ–€β–ˆβ–„β–„β–€β–€Β β–ˆβ–ˆβ–ˆβ–ˆβ–€β–„β–ˆ +β–ˆβ–€β–„β–„Β β–€Β β–€β–„β–ˆβ–ˆβ–€β–„β–ˆβ–€β–€β–ˆΒ β–„Β β–ˆβ–€β–ˆβ–€Β β–ˆΒ β–„Β Β β–„β–€β–„β–„β–ˆβ–€β–„β–ˆβ–ˆ +β–ˆβ–€Β β–„β–€Β β–„β–€Β β–„β–€Β β–€β–„β–ˆβ–ˆΒ β–€β–ˆβ–ˆβ–€β–„Β β–„β–„β–„β–„β–€β–„β–ˆβ–„β–ˆβ–ˆΒ β–€Β β–ˆβ–„β–ˆ +β–ˆβ–„β–ˆβ–„β–„β–ˆβ–€β–€β–„β–„β–„β–ˆβ–„β–€β–ˆΒ β–€β–ˆβ–„Β β–€β–„β–€β–„β–„Β β–€β–€Β β–€β–ˆβ–„β–ˆΒ Β β–ˆβ–ˆβ–ˆβ–ˆ +β–ˆβ–€β–€β–„Β Β β–ˆβ–€β–ˆβ–„β–ˆβ–„β–„β–€β–€β–€β–„Β β–ˆβ–€β–€Β Β β–€β–ˆβ–„β–ˆβ–ˆβ–€β–€Β β–€β–€Β β–„Β β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ β–€β–€Β β–€β–„β–ˆβ–„β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆΒ β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ β–„β–€β–€Β β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–„β–ˆΒ β–€β–ˆβ–„Β β–ˆβ–„Β Β β–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–€β–€β–€Β β–€Β Β Β β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆΒ Β β–„β–ˆβ–„β–ˆβ–ˆΒ Β β–ˆβ–€Β β–ˆΒ β–„β–„β–„β–€β–„β–„Β Β Β β–ˆβ–ˆβ–„β–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„β–„Β β–ˆΒ Β β–€β–€β–€β–ˆΒ β–ˆΒ β–€β–„Β β–ˆβ–€Β β–ˆΒ Β β–ˆβ–€β–„β–„Β β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: R62QZOJYRRIRXNC4R77TEU4APWZTWOPX + +Press Enter to continue... +cSeed Profile: FB55576035C58E02 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [########------------] 17s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [#########-----------] 16s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [##########----------] 15s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [##########----------] 14s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [###########---------] 13s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [############--------] 12s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [############--------] 11s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [#############-------] 10s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [##############------] 9s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [##############------] 8s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [###############-----] 7s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [################----] 6s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [################----] 5s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [#################---] 4s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [##################--] 3s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [##################--] 2s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 519022 [###################-] 1s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [--------------------] 30s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [--------------------] 29s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [#-------------------] 28s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [##------------------] 27s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [##------------------] 26s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [###-----------------] 25s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [####----------------] 24s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [####----------------] 23s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [#####---------------] 22s +cSeed Profile: FB55576035C58E02 > Main Menu > 2FA Codes + +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 108964 [######--------------] 21s diff --git a/artifacts/agent_tui_test/20260223T191656Z/report.json b/artifacts/agent_tui_test/20260223T191656Z/report.json new file mode 100644 index 00000000..2461dc79 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191656Z/report.json @@ -0,0 +1,40 @@ +{ + "timestamp_utc": "20260223T191656Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-x68y5m0q", + "duration_sec": 4.189, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 4.120153266998386, + "detail": null + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "add_password_quick": true, + "invalid_length_validation": true, + "add_totp": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_codes_view": true, + "settings_stats": true, + "graceful_exit": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191656Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191656Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191656Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T191656Z/transcript.clean.txt new file mode 100644 index 00000000..a0cfc502 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191656Z/transcript.clean.txt @@ -0,0 +1,523 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +later push couch foot harsh detect very wage teach lawn manage agree +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-x68y5m0q/.seedpass/CD235E80D3BD7C45/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-x68y5m0q/.seedpass/CD235E80D3BD7C45/backups/entries_db_backup_1771874217.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: wJE!"^8J40df + +Press Enter to continue... +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: wJE!"^8J40df +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: CD235E80D3BD7C45 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: CD235E80D3BD7C45 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: CD235E80D3BD7C45 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-x68y5m0q/.seedpass/CD235E80D3BD7C45/backups/entries_db_backup_1771874218.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=LYLEEHEKMMA4M3CG4GRFBEVVJQL7ALF6&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆΒ β–€β–ˆβ–„Β Β Β β–„β–€Β β–€Β β–€β–€Β β–ˆβ–„Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–„β–€β–„β–€Β β–„β–„β–„Β β–€β–„β–€β–€Β β–€β–„Β Β β–€Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–„Β β–„β–€β–ˆβ–€β–ˆβ–€β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€Β β–€β–„β–„Β β–€β–ˆβ–„Β β–„Β β–ˆβ–„β–„β–„β–„β–„β–ˆΒ β–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–€β–„Β Β Β Β β–€β–€β–€β–ˆβ–€Β Β β–ˆβ–„β–€β–ˆβ–ˆβ–„Β Β β–„β–„β–ˆβ–„Β β–€β–€β–€β–„β–€Β β–„β–ˆβ–€β–„β–ˆβ–ˆ +β–ˆβ–ˆΒ Β β–ˆβ–ˆβ–€β–€β–ˆβ–ˆΒ β–€β–ˆβ–ˆβ–€Β β–„β–„β–ˆβ–„β–ˆβ–ˆΒ β–€β–€β–„β–ˆβ–„β–€β–„β–ˆΒ β–€β–„β–ˆΒ Β β–€β–ˆ +β–ˆβ–ˆβ–€Β β–ˆβ–„β–ˆβ–€Β β–ˆβ–ˆβ–„β–ˆΒ β–€β–ˆβ–€β–„β–€β–ˆβ–ˆβ–„β–ˆΒ Β β–€β–ˆβ–„Β β–€β–ˆβ–ˆβ–„Β β–€β–€β–„β–„β–ˆ +β–ˆβ–„Β β–€β–ˆβ–€β–„β–€β–„Β β–„β–€β–ˆβ–€Β Β β–€β–ˆβ–„β–€β–€β–„Β β–ˆβ–€β–„β–ˆβ–€β–„β–„β–ˆΒ β–€Β β–ˆΒ β–„β–ˆβ–ˆ +β–ˆβ–€Β Β β–ˆβ–„β–ˆβ–€β–€β–ˆΒ β–ˆΒ β–„β–ˆβ–ˆβ–ˆΒ β–ˆβ–„β–ˆβ–„β–ˆΒ β–€β–„β–„β–€β–€β–„β–„Β β–ˆβ–€β–€β–€β–„β–ˆβ–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–„β–€β–„β–„Β β–ˆβ–€β–„β–€Β β–€β–€Β β–„β–„β–ˆΒ β–€β–ˆβ–€β–ˆβ–„β–„β–€β–€Β β–„β–ˆβ–ˆβ–ˆβ–€β–„β–ˆ +β–ˆΒ β–€β–ˆβ–€β–„Β β–€Β Β Β β–€β–„β–„β–„β–€Β β–ˆβ–„β–€β–ˆβ–€β–ˆβ–€Β β–ˆΒ β–„Β Β β–„β–ˆβ–„β–„β–ˆβ–€β–„β–€β–ˆ +β–ˆΒ Β β–„Β β–€β–€β–€Β β–ˆβ–„β–„β–ˆΒ Β Β β–„β–€β–ˆβ–ˆβ–€β–„Β β–„β–„β–„β–„β–€β–„β–€β–€Β β–ˆβ–„β–€Β Β β–ˆβ–ˆ +β–ˆβ–„β–ˆβ–„β–ˆβ–„β–€β–€Β β–€β–„Β β–€β–ˆβ–€Β β–€β–ˆβ–ˆΒ β–€β–„β–€β–„β–„Β β–€β–€β–ˆβ–„β–„β–ˆβ–€β–€Β β–€β–ˆβ–ˆβ–ˆ +β–ˆβ–€β–€β–€β–€β–€Β β–€β–„Β β–ˆβ–„Β β–„Β Β β–„β–„β–€β–„β–€Β Β β–€β–ˆβ–„β–ˆβ–ˆβ–„β–€Β β–€Β β–€Β β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ β–„β–„Β β–„β–€β–ˆβ–€β–„β–€β–„β–ˆβ–ˆβ–€β–ˆΒ β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ β–„β–€β–€Β β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€Β β–ˆβ–ˆβ–€β–€β–ˆΒ β–ˆβ–„Β Β β–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–€β–€β–€Β β–€Β β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆΒ β–ˆβ–ˆβ–„β–„β–€β–ˆΒ β–„β–ˆβ–€Β β–ˆΒ β–„β–„β–„β–€β–„β–„Β Β Β β–ˆβ–ˆΒ β–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€Β Β β–€β–„β–€β–ˆβ–€β–€β–„β–€Β β–ˆΒ β–€β–„Β β–ˆβ–€β–€β–ˆβ–„β–€β–ˆβ–€β–ˆβ–ˆΒ β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: LYLEEHEKMMA4M3CG4GRFBEVVJQL7ALF6 + +Press Enter to continue... +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: CD235E80D3BD7C45 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 472782 [##################--] 2s + +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-x68y5m0q/.seedpass/CD235E80D3BD7C45/backups/entries_db_backup_1771874218.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: wJE!"^8J40df +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: CD235E80D3BD7C45 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-x68y5m0q/.seedpass/CD235E80D3BD7C45/backups/entries_db_backup_1771874218.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: CD235E80D3BD7C45 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-x68y5m0q/.seedpass/CD235E80D3BD7C45/backups/entries_db_backup_1771874218.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: CD235E80D3BD7C45 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 080875 [--------------------] 30s + +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 2 + password: 1 + totp: 1 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-x68y5m0q/.seedpass/CD235E80D3BD7C45/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T191656Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T191656Z/transcript.raw.txt new file mode 100644 index 00000000..c6e67e77 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191656Z/transcript.raw.txt @@ -0,0 +1,524 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +later push couch foot harsh detect very wage teach lawn manage agree +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-x68y5m0q/.seedpass/CD235E80D3BD7C45/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-x68y5m0q/.seedpass/CD235E80D3BD7C45/backups/entries_db_backup_1771874217.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: wJE!"^8J40df + +Press Enter to continue... +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: wJE!"^8J40df +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: CD235E80D3BD7C45 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: CD235E80D3BD7C45 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: CD235E80D3BD7C45 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-x68y5m0q/.seedpass/CD235E80D3BD7C45/backups/entries_db_backup_1771874218.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=LYLEEHEKMMA4M3CG4GRFBEVVJQL7ALF6&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆΒ β–€β–ˆβ–„Β Β Β β–„β–€Β β–€Β β–€β–€Β β–ˆβ–„Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–„β–€β–„β–€Β β–„β–„β–„Β β–€β–„β–€β–€Β β–€β–„Β Β β–€Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–„Β β–„β–€β–ˆβ–€β–ˆβ–€β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€Β β–€β–„β–„Β β–€β–ˆβ–„Β β–„Β β–ˆβ–„β–„β–„β–„β–„β–ˆΒ β–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–€β–„Β Β Β Β β–€β–€β–€β–ˆβ–€Β Β β–ˆβ–„β–€β–ˆβ–ˆβ–„Β Β β–„β–„β–ˆβ–„Β β–€β–€β–€β–„β–€Β β–„β–ˆβ–€β–„β–ˆβ–ˆ +β–ˆβ–ˆΒ Β β–ˆβ–ˆβ–€β–€β–ˆβ–ˆΒ β–€β–ˆβ–ˆβ–€Β β–„β–„β–ˆβ–„β–ˆβ–ˆΒ β–€β–€β–„β–ˆβ–„β–€β–„β–ˆΒ β–€β–„β–ˆΒ Β β–€β–ˆ +β–ˆβ–ˆβ–€Β β–ˆβ–„β–ˆβ–€Β β–ˆβ–ˆβ–„β–ˆΒ β–€β–ˆβ–€β–„β–€β–ˆβ–ˆβ–„β–ˆΒ Β β–€β–ˆβ–„Β β–€β–ˆβ–ˆβ–„Β β–€β–€β–„β–„β–ˆ +β–ˆβ–„Β β–€β–ˆβ–€β–„β–€β–„Β β–„β–€β–ˆβ–€Β Β β–€β–ˆβ–„β–€β–€β–„Β β–ˆβ–€β–„β–ˆβ–€β–„β–„β–ˆΒ β–€Β β–ˆΒ β–„β–ˆβ–ˆ +β–ˆβ–€Β Β β–ˆβ–„β–ˆβ–€β–€β–ˆΒ β–ˆΒ β–„β–ˆβ–ˆβ–ˆΒ β–ˆβ–„β–ˆβ–„β–ˆΒ β–€β–„β–„β–€β–€β–„β–„Β β–ˆβ–€β–€β–€β–„β–ˆβ–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–„β–€β–„β–„Β β–ˆβ–€β–„β–€Β β–€β–€Β β–„β–„β–ˆΒ β–€β–ˆβ–€β–ˆβ–„β–„β–€β–€Β β–„β–ˆβ–ˆβ–ˆβ–€β–„β–ˆ +β–ˆΒ β–€β–ˆβ–€β–„Β β–€Β Β Β β–€β–„β–„β–„β–€Β β–ˆβ–„β–€β–ˆβ–€β–ˆβ–€Β β–ˆΒ β–„Β Β β–„β–ˆβ–„β–„β–ˆβ–€β–„β–€β–ˆ +β–ˆΒ Β β–„Β β–€β–€β–€Β β–ˆβ–„β–„β–ˆΒ Β Β β–„β–€β–ˆβ–ˆβ–€β–„Β β–„β–„β–„β–„β–€β–„β–€β–€Β β–ˆβ–„β–€Β Β β–ˆβ–ˆ +β–ˆβ–„β–ˆβ–„β–ˆβ–„β–€β–€Β β–€β–„Β β–€β–ˆβ–€Β β–€β–ˆβ–ˆΒ β–€β–„β–€β–„β–„Β β–€β–€β–ˆβ–„β–„β–ˆβ–€β–€Β β–€β–ˆβ–ˆβ–ˆ +β–ˆβ–€β–€β–€β–€β–€Β β–€β–„Β β–ˆβ–„Β β–„Β Β β–„β–„β–€β–„β–€Β Β β–€β–ˆβ–„β–ˆβ–ˆβ–„β–€Β β–€Β β–€Β β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ β–„β–„Β β–„β–€β–ˆβ–€β–„β–€β–„β–ˆβ–ˆβ–€β–ˆΒ β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ β–„β–€β–€Β β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€Β β–ˆβ–ˆβ–€β–€β–ˆΒ β–ˆβ–„Β Β β–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–€β–€β–€Β β–€Β β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆΒ β–ˆβ–ˆβ–„β–„β–€β–ˆΒ β–„β–ˆβ–€Β β–ˆΒ β–„β–„β–„β–€β–„β–„Β Β Β β–ˆβ–ˆΒ β–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€Β Β β–€β–„β–€β–ˆβ–€β–€β–„β–€Β β–ˆΒ β–€β–„Β β–ˆβ–€β–€β–ˆβ–„β–€β–ˆβ–€β–ˆβ–ˆΒ β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: LYLEEHEKMMA4M3CG4GRFBEVVJQL7ALF6 + +Press Enter to continue... +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: CD235E80D3BD7C45 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 472782 [##################--] 2s + +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-x68y5m0q/.seedpass/CD235E80D3BD7C45/backups/entries_db_backup_1771874218.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: wJE!"^8J40df +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: CD235E80D3BD7C45 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-x68y5m0q/.seedpass/CD235E80D3BD7C45/backups/entries_db_backup_1771874218.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: CD235E80D3BD7C45 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-x68y5m0q/.seedpass/CD235E80D3BD7C45/backups/entries_db_backup_1771874218.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: CD235E80D3BD7C45 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: CD235E80D3BD7C45 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 080875 [--------------------] 30s + +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 2 + password: 1 + totp: 1 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-x68y5m0q/.seedpass/CD235E80D3BD7C45/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: CD235E80D3BD7C45 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191700Z/report.json b/artifacts/agent_tui_test/20260223T191700Z/report.json new file mode 100644 index 00000000..d1384ee4 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191700Z/report.json @@ -0,0 +1,40 @@ +{ + "timestamp_utc": "20260223T191700Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-v2356wrz", + "duration_sec": 4.201, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 4.12864226000238, + "detail": null + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "add_password_quick": true, + "invalid_length_validation": true, + "add_totp": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_codes_view": true, + "settings_stats": true, + "graceful_exit": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191700Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191700Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191700Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T191700Z/transcript.clean.txt new file mode 100644 index 00000000..833eef29 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191700Z/transcript.clean.txt @@ -0,0 +1,523 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +multiply math void grief labor spring trend believe swear escape basket rough +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-v2356wrz/.seedpass/91A6B9A8F95FD95F/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-v2356wrz/.seedpass/91A6B9A8F95FD95F/backups/entries_db_backup_1771874221.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: Z`!h\n9Gf1H4 + +Press Enter to continue... +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Z`!h\n9Gf1H4 +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 91A6B9A8F95FD95F > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-v2356wrz/.seedpass/91A6B9A8F95FD95F/backups/entries_db_backup_1771874222.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=NOYYKYVO3LBREYXGCWQSN5ZPUG5PYW5F&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–€β–ˆβ–€β–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆβ–€Β β–€β–ˆβ–„β–ˆΒ β–ˆΒ β–ˆΒ β–€β–„Β β–€Β β–ˆβ–€β–ˆβ–€β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆβ–ˆβ–€Β Β Β β–ˆβ–„β–€Β β–€β–ˆβ–€β–€β–€β–€β–„β–€Β β–€β–€β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–„β–€β–ˆβ–€β–„β–€β–ˆβ–€β–„β–€β–„β–€β–„β–€β–ˆβ–€β–ˆΒ β–„Β β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–€β–€β–ˆβ–€β–„Β β–ˆΒ β–ˆΒ β–€β–ˆΒ Β β–€Β β–„Β Β β–„β–€β–„β–€β–€β–€β–ˆβ–€β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ +β–ˆΒ β–ˆβ–„β–€β–€β–ˆβ–€β–€β–„Β β–„β–ˆΒ β–ˆΒ β–„β–€β–„β–ˆβ–„β–ˆβ–€Β Β β–€β–„β–„β–„β–ˆβ–€β–ˆβ–€β–€β–ˆΒ β–€Β β–ˆ +β–ˆβ–€β–„β–„β–„β–€Β β–€β–„β–€β–€β–„β–ˆβ–€Β β–€β–„β–€β–€β–€Β β–„Β β–„Β β–„Β β–ˆβ–ˆβ–€β–„Β β–„β–„β–ˆβ–„β–€β–€β–ˆ +β–ˆβ–ˆβ–€β–„β–„β–€β–€β–€β–ˆΒ β–ˆβ–€β–€β–€Β β–„Β β–ˆΒ β–€β–„β–ˆΒ β–€β–€β–„β–„β–ˆβ–ˆΒ β–„Β β–ˆβ–€β–„Β Β Β β–ˆ +β–ˆβ–€β–„β–€β–€β–ˆβ–„β–€β–„β–€β–€β–„Β β–ˆβ–„β–„Β β–ˆβ–„β–€Β β–„Β β–„β–€β–„β–„β–€β–„β–ˆβ–€β–€Β β–„β–ˆβ–€Β Β β–ˆ +β–ˆΒ β–ˆβ–„β–ˆβ–ˆΒ β–€Β β–„β–ˆΒ β–„β–„β–ˆβ–€Β Β β–€β–€β–ˆΒ Β Β β–ˆβ–€β–„β–ˆΒ β–ˆβ–€β–„Β β–„β–„β–„Β Β β–ˆ +β–ˆΒ β–„β–ˆΒ β–€β–ˆβ–€β–„β–„Β β–€β–€β–„β–€β–ˆβ–€β–€β–€β–„Β β–€Β β–ˆβ–€β–€β–€Β β–ˆβ–ˆβ–ˆΒ β–€β–€Β β–„β–ˆβ–„β–ˆ +β–ˆΒ β–€β–„β–ˆβ–„Β β–€β–€β–ˆβ–ˆβ–„β–€β–„β–ˆβ–„Β β–€β–€β–ˆβ–€β–„Β β–ˆβ–ˆΒ β–„β–€β–ˆβ–„β–ˆΒ Β β–€Β β–ˆβ–„β–„β–ˆ +β–ˆβ–€β–„β–€β–„Β β–„β–€β–ˆΒ Β β–ˆΒ β–ˆΒ β–ˆβ–„β–„β–„β–ˆβ–„β–ˆΒ β–€β–ˆβ–„β–€Β β–„Β Β β–ˆβ–„β–€β–€β–ˆβ–€β–€β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–€β–€β–€β–€β–ˆΒ Β Β β–ˆβ–„β–ˆβ–ˆβ–„β–„β–„β–€Β β–ˆβ–„β–ˆβ–ˆβ–ˆΒ Β Β Β β–ˆΒ β–„β–ˆβ–ˆβ–€β–„Β β–ˆ +β–ˆβ–€Β β–€β–€Β β–ˆβ–€β–€β–€Β β–„β–ˆβ–„β–„β–€β–„β–ˆβ–ˆΒ Β Β Β Β β–ˆβ–„β–„β–ˆβ–ˆΒ Β β–€Β β–€Β β–„β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–„Β β–€β–€β–€β–„β–ˆΒ Β β–ˆβ–€β–ˆβ–€β–„β–ˆβ–„β–„β–ˆβ–€β–€Β β–ˆβ–€β–ˆΒ β–€β–€β–„β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–„β–€β–ˆβ–ˆΒ β–ˆβ–ˆβ–€Β Β Β β–„β–€β–€Β β–„β–„β–€β–„β–ˆΒ β–€β–€β–€Β β–€β–„β–„β–€β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–„β–ˆΒ β–„Β Β β–€Β β–„β–€β–„β–ˆβ–ˆΒ β–„β–€β–€Β β–„β–€Β β–ˆβ–ˆβ–„Β β–€β–ˆβ–„Β β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–ˆβ–„β–ˆΒ β–„β–„β–€β–„β–„β–€β–ˆβ–„Β β–„β–ˆΒ Β Β β–„β–ˆΒ β–€Β Β β–€Β β–€β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: NOYYKYVO3LBREYXGCWQSN5ZPUG5PYW5F + +Press Enter to continue... +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 442018 [#-------------------] 28s + +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-v2356wrz/.seedpass/91A6B9A8F95FD95F/backups/entries_db_backup_1771874222.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Z`!h\n9Gf1H4 +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 91A6B9A8F95FD95F > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-v2356wrz/.seedpass/91A6B9A8F95FD95F/backups/entries_db_backup_1771874222.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 91A6B9A8F95FD95F > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-v2356wrz/.seedpass/91A6B9A8F95FD95F/backups/entries_db_backup_1771874222.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 442018 [##------------------] 26s + +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 2 + password: 1 + totp: 1 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-v2356wrz/.seedpass/91A6B9A8F95FD95F/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T191700Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T191700Z/transcript.raw.txt new file mode 100644 index 00000000..4841c21e --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191700Z/transcript.raw.txt @@ -0,0 +1,524 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +multiply math void grief labor spring trend believe swear escape basket rough +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-v2356wrz/.seedpass/91A6B9A8F95FD95F/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-v2356wrz/.seedpass/91A6B9A8F95FD95F/backups/entries_db_backup_1771874221.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: Z`!h\n9Gf1H4 + +Press Enter to continue... +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Z`!h\n9Gf1H4 +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 91A6B9A8F95FD95F > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-v2356wrz/.seedpass/91A6B9A8F95FD95F/backups/entries_db_backup_1771874222.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=NOYYKYVO3LBREYXGCWQSN5ZPUG5PYW5F&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–€β–ˆβ–€β–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆβ–€Β β–€β–ˆβ–„β–ˆΒ β–ˆΒ β–ˆΒ β–€β–„Β β–€Β β–ˆβ–€β–ˆβ–€β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆβ–ˆβ–€Β Β Β β–ˆβ–„β–€Β β–€β–ˆβ–€β–€β–€β–€β–„β–€Β β–€β–€β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–„β–€β–ˆβ–€β–„β–€β–ˆβ–€β–„β–€β–„β–€β–„β–€β–ˆβ–€β–ˆΒ β–„Β β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–€β–€β–ˆβ–€β–„Β β–ˆΒ β–ˆΒ β–€β–ˆΒ Β β–€Β β–„Β Β β–„β–€β–„β–€β–€β–€β–ˆβ–€β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ +β–ˆΒ β–ˆβ–„β–€β–€β–ˆβ–€β–€β–„Β β–„β–ˆΒ β–ˆΒ β–„β–€β–„β–ˆβ–„β–ˆβ–€Β Β β–€β–„β–„β–„β–ˆβ–€β–ˆβ–€β–€β–ˆΒ β–€Β β–ˆ +β–ˆβ–€β–„β–„β–„β–€Β β–€β–„β–€β–€β–„β–ˆβ–€Β β–€β–„β–€β–€β–€Β β–„Β β–„Β β–„Β β–ˆβ–ˆβ–€β–„Β β–„β–„β–ˆβ–„β–€β–€β–ˆ +β–ˆβ–ˆβ–€β–„β–„β–€β–€β–€β–ˆΒ β–ˆβ–€β–€β–€Β β–„Β β–ˆΒ β–€β–„β–ˆΒ β–€β–€β–„β–„β–ˆβ–ˆΒ β–„Β β–ˆβ–€β–„Β Β Β β–ˆ +β–ˆβ–€β–„β–€β–€β–ˆβ–„β–€β–„β–€β–€β–„Β β–ˆβ–„β–„Β β–ˆβ–„β–€Β β–„Β β–„β–€β–„β–„β–€β–„β–ˆβ–€β–€Β β–„β–ˆβ–€Β Β β–ˆ +β–ˆΒ β–ˆβ–„β–ˆβ–ˆΒ β–€Β β–„β–ˆΒ β–„β–„β–ˆβ–€Β Β β–€β–€β–ˆΒ Β Β β–ˆβ–€β–„β–ˆΒ β–ˆβ–€β–„Β β–„β–„β–„Β Β β–ˆ +β–ˆΒ β–„β–ˆΒ β–€β–ˆβ–€β–„β–„Β β–€β–€β–„β–€β–ˆβ–€β–€β–€β–„Β β–€Β β–ˆβ–€β–€β–€Β β–ˆβ–ˆβ–ˆΒ β–€β–€Β β–„β–ˆβ–„β–ˆ +β–ˆΒ β–€β–„β–ˆβ–„Β β–€β–€β–ˆβ–ˆβ–„β–€β–„β–ˆβ–„Β β–€β–€β–ˆβ–€β–„Β β–ˆβ–ˆΒ β–„β–€β–ˆβ–„β–ˆΒ Β β–€Β β–ˆβ–„β–„β–ˆ +β–ˆβ–€β–„β–€β–„Β β–„β–€β–ˆΒ Β β–ˆΒ β–ˆΒ β–ˆβ–„β–„β–„β–ˆβ–„β–ˆΒ β–€β–ˆβ–„β–€Β β–„Β Β β–ˆβ–„β–€β–€β–ˆβ–€β–€β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–€β–€β–€β–€β–ˆΒ Β Β β–ˆβ–„β–ˆβ–ˆβ–„β–„β–„β–€Β β–ˆβ–„β–ˆβ–ˆβ–ˆΒ Β Β Β β–ˆΒ β–„β–ˆβ–ˆβ–€β–„Β β–ˆ +β–ˆβ–€Β β–€β–€Β β–ˆβ–€β–€β–€Β β–„β–ˆβ–„β–„β–€β–„β–ˆβ–ˆΒ Β Β Β Β β–ˆβ–„β–„β–ˆβ–ˆΒ Β β–€Β β–€Β β–„β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–„Β β–€β–€β–€β–„β–ˆΒ Β β–ˆβ–€β–ˆβ–€β–„β–ˆβ–„β–„β–ˆβ–€β–€Β β–ˆβ–€β–ˆΒ β–€β–€β–„β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–„β–€β–ˆβ–ˆΒ β–ˆβ–ˆβ–€Β Β Β β–„β–€β–€Β β–„β–„β–€β–„β–ˆΒ β–€β–€β–€Β β–€β–„β–„β–€β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–„β–ˆΒ β–„Β Β β–€Β β–„β–€β–„β–ˆβ–ˆΒ β–„β–€β–€Β β–„β–€Β β–ˆβ–ˆβ–„Β β–€β–ˆβ–„Β β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–ˆβ–„β–ˆΒ β–„β–„β–€β–„β–„β–€β–ˆβ–„Β β–„β–ˆΒ Β Β β–„β–ˆΒ β–€Β Β β–€Β β–€β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: NOYYKYVO3LBREYXGCWQSN5ZPUG5PYW5F + +Press Enter to continue... +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 442018 [#-------------------] 28s + +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-v2356wrz/.seedpass/91A6B9A8F95FD95F/backups/entries_db_backup_1771874222.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Z`!h\n9Gf1H4 +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 91A6B9A8F95FD95F > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-v2356wrz/.seedpass/91A6B9A8F95FD95F/backups/entries_db_backup_1771874222.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 91A6B9A8F95FD95F > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-v2356wrz/.seedpass/91A6B9A8F95FD95F/backups/entries_db_backup_1771874222.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 91A6B9A8F95FD95F > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 442018 [##------------------] 26s + +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 2 + password: 1 + totp: 1 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-v2356wrz/.seedpass/91A6B9A8F95FD95F/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 91A6B9A8F95FD95F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191704Z/report.json b/artifacts/agent_tui_test/20260223T191704Z/report.json new file mode 100644 index 00000000..876977f9 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191704Z/report.json @@ -0,0 +1,40 @@ +{ + "timestamp_utc": "20260223T191704Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-swz_wc1p", + "duration_sec": 52.883, + "seedpass_exit_code": -9, + "status": "failed", + "failure": "Unable to return to main menu within timeout.", + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "failed", + "duration_sec": 51.36423393499717, + "detail": "Unable to return to main menu within timeout." + } + ], + "coverage_points": { + "startup_onboarding": false, + "main_menu": false, + "add_password_quick": false, + "invalid_length_validation": false, + "add_totp": false, + "retrieve_entry": false, + "search_entries": false, + "list_entries": false, + "modify_entry": false, + "archive_restore": false, + "totp_codes_view": false, + "settings_stats": false, + "graceful_exit": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191704Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191704Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191704Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T191704Z/transcript.clean.txt new file mode 100644 index 00000000..9d5dbbf2 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191704Z/transcript.clean.txt @@ -0,0 +1,18 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +tooth furnace range force bicycle rug first frost cherry grab grit stumble +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: AgentPass123! diff --git a/artifacts/agent_tui_test/20260223T191704Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T191704Z/transcript.raw.txt new file mode 100644 index 00000000..9d5dbbf2 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191704Z/transcript.raw.txt @@ -0,0 +1,18 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +tooth furnace range force bicycle rug first frost cherry grab grit stumble +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: AgentPass123! diff --git a/artifacts/agent_tui_test/20260223T191833Z/report.json b/artifacts/agent_tui_test/20260223T191833Z/report.json new file mode 100644 index 00000000..2b990536 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191833Z/report.json @@ -0,0 +1,40 @@ +{ + "timestamp_utc": "20260223T191833Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-eug352_t", + "duration_sec": 5.385, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 5.310055312998884, + "detail": null + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "add_password_quick": true, + "invalid_length_validation": true, + "add_totp": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_codes_view": true, + "settings_stats": true, + "graceful_exit": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191833Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191833Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191833Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T191833Z/transcript.clean.txt new file mode 100644 index 00000000..afa373bc --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191833Z/transcript.clean.txt @@ -0,0 +1,523 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +asset often alone display candy before sugar chest identify change road stone +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-eug352_t/.seedpass/D8A9EDE84D27F3D4/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-eug352_t/.seedpass/D8A9EDE84D27F3D4/backups/entries_db_backup_1771874315.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: 9&NIx7D2@r`i + +Press Enter to continue... +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 9&NIx7D2@r`i +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: D8A9EDE84D27F3D4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-eug352_t/.seedpass/D8A9EDE84D27F3D4/backups/entries_db_backup_1771874316.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=DXCXZHH5NSR322BLNNUNARKDR3NMZ2KF&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€β–€β–ˆβ–€β–€β–€β–ˆβ–€β–€β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆΒ β–ˆΒ Β β–„β–ˆΒ β–ˆβ–„β–ˆβ–„β–ˆΒ β–€β–€β–„β–€Β Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€β–„Β β–€β–€Β β–ˆβ–ˆΒ β–ˆΒ Β Β β–„Β β–„β–ˆβ–„β–€β–„Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„β–€β–ˆΒ β–„β–€β–„Β β–ˆΒ β–ˆΒ β–ˆΒ β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–€β–€β–€β–€β–€β–€Β Β β–„Β β–„β–„β–ˆβ–„β–ˆβ–€β–„β–€β–€β–€β–ˆβ–ˆβ–„β–ˆβ–„Β β–€β–ˆβ–ˆβ–€β–ˆβ–€β–€β–€β–ˆ +β–ˆβ–„Β β–„Β Β β–„β–€Β β–ˆΒ β–€β–„β–„β–„β–ˆβ–€Β β–ˆΒ β–€β–„β–„β–€β–ˆΒ β–€β–ˆβ–€β–„β–ˆβ–„β–„β–€β–€β–„β–„β–€β–ˆ +β–ˆΒ Β Β Β β–ˆβ–„β–€β–„β–„Β Β β–€Β β–€β–ˆβ–€β–„β–„β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„β–„Β β–€β–€β–€β–„β–€β–„β–„Β β–ˆ +β–ˆβ–„Β Β β–ˆΒ β–„β–€Β β–„Β β–ˆβ–€β–€β–„β–„Β Β β–ˆΒ β–€β–„β–ˆΒ β–„β–ˆβ–€β–„Β β–€β–€β–ˆΒ Β β–€β–€β–„Β β–ˆ +β–ˆβ–€Β β–ˆΒ β–ˆβ–€β–€β–€β–„β–„β–€β–ˆβ–ˆΒ β–€Β β–„β–€Β β–ˆβ–ˆβ–ˆβ–ˆβ–„β–ˆβ–€Β β–€Β β–€Β β–ˆβ–€Β Β β–„β–€β–ˆ +β–ˆΒ Β β–€β–„β–„β–„β–€β–ˆΒ Β β–€Β β–„β–ˆβ–€β–ˆβ–€β–ˆΒ Β β–€β–ˆβ–€Β Β β–€β–„β–ˆΒ β–„β–ˆβ–„Β Β Β β–ˆβ–€β–ˆ +β–ˆβ–€β–„Β β–ˆβ–ˆΒ β–€β–ˆβ–ˆβ–„β–€β–ˆβ–„β–ˆΒ β–„Β β–ˆβ–„β–ˆΒ β–ˆβ–„β–„Β β–„β–€β–ˆβ–„Β β–€β–ˆΒ β–€β–ˆΒ β–ˆβ–ˆ +β–ˆβ–„β–€β–ˆβ–ˆβ–€β–„β–€β–€Β β–€β–„Β Β Β Β β–€β–€β–„β–„β–„β–ˆβ–ˆβ–„Β β–€β–€Β Β β–ˆΒ β–ˆβ–ˆΒ β–ˆβ–„Β Β β–ˆ +β–ˆβ–„β–„β–€β–„β–€β–ˆβ–€β–€Β β–€β–ˆβ–€β–„β–€β–„β–€β–„β–€β–„β–€β–„β–ˆΒ Β β–ˆβ–„β–€β–€β–ˆβ–„Β β–ˆβ–„β–„β–„β–„Β β–ˆ +β–ˆΒ β–€Β β–€β–€Β β–€β–„β–ˆΒ Β β–ˆΒ β–ˆβ–ˆβ–€β–ˆβ–€β–„β–ˆβ–„β–€β–„Β β–„β–ˆβ–€β–€Β β–€Β β–ˆΒ β–€β–ˆβ–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–„β–€β–€β–„Β β–„Β β–ˆβ–ˆβ–ˆβ–„β–€β–„β–„β–€β–ˆβ–€β–ˆβ–€Β β–ˆβ–€β–„β–„Β β–€Β Β Β β–€β–€Β Β β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ β–€Β β–ˆβ–ˆΒ β–€β–ˆβ–„Β β–€Β Β β–€β–„β–€β–ˆΒ Β β–„Β β–ˆβ–€β–ˆΒ β–„Β Β β–„β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆΒ β–€β–ˆβ–€β–„β–ˆβ–€β–€β–€β–ˆβ–€β–€Β β–„β–€β–€β–ˆβ–„β–ˆΒ Β β–€β–€β–€Β β–„β–ˆβ–„β–„β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–„β–„Β β–„β–€Β β–€β–ˆβ–ˆΒ β–€Β β–„β–ˆβ–ˆβ–„Β β–ˆβ–ˆβ–„β–€Β β–„β–€β–€β–ˆβ–€β–€β–€β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–€Β Β Β β–€Β β–„β–€β–ˆβ–„Β β–ˆβ–ˆβ–ˆΒ β–€β–ˆβ–€β–€β–„β–„β–„β–ˆβ–€β–€β–ˆβ–„Β β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: DXCXZHH5NSR322BLNNUNARKDR3NMZ2KF + +Press Enter to continue... +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 203226 [####----------------] 24s + +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-eug352_t/.seedpass/D8A9EDE84D27F3D4/backups/entries_db_backup_1771874316.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 9&NIx7D2@r`i +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: D8A9EDE84D27F3D4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-eug352_t/.seedpass/D8A9EDE84D27F3D4/backups/entries_db_backup_1771874316.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: D8A9EDE84D27F3D4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-eug352_t/.seedpass/D8A9EDE84D27F3D4/backups/entries_db_backup_1771874316.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 203226 [#####---------------] 22s + +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 2 + password: 1 + totp: 1 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-eug352_t/.seedpass/D8A9EDE84D27F3D4/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T191833Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T191833Z/transcript.raw.txt new file mode 100644 index 00000000..fe6816ec --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191833Z/transcript.raw.txt @@ -0,0 +1,524 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +asset often alone display candy before sugar chest identify change road stone +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-eug352_t/.seedpass/D8A9EDE84D27F3D4/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-eug352_t/.seedpass/D8A9EDE84D27F3D4/backups/entries_db_backup_1771874315.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: 9&NIx7D2@r`i + +Press Enter to continue... +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 9&NIx7D2@r`i +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: D8A9EDE84D27F3D4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-eug352_t/.seedpass/D8A9EDE84D27F3D4/backups/entries_db_backup_1771874316.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=DXCXZHH5NSR322BLNNUNARKDR3NMZ2KF&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€β–€β–ˆβ–€β–€β–€β–ˆβ–€β–€β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆΒ β–ˆΒ Β β–„β–ˆΒ β–ˆβ–„β–ˆβ–„β–ˆΒ β–€β–€β–„β–€Β Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€β–„Β β–€β–€Β β–ˆβ–ˆΒ β–ˆΒ Β Β β–„Β β–„β–ˆβ–„β–€β–„Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„β–€β–ˆΒ β–„β–€β–„Β β–ˆΒ β–ˆΒ β–ˆΒ β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–€β–€β–€β–€β–€β–€Β Β β–„Β β–„β–„β–ˆβ–„β–ˆβ–€β–„β–€β–€β–€β–ˆβ–ˆβ–„β–ˆβ–„Β β–€β–ˆβ–ˆβ–€β–ˆβ–€β–€β–€β–ˆ +β–ˆβ–„Β β–„Β Β β–„β–€Β β–ˆΒ β–€β–„β–„β–„β–ˆβ–€Β β–ˆΒ β–€β–„β–„β–€β–ˆΒ β–€β–ˆβ–€β–„β–ˆβ–„β–„β–€β–€β–„β–„β–€β–ˆ +β–ˆΒ Β Β Β β–ˆβ–„β–€β–„β–„Β Β β–€Β β–€β–ˆβ–€β–„β–„β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„β–„Β β–€β–€β–€β–„β–€β–„β–„Β β–ˆ +β–ˆβ–„Β Β β–ˆΒ β–„β–€Β β–„Β β–ˆβ–€β–€β–„β–„Β Β β–ˆΒ β–€β–„β–ˆΒ β–„β–ˆβ–€β–„Β β–€β–€β–ˆΒ Β β–€β–€β–„Β β–ˆ +β–ˆβ–€Β β–ˆΒ β–ˆβ–€β–€β–€β–„β–„β–€β–ˆβ–ˆΒ β–€Β β–„β–€Β β–ˆβ–ˆβ–ˆβ–ˆβ–„β–ˆβ–€Β β–€Β β–€Β β–ˆβ–€Β Β β–„β–€β–ˆ +β–ˆΒ Β β–€β–„β–„β–„β–€β–ˆΒ Β β–€Β β–„β–ˆβ–€β–ˆβ–€β–ˆΒ Β β–€β–ˆβ–€Β Β β–€β–„β–ˆΒ β–„β–ˆβ–„Β Β Β β–ˆβ–€β–ˆ +β–ˆβ–€β–„Β β–ˆβ–ˆΒ β–€β–ˆβ–ˆβ–„β–€β–ˆβ–„β–ˆΒ β–„Β β–ˆβ–„β–ˆΒ β–ˆβ–„β–„Β β–„β–€β–ˆβ–„Β β–€β–ˆΒ β–€β–ˆΒ β–ˆβ–ˆ +β–ˆβ–„β–€β–ˆβ–ˆβ–€β–„β–€β–€Β β–€β–„Β Β Β Β β–€β–€β–„β–„β–„β–ˆβ–ˆβ–„Β β–€β–€Β Β β–ˆΒ β–ˆβ–ˆΒ β–ˆβ–„Β Β β–ˆ +β–ˆβ–„β–„β–€β–„β–€β–ˆβ–€β–€Β β–€β–ˆβ–€β–„β–€β–„β–€β–„β–€β–„β–€β–„β–ˆΒ Β β–ˆβ–„β–€β–€β–ˆβ–„Β β–ˆβ–„β–„β–„β–„Β β–ˆ +β–ˆΒ β–€Β β–€β–€Β β–€β–„β–ˆΒ Β β–ˆΒ β–ˆβ–ˆβ–€β–ˆβ–€β–„β–ˆβ–„β–€β–„Β β–„β–ˆβ–€β–€Β β–€Β β–ˆΒ β–€β–ˆβ–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–„β–€β–€β–„Β β–„Β β–ˆβ–ˆβ–ˆβ–„β–€β–„β–„β–€β–ˆβ–€β–ˆβ–€Β β–ˆβ–€β–„β–„Β β–€Β Β Β β–€β–€Β Β β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ β–€Β β–ˆβ–ˆΒ β–€β–ˆβ–„Β β–€Β Β β–€β–„β–€β–ˆΒ Β β–„Β β–ˆβ–€β–ˆΒ β–„Β Β β–„β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆΒ β–€β–ˆβ–€β–„β–ˆβ–€β–€β–€β–ˆβ–€β–€Β β–„β–€β–€β–ˆβ–„β–ˆΒ Β β–€β–€β–€Β β–„β–ˆβ–„β–„β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–„β–„Β β–„β–€Β β–€β–ˆβ–ˆΒ β–€Β β–„β–ˆβ–ˆβ–„Β β–ˆβ–ˆβ–„β–€Β β–„β–€β–€β–ˆβ–€β–€β–€β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–€Β Β Β β–€Β β–„β–€β–ˆβ–„Β β–ˆβ–ˆβ–ˆΒ β–€β–ˆβ–€β–€β–„β–„β–„β–ˆβ–€β–€β–ˆβ–„Β β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: DXCXZHH5NSR322BLNNUNARKDR3NMZ2KF + +Press Enter to continue... +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 203226 [####----------------] 24s + +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-eug352_t/.seedpass/D8A9EDE84D27F3D4/backups/entries_db_backup_1771874316.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 9&NIx7D2@r`i +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: D8A9EDE84D27F3D4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-eug352_t/.seedpass/D8A9EDE84D27F3D4/backups/entries_db_backup_1771874316.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: D8A9EDE84D27F3D4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-eug352_t/.seedpass/D8A9EDE84D27F3D4/backups/entries_db_backup_1771874316.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 203226 [#####---------------] 22s + +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 2 + password: 1 + totp: 1 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-eug352_t/.seedpass/D8A9EDE84D27F3D4/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: D8A9EDE84D27F3D4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191838Z/report.json b/artifacts/agent_tui_test/20260223T191838Z/report.json new file mode 100644 index 00000000..28ba6c42 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191838Z/report.json @@ -0,0 +1,40 @@ +{ + "timestamp_utc": "20260223T191838Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-dbh0_bk2", + "duration_sec": 5.387, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 5.320108566000272, + "detail": null + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "add_password_quick": true, + "invalid_length_validation": true, + "add_totp": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_codes_view": true, + "settings_stats": true, + "graceful_exit": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191838Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191838Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191838Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T191838Z/transcript.clean.txt new file mode 100644 index 00000000..9ce48eba --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191838Z/transcript.clean.txt @@ -0,0 +1,523 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +deer name demise matter reason knee coconut hundred bless merit scorpion alarm +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-dbh0_bk2/.seedpass/05E261D59626F53A/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 05E261D59626F53A > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-dbh0_bk2/.seedpass/05E261D59626F53A/backups/entries_db_backup_1771874321.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: u4p^N0Ex1=^S + +Press Enter to continue... +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 05E261D59626F53A > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: u4p^N0Ex1=^S +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 05E261D59626F53A > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 05E261D59626F53A > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 05E261D59626F53A > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 05E261D59626F53A > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 05E261D59626F53A > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 05E261D59626F53A > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 05E261D59626F53A > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-dbh0_bk2/.seedpass/05E261D59626F53A/backups/entries_db_backup_1771874321.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=KM4TENWCNRVWX2HKXUASVM4THLGRK5HJ&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–€β–€β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆβ–€β–ˆβ–€β–„β–€Β β–€β–ˆβ–€Β β–€Β β–€β–€Β β–ˆβ–„Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–ˆβ–€β–„Β β–€β–„Β β–„Β β–€β–„β–€β–€Β β–€β–„Β Β β–€Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–„β–€β–„Β β–„β–€β–ˆβ–€β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€Β β–€Β Β β–ˆβ–„Β β–ˆΒ β–„Β β–ˆβ–„β–„β–„β–„β–„β–ˆΒ β–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–ˆΒ β–€β–„β–„β–ˆβ–€β–„β–€β–€Β β–ˆβ–„β–„Β β–€β–ˆβ–ˆβ–„Β Β β–„β–„β–ˆβ–„Β β–€β–€β–€β–„β–€β–„β–ˆβ–€Β β–„β–ˆβ–ˆ +β–ˆβ–€β–„β–€β–„Β β–ˆβ–€β–„β–ˆβ–ˆβ–ˆΒ β–ˆβ–ˆΒ β–„β–„β–ˆΒ β–ˆβ–ˆΒ β–€β–€β–„β–ˆβ–„β–ˆβ–„β–ˆΒ β–€β–„β–„β–ˆΒ β–€β–ˆ +β–ˆβ–ˆβ–ˆβ–€β–€Β β–€β–€β–€β–„β–€Β β–ˆβ–€β–ˆΒ Β Β β–€β–ˆβ–ˆβ–„β–ˆΒ Β β–€β–ˆβ–„Β β–€β–€β–ˆβ–„Β β–€β–€β–„Β β–ˆ +β–ˆΒ β–„β–€β–€β–„β–€β–€β–€Β Β β–€β–„β–„Β β–„β–ˆβ–„β–„β–€β–€β–„Β β–ˆβ–€β–„β–ˆβ–€β–„β–„β–ˆβ–€β–€β–„β–ˆΒ β–ˆΒ β–ˆ +β–ˆβ–€β–€β–€β–„β–„β–„β–€β–„β–„Β β–€β–ˆΒ Β β–ˆβ–ˆΒ β–„β–„β–ˆβ–„β–ˆΒ β–€β–„β–„β–€β–ˆβ–€β–ˆβ–€β–ˆβ–„β–„Β β–„β–ˆβ–ˆ +β–ˆβ–ˆβ–€β–ˆβ–„Β Β β–€β–ˆΒ Β β–ˆβ–ˆΒ β–€β–ˆβ–€β–ˆβ–„β–€β–„β–ˆΒ β–€β–ˆβ–€β–ˆβ–„Β Β β–€Β β–„β–ˆβ–ˆβ–€β–€β–„β–ˆ +β–ˆβ–€β–„Β β–€β–„β–€β–€β–„Β β–€β–„β–ˆβ–ˆβ–ˆβ–€β–€Β β–„β–€β–ˆβ–€β–ˆβ–€Β β–ˆΒ β–„Β Β β–„β–ˆβ–„β–„β–ˆβ–€β–„β–ˆβ–ˆ +β–ˆβ–ˆΒ β–€β–„β–€β–„β–€β–ˆβ–€β–€β–ˆΒ β–ˆβ–€β–€β–ˆβ–€β–ˆβ–ˆβ–€β–„Β β–„β–„β–„β–„β–€β–„β–€β–€β–ˆβ–€β–„β–€Β β–€Β β–ˆ +β–ˆβ–„β–ˆβ–„β–€β–ˆβ–€β–€β–ˆβ–ˆβ–„β–€β–€Β Β β–€β–€β–ˆβ–„β–„β–€β–„β–€β–„β–„Β β–€β–€β–€Β β–„β–„β–„Β β–ˆβ–„β–ˆβ–ˆβ–ˆ +β–ˆβ–€β–€β–€β–„β–„β–„β–€Β Β β–ˆβ–€β–ˆΒ β–ˆΒ β–„Β Β β–€β–€Β Β β–€β–ˆβ–„β–ˆβ–ˆβ–ˆΒ Β β–€Β β–€Β Β β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ Β β–ˆβ–ˆβ–€β–„β–€β–ˆΒ β–€β–„β–ˆβ–ˆβ–€β–ˆΒ β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ β–„β–€β–€β–ˆβ–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–„β–„β–„β–€β–„β–„β–ˆβ–ˆβ–„Β Β β–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–€β–€β–€Β β–€Β β–ˆβ–„β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆβ–ˆΒ β–„β–€β–„β–€β–ˆΒ β–„β–ˆβ–€Β β–ˆΒ β–„β–„β–„β–€β–„β–„Β Β Β β–ˆβ–ˆβ–„β–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–ˆΒ Β β–ˆΒ β–„β–€β–€Β β–€Β β–ˆΒ β–€β–„Β β–ˆβ–€Β β–€β–ˆβ–ˆβ–ˆβ–€β–€β–ˆΒ β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: KM4TENWCNRVWX2HKXUASVM4THLGRK5HJ + +Press Enter to continue... +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 05E261D59626F53A > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 05E261D59626F53A > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 716388 [#######-------------] 19s + +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 05E261D59626F53A > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-dbh0_bk2/.seedpass/05E261D59626F53A/backups/entries_db_backup_1771874321.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 05E261D59626F53A > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: u4p^N0Ex1=^S +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 05E261D59626F53A > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-dbh0_bk2/.seedpass/05E261D59626F53A/backups/entries_db_backup_1771874322.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 05E261D59626F53A > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 05E261D59626F53A > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-dbh0_bk2/.seedpass/05E261D59626F53A/backups/entries_db_backup_1771874322.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 05E261D59626F53A > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 05E261D59626F53A > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 716388 [#########-----------] 16s + +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 2 + password: 1 + totp: 1 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-dbh0_bk2/.seedpass/05E261D59626F53A/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T191838Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T191838Z/transcript.raw.txt new file mode 100644 index 00000000..9b628249 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191838Z/transcript.raw.txt @@ -0,0 +1,524 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +deer name demise matter reason knee coconut hundred bless merit scorpion alarm +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-dbh0_bk2/.seedpass/05E261D59626F53A/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 05E261D59626F53A > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-dbh0_bk2/.seedpass/05E261D59626F53A/backups/entries_db_backup_1771874321.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: u4p^N0Ex1=^S + +Press Enter to continue... +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 05E261D59626F53A > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: u4p^N0Ex1=^S +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 05E261D59626F53A > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 05E261D59626F53A > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 05E261D59626F53A > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 05E261D59626F53A > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 05E261D59626F53A > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 05E261D59626F53A > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 05E261D59626F53A > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-dbh0_bk2/.seedpass/05E261D59626F53A/backups/entries_db_backup_1771874321.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=KM4TENWCNRVWX2HKXUASVM4THLGRK5HJ&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–€β–€β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆβ–€β–ˆβ–€β–„β–€Β β–€β–ˆβ–€Β β–€Β β–€β–€Β β–ˆβ–„Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–ˆβ–€β–„Β β–€β–„Β β–„Β β–€β–„β–€β–€Β β–€β–„Β Β β–€Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–„β–€β–„Β β–„β–€β–ˆβ–€β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€Β β–€Β Β β–ˆβ–„Β β–ˆΒ β–„Β β–ˆβ–„β–„β–„β–„β–„β–ˆΒ β–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–ˆΒ β–€β–„β–„β–ˆβ–€β–„β–€β–€Β β–ˆβ–„β–„Β β–€β–ˆβ–ˆβ–„Β Β β–„β–„β–ˆβ–„Β β–€β–€β–€β–„β–€β–„β–ˆβ–€Β β–„β–ˆβ–ˆ +β–ˆβ–€β–„β–€β–„Β β–ˆβ–€β–„β–ˆβ–ˆβ–ˆΒ β–ˆβ–ˆΒ β–„β–„β–ˆΒ β–ˆβ–ˆΒ β–€β–€β–„β–ˆβ–„β–ˆβ–„β–ˆΒ β–€β–„β–„β–ˆΒ β–€β–ˆ +β–ˆβ–ˆβ–ˆβ–€β–€Β β–€β–€β–€β–„β–€Β β–ˆβ–€β–ˆΒ Β Β β–€β–ˆβ–ˆβ–„β–ˆΒ Β β–€β–ˆβ–„Β β–€β–€β–ˆβ–„Β β–€β–€β–„Β β–ˆ +β–ˆΒ β–„β–€β–€β–„β–€β–€β–€Β Β β–€β–„β–„Β β–„β–ˆβ–„β–„β–€β–€β–„Β β–ˆβ–€β–„β–ˆβ–€β–„β–„β–ˆβ–€β–€β–„β–ˆΒ β–ˆΒ β–ˆ +β–ˆβ–€β–€β–€β–„β–„β–„β–€β–„β–„Β β–€β–ˆΒ Β β–ˆβ–ˆΒ β–„β–„β–ˆβ–„β–ˆΒ β–€β–„β–„β–€β–ˆβ–€β–ˆβ–€β–ˆβ–„β–„Β β–„β–ˆβ–ˆ +β–ˆβ–ˆβ–€β–ˆβ–„Β Β β–€β–ˆΒ Β β–ˆβ–ˆΒ β–€β–ˆβ–€β–ˆβ–„β–€β–„β–ˆΒ β–€β–ˆβ–€β–ˆβ–„Β Β β–€Β β–„β–ˆβ–ˆβ–€β–€β–„β–ˆ +β–ˆβ–€β–„Β β–€β–„β–€β–€β–„Β β–€β–„β–ˆβ–ˆβ–ˆβ–€β–€Β β–„β–€β–ˆβ–€β–ˆβ–€Β β–ˆΒ β–„Β Β β–„β–ˆβ–„β–„β–ˆβ–€β–„β–ˆβ–ˆ +β–ˆβ–ˆΒ β–€β–„β–€β–„β–€β–ˆβ–€β–€β–ˆΒ β–ˆβ–€β–€β–ˆβ–€β–ˆβ–ˆβ–€β–„Β β–„β–„β–„β–„β–€β–„β–€β–€β–ˆβ–€β–„β–€Β β–€Β β–ˆ +β–ˆβ–„β–ˆβ–„β–€β–ˆβ–€β–€β–ˆβ–ˆβ–„β–€β–€Β Β β–€β–€β–ˆβ–„β–„β–€β–„β–€β–„β–„Β β–€β–€β–€Β β–„β–„β–„Β β–ˆβ–„β–ˆβ–ˆβ–ˆ +β–ˆβ–€β–€β–€β–„β–„β–„β–€Β Β β–ˆβ–€β–ˆΒ β–ˆΒ β–„Β Β β–€β–€Β Β β–€β–ˆβ–„β–ˆβ–ˆβ–ˆΒ Β β–€Β β–€Β Β β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ Β β–ˆβ–ˆβ–€β–„β–€β–ˆΒ β–€β–„β–ˆβ–ˆβ–€β–ˆΒ β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ β–„β–€β–€β–ˆβ–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–„β–„β–„β–€β–„β–„β–ˆβ–ˆβ–„Β Β β–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–€β–€β–€Β β–€Β β–ˆβ–„β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆβ–ˆΒ β–„β–€β–„β–€β–ˆΒ β–„β–ˆβ–€Β β–ˆΒ β–„β–„β–„β–€β–„β–„Β Β Β β–ˆβ–ˆβ–„β–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–ˆΒ Β β–ˆΒ β–„β–€β–€Β β–€Β β–ˆΒ β–€β–„Β β–ˆβ–€Β β–€β–ˆβ–ˆβ–ˆβ–€β–€β–ˆΒ β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: KM4TENWCNRVWX2HKXUASVM4THLGRK5HJ + +Press Enter to continue... +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 05E261D59626F53A > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 05E261D59626F53A > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 716388 [#######-------------] 19s + +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 05E261D59626F53A > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-dbh0_bk2/.seedpass/05E261D59626F53A/backups/entries_db_backup_1771874321.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 05E261D59626F53A > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: u4p^N0Ex1=^S +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 05E261D59626F53A > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-dbh0_bk2/.seedpass/05E261D59626F53A/backups/entries_db_backup_1771874322.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 05E261D59626F53A > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 05E261D59626F53A > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-dbh0_bk2/.seedpass/05E261D59626F53A/backups/entries_db_backup_1771874322.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 05E261D59626F53A > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 05E261D59626F53A > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 716388 [#########-----------] 16s + +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 2 + password: 1 + totp: 1 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-dbh0_bk2/.seedpass/05E261D59626F53A/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 05E261D59626F53A > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191844Z/report.json b/artifacts/agent_tui_test/20260223T191844Z/report.json new file mode 100644 index 00000000..f46b4a48 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191844Z/report.json @@ -0,0 +1,40 @@ +{ + "timestamp_utc": "20260223T191844Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-vdlj2ovh", + "duration_sec": 5.411, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 5.337740708000638, + "detail": null + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "add_password_quick": true, + "invalid_length_validation": true, + "add_totp": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_codes_view": true, + "settings_stats": true, + "graceful_exit": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191844Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T191844Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T191844Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T191844Z/transcript.clean.txt new file mode 100644 index 00000000..446c20a1 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191844Z/transcript.clean.txt @@ -0,0 +1,523 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +exercise shaft wine sense caution report unfair chat better suggest dragon topple +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-vdlj2ovh/.seedpass/8A1F3BBFE0C46CAC/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vdlj2ovh/.seedpass/8A1F3BBFE0C46CAC/backups/entries_db_backup_1771874326.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: ~ceBZCp^689_ + +Press Enter to continue... +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: ~ceBZCp^689_ +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 8A1F3BBFE0C46CAC > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vdlj2ovh/.seedpass/8A1F3BBFE0C46CAC/backups/entries_db_backup_1771874327.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=Z3CJASCUUJTV6UAT7742X6BQU4JSN6B3&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–ˆβ–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–€β–€β–€β–„Β β–„β–ˆβ–„β–ˆβ–„Β β–€Β β–ˆβ–„β–€β–ˆβ–€β–€β–„β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–ˆΒ Β β–€β–„β–€β–ˆβ–€β–€Β Β β–ˆβ–ˆβ–€Β β–ˆβ–„β–„β–ˆβ–€β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–„Β β–ˆΒ β–ˆβ–€β–ˆβ–€β–„Β β–ˆΒ β–„β–€β–ˆΒ β–„β–€β–„Β β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–„Β β–ˆβ–ˆβ–ˆβ–ˆβ–ˆΒ β–€β–ˆβ–€β–€Β Β β–ˆβ–ˆβ–ˆβ–€β–„β–ˆβ–„β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–ˆ +β–ˆβ–ˆβ–ˆΒ β–€β–„β–„β–€Β β–€β–ˆβ–€Β β–„β–ˆΒ Β β–€β–€β–„β–€β–€β–ˆΒ β–€Β β–€Β Β β–ˆΒ β–„β–„β–„β–€Β Β β–€β–ˆ +β–ˆΒ β–„β–ˆβ–ˆβ–„Β β–€Β β–€β–„β–ˆβ–ˆβ–„β–€β–€Β β–€β–€Β β–€β–€β–„Β Β β–ˆβ–€Β β–€β–ˆβ–„β–€β–„β–€β–ˆΒ β–€Β β–ˆ +β–ˆβ–„β–„Β β–€β–„β–€β–€β–ˆβ–ˆΒ β–„Β β–ˆβ–€β–€β–„β–€β–ˆΒ β–„β–ˆβ–„β–„β–„β–ˆβ–„β–ˆβ–€β–ˆβ–€β–€β–ˆβ–€Β β–ˆβ–ˆΒ β–ˆ +β–ˆΒ β–€β–ˆβ–ˆΒ β–ˆβ–€β–€β–ˆβ–„β–„β–€β–„Β Β Β β–„β–ˆΒ β–ˆΒ β–„β–„Β β–ˆβ–€β–ˆΒ β–€β–ˆβ–„β–ˆβ–„β–€β–€β–„β–ˆβ–ˆ +β–ˆβ–„β–€Β Β β–ˆβ–€β–€β–„β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆΒ β–„β–„Β Β β–„β–ˆβ–„β–„β–ˆΒ β–ˆΒ β–„β–€β–€β–ˆβ–€β–ˆβ–„β–„Β β–€β–ˆ +β–ˆβ–€β–„β–€Β β–ˆβ–€β–€Β β–ˆβ–€Β β–„β–ˆβ–„β–ˆβ–ˆΒ β–ˆβ–„Β β–€β–„Β β–„Β β–€Β β–ˆΒ Β β–€Β Β β–€β–ˆΒ β–ˆβ–ˆ +β–ˆβ–„β–€β–„β–ˆβ–ˆβ–€β–€β–ˆβ–€Β β–ˆβ–€Β β–€β–ˆΒ Β Β β–„β–„Β β–„β–ˆβ–„β–€β–€β–ˆβ–€β–„Β β–€β–ˆβ–ˆβ–„β–ˆβ–€Β β–ˆ +β–ˆβ–€Β β–€Β β–€β–€β–€β–ˆβ–„β–„β–ˆβ–„Β β–ˆβ–€β–„Β β–„β–„β–ˆΒ β–„β–ˆβ–ˆβ–ˆΒ β–ˆΒ β–„β–€β–ˆβ–ˆβ–„β–ˆβ–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆβ–„β–€Β β–ˆβ–€β–€β–„β–„β–€β–ˆβ–€Β β–€Β β–€β–ˆβ–„Β β–ˆΒ Β Β β–„Β Β Β β–„β–€β–€Β β–€Β β–€β–€β–€β–ˆ +β–ˆΒ β–ˆΒ β–„β–„Β β–€β–ˆβ–€β–ˆΒ Β β–€β–„β–„Β β–€Β β–ˆβ–ˆβ–„β–„Β β–„β–ˆβ–€β–€Β Β β–€Β Β β–€β–„β–ˆβ–„Β β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–„β–„β–ˆβ–€β–€β–ˆΒ Β β–€β–ˆΒ β–„β–„Β β–€β–„β–ˆβ–„β–„β–ˆΒ β–ˆβ–€β–ˆΒ β–ˆβ–ˆΒ β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆΒ β–„Β β–„β–€β–ˆβ–€β–„β–ˆβ–ˆβ–€β–„β–€β–ˆβ–ˆβ–€β–ˆβ–€β–„β–€Β β–€β–€β–€Β β–ˆβ–€β–ˆβ–ˆβ–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–ˆβ–€β–ˆβ–€β–„β–„β–„β–„β–€β–ˆΒ β–€β–„β–„Β Β β–ˆΒ β–ˆΒ β–„β–„β–€β–„β–€β–€β–ˆβ–€β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€Β β–ˆβ–ˆβ–ˆβ–„β–ˆβ–ˆΒ β–€β–ˆβ–„β–€β–„Β β–ˆβ–€β–€β–ˆΒ β–ˆΒ β–„β–€β–ˆβ–ˆβ–„β–€Β β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: Z3CJASCUUJTV6UAT7742X6BQU4JSN6B3 + +Press Enter to continue... +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 696921 [###########---------] 13s + +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vdlj2ovh/.seedpass/8A1F3BBFE0C46CAC/backups/entries_db_backup_1771874327.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: ~ceBZCp^689_ +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 8A1F3BBFE0C46CAC > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vdlj2ovh/.seedpass/8A1F3BBFE0C46CAC/backups/entries_db_backup_1771874327.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 8A1F3BBFE0C46CAC > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vdlj2ovh/.seedpass/8A1F3BBFE0C46CAC/backups/entries_db_backup_1771874327.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 696921 [############--------] 11s + +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 2 + password: 1 + totp: 1 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-vdlj2ovh/.seedpass/8A1F3BBFE0C46CAC/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T191844Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T191844Z/transcript.raw.txt new file mode 100644 index 00000000..a0f97247 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T191844Z/transcript.raw.txt @@ -0,0 +1,524 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +exercise shaft wine sense caution report unfair chat better suggest dragon topple +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-vdlj2ovh/.seedpass/8A1F3BBFE0C46CAC/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vdlj2ovh/.seedpass/8A1F3BBFE0C46CAC/backups/entries_db_backup_1771874326.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: ~ceBZCp^689_ + +Press Enter to continue... +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: ~ceBZCp^689_ +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 8A1F3BBFE0C46CAC > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vdlj2ovh/.seedpass/8A1F3BBFE0C46CAC/backups/entries_db_backup_1771874327.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=Z3CJASCUUJTV6UAT7742X6BQU4JSN6B3&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–ˆβ–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–€β–€β–€β–„Β β–„β–ˆβ–„β–ˆβ–„Β β–€Β β–ˆβ–„β–€β–ˆβ–€β–€β–„β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–ˆΒ Β β–€β–„β–€β–ˆβ–€β–€Β Β β–ˆβ–ˆβ–€Β β–ˆβ–„β–„β–ˆβ–€β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–„Β β–ˆΒ β–ˆβ–€β–ˆβ–€β–„Β β–ˆΒ β–„β–€β–ˆΒ β–„β–€β–„Β β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–„Β β–ˆβ–ˆβ–ˆβ–ˆβ–ˆΒ β–€β–ˆβ–€β–€Β Β β–ˆβ–ˆβ–ˆβ–€β–„β–ˆβ–„β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–ˆ +β–ˆβ–ˆβ–ˆΒ β–€β–„β–„β–€Β β–€β–ˆβ–€Β β–„β–ˆΒ Β β–€β–€β–„β–€β–€β–ˆΒ β–€Β β–€Β Β β–ˆΒ β–„β–„β–„β–€Β Β β–€β–ˆ +β–ˆΒ β–„β–ˆβ–ˆβ–„Β β–€Β β–€β–„β–ˆβ–ˆβ–„β–€β–€Β β–€β–€Β β–€β–€β–„Β Β β–ˆβ–€Β β–€β–ˆβ–„β–€β–„β–€β–ˆΒ β–€Β β–ˆ +β–ˆβ–„β–„Β β–€β–„β–€β–€β–ˆβ–ˆΒ β–„Β β–ˆβ–€β–€β–„β–€β–ˆΒ β–„β–ˆβ–„β–„β–„β–ˆβ–„β–ˆβ–€β–ˆβ–€β–€β–ˆβ–€Β β–ˆβ–ˆΒ β–ˆ +β–ˆΒ β–€β–ˆβ–ˆΒ β–ˆβ–€β–€β–ˆβ–„β–„β–€β–„Β Β Β β–„β–ˆΒ β–ˆΒ β–„β–„Β β–ˆβ–€β–ˆΒ β–€β–ˆβ–„β–ˆβ–„β–€β–€β–„β–ˆβ–ˆ +β–ˆβ–„β–€Β Β β–ˆβ–€β–€β–„β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆΒ β–„β–„Β Β β–„β–ˆβ–„β–„β–ˆΒ β–ˆΒ β–„β–€β–€β–ˆβ–€β–ˆβ–„β–„Β β–€β–ˆ +β–ˆβ–€β–„β–€Β β–ˆβ–€β–€Β β–ˆβ–€Β β–„β–ˆβ–„β–ˆβ–ˆΒ β–ˆβ–„Β β–€β–„Β β–„Β β–€Β β–ˆΒ Β β–€Β Β β–€β–ˆΒ β–ˆβ–ˆ +β–ˆβ–„β–€β–„β–ˆβ–ˆβ–€β–€β–ˆβ–€Β β–ˆβ–€Β β–€β–ˆΒ Β Β β–„β–„Β β–„β–ˆβ–„β–€β–€β–ˆβ–€β–„Β β–€β–ˆβ–ˆβ–„β–ˆβ–€Β β–ˆ +β–ˆβ–€Β β–€Β β–€β–€β–€β–ˆβ–„β–„β–ˆβ–„Β β–ˆβ–€β–„Β β–„β–„β–ˆΒ β–„β–ˆβ–ˆβ–ˆΒ β–ˆΒ β–„β–€β–ˆβ–ˆβ–„β–ˆβ–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆβ–„β–€Β β–ˆβ–€β–€β–„β–„β–€β–ˆβ–€Β β–€Β β–€β–ˆβ–„Β β–ˆΒ Β Β β–„Β Β Β β–„β–€β–€Β β–€Β β–€β–€β–€β–ˆ +β–ˆΒ β–ˆΒ β–„β–„Β β–€β–ˆβ–€β–ˆΒ Β β–€β–„β–„Β β–€Β β–ˆβ–ˆβ–„β–„Β β–„β–ˆβ–€β–€Β Β β–€Β Β β–€β–„β–ˆβ–„Β β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–„β–„β–ˆβ–€β–€β–ˆΒ Β β–€β–ˆΒ β–„β–„Β β–€β–„β–ˆβ–„β–„β–ˆΒ β–ˆβ–€β–ˆΒ β–ˆβ–ˆΒ β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆΒ β–„Β β–„β–€β–ˆβ–€β–„β–ˆβ–ˆβ–€β–„β–€β–ˆβ–ˆβ–€β–ˆβ–€β–„β–€Β β–€β–€β–€Β β–ˆβ–€β–ˆβ–ˆβ–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–ˆβ–€β–ˆβ–€β–„β–„β–„β–„β–€β–ˆΒ β–€β–„β–„Β Β β–ˆΒ β–ˆΒ β–„β–„β–€β–„β–€β–€β–ˆβ–€β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€Β β–ˆβ–ˆβ–ˆβ–„β–ˆβ–ˆΒ β–€β–ˆβ–„β–€β–„Β β–ˆβ–€β–€β–ˆΒ β–ˆΒ β–„β–€β–ˆβ–ˆβ–„β–€Β β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: Z3CJASCUUJTV6UAT7742X6BQU4JSN6B3 + +Press Enter to continue... +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 696921 [###########---------] 13s + +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vdlj2ovh/.seedpass/8A1F3BBFE0C46CAC/backups/entries_db_backup_1771874327.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: ~ceBZCp^689_ +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 8A1F3BBFE0C46CAC > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vdlj2ovh/.seedpass/8A1F3BBFE0C46CAC/backups/entries_db_backup_1771874327.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 8A1F3BBFE0C46CAC > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-vdlj2ovh/.seedpass/8A1F3BBFE0C46CAC/backups/entries_db_backup_1771874327.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 696921 [############--------] 11s + +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 2 + password: 1 + totp: 1 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-vdlj2ovh/.seedpass/8A1F3BBFE0C46CAC/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 8A1F3BBFE0C46CAC > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192111Z/report.json b/artifacts/agent_tui_test/20260223T192111Z/report.json new file mode 100644 index 00000000..d03a320c --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192111Z/report.json @@ -0,0 +1,43 @@ +{ + "timestamp_utc": "20260223T192111Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-y1ktay8h", + "duration_sec": 30.524, + "seedpass_exit_code": -9, + "status": "failed", + "failure": "Timed out waiting for pattern: 'Select entry type or press Enter to go back:'\nRecent output:\nending deltas: 0\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\nPress Enter to continue.\r\n\r\n\u001bcSeed Profile: B88A591A791791B2 > Main Menu\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 99\r\nInvalid choice. Please select a valid option.1\r\n\r\n\u001bcSeed Profile: B88A591A791791B2 > Main Menu\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: \u001bcSeed Profile: Main Menu > Add Entry\r\n\r\n\r\nAdd Entry:\r\n1. Password\r\n2. 2FA (TOTP)\r\n3. SSH Key\r\n4. Seed Phrase\r\n5. Nostr Key Pair\r\n6. PGP Key\r\n7. Key/Value\r\n8. Managed Account\r\nSelect entry type or press Enter to go back: ", + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "failed", + "duration_sec": 29.004274161001376, + "detail": "Timed out waiting for pattern: 'Select entry type or press Enter to go back:'\nRecent output:\nending deltas: 0\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\nPress Enter to continue.\r\n\r\n\u001bcSeed Profile: B88A591A791791B2 > Main Menu\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 99\r\nInvalid choice. Please select a valid option.1\r\n\r\n\u001bcSeed Profile: B88A591A791791B2 > Main Menu\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: \u001bcSeed Profile: Main Menu > Add Entry\r\n\r\n\r\nAdd Entry:\r\n1. Password\r\n2. 2FA (TOTP)\r\n3. SSH Key\r\n4. Seed Phrase\r\n5. Nostr Key Pair\r\n6. PGP Key\r\n7. Key/Value\r\n8. Managed Account\r\nSelect entry type or press Enter to go back: " + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "invalid_input_resilience": false, + "add_password_quick": false, + "invalid_length_validation": false, + "add_totp": false, + "add_all_entry_types": false, + "retrieve_entry": false, + "search_entries": false, + "list_entries": false, + "modify_entry": false, + "archive_restore": false, + "totp_codes_view": false, + "settings_toggles_lock_unlock": false, + "settings_stats": false, + "graceful_exit": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192111Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192111Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192111Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T192111Z/transcript.clean.txt new file mode 100644 index 00000000..ec042749 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192111Z/transcript.clean.txt @@ -0,0 +1,81 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +hedgehog advice sing armed subway allow educate more pyramid exist victory chase +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-y1ktay8h/.seedpass/B88A591A791791B2/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: B88A591A791791B2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option.1 + +cSeed Profile: B88A591A791791B2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192111Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T192111Z/transcript.raw.txt new file mode 100644 index 00000000..ec042749 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192111Z/transcript.raw.txt @@ -0,0 +1,81 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +hedgehog advice sing armed subway allow educate more pyramid exist victory chase +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-y1ktay8h/.seedpass/B88A591A791791B2/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: B88A591A791791B2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option.1 + +cSeed Profile: B88A591A791791B2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192218Z/report.json b/artifacts/agent_tui_test/20260223T192218Z/report.json new file mode 100644 index 00000000..0f8741b5 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192218Z/report.json @@ -0,0 +1,43 @@ +{ + "timestamp_utc": "20260223T192218Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-_sbf6mb3", + "duration_sec": 29.126, + "seedpass_exit_code": -9, + "status": "failed", + "failure": "Timed out waiting for pattern: 'Enter your choice \\\\(1-8\\\\) or press Enter to exit:'\nRecent output:\n\n managed_account: 0\r\nRelays configured: 3\r\nBackups: 0 (dir: /tmp/seedpass-agent-home-_sbf6mb3/.seedpass/63761474E0259E42/backups)\r\nSchema version: 4\r\nDatabase checksum ok: no\r\nScript checksum ok: yes\r\nSnapshot chunks: 0\r\nPending deltas: 0\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\nPress Enter to continue.\r\n\r\n\u001bcSeed Profile: 63761474E0259E42 > Main Menu\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 99\r\nInvalid choice. Please select a valid option.\r\n\u001bcSeed Profile: 63761474E0259E42 > Main Menu\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: ", + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "failed", + "duration_sec": 27.616451837002387, + "detail": "Timed out waiting for pattern: 'Enter your choice \\\\(1-8\\\\) or press Enter to exit:'\nRecent output:\n\n managed_account: 0\r\nRelays configured: 3\r\nBackups: 0 (dir: /tmp/seedpass-agent-home-_sbf6mb3/.seedpass/63761474E0259E42/backups)\r\nSchema version: 4\r\nDatabase checksum ok: no\r\nScript checksum ok: yes\r\nSnapshot chunks: 0\r\nPending deltas: 0\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\nPress Enter to continue.\r\n\r\n\u001bcSeed Profile: 63761474E0259E42 > Main Menu\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 99\r\nInvalid choice. Please select a valid option.\r\n\u001bcSeed Profile: 63761474E0259E42 > Main Menu\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: " + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "invalid_input_resilience": false, + "add_password_quick": false, + "invalid_length_validation": false, + "add_totp": false, + "add_all_entry_types": false, + "retrieve_entry": false, + "search_entries": false, + "list_entries": false, + "modify_entry": false, + "archive_restore": false, + "totp_codes_view": false, + "settings_toggles_lock_unlock": false, + "settings_stats": false, + "graceful_exit": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192218Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192218Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192218Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T192218Z/transcript.clean.txt new file mode 100644 index 00000000..83266639 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192218Z/transcript.clean.txt @@ -0,0 +1,68 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +normal repeat later poem diesel idle private orchard smoke multiply slogan already +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-_sbf6mb3/.seedpass/63761474E0259E42/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 63761474E0259E42 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 63761474E0259E42 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192218Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T192218Z/transcript.raw.txt new file mode 100644 index 00000000..83266639 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192218Z/transcript.raw.txt @@ -0,0 +1,68 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +normal repeat later poem diesel idle private orchard smoke multiply slogan already +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-_sbf6mb3/.seedpass/63761474E0259E42/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 63761474E0259E42 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 63761474E0259E42 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192300Z/report.json b/artifacts/agent_tui_test/20260223T192300Z/report.json new file mode 100644 index 00000000..c0aac218 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192300Z/report.json @@ -0,0 +1,43 @@ +{ + "timestamp_utc": "20260223T192300Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-u_8mekp7", + "duration_sec": 29.054, + "seedpass_exit_code": -9, + "status": "failed", + "failure": "Timed out waiting for pattern: 'Select entry type or press Enter to go back:'\nRecent output:\nending deltas: 0\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\nPress Enter to continue.\r\n\r\n\u001bcSeed Profile: 91880BEA7C8182BF > Main Menu\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 99\r\nInvalid choice. Please select a valid option.\r\n\u001bcSeed Profile: 91880BEA7C8182BF > Main Menu\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 1\r\n\u001bcSeed Profile: Main Menu > Add Entry\r\n\r\n\r\nAdd Entry:\r\n1. Password\r\n2. 2FA (TOTP)\r\n3. SSH Key\r\n4. Seed Phrase\r\n5. Nostr Key Pair\r\n6. PGP Key\r\n7. Key/Value\r\n8. Managed Account\r\nSelect entry type or press Enter to go back: ", + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "failed", + "duration_sec": 27.54447121299745, + "detail": "Timed out waiting for pattern: 'Select entry type or press Enter to go back:'\nRecent output:\nending deltas: 0\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\nPress Enter to continue.\r\n\r\n\u001bcSeed Profile: 91880BEA7C8182BF > Main Menu\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 99\r\nInvalid choice. Please select a valid option.\r\n\u001bcSeed Profile: 91880BEA7C8182BF > Main Menu\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 1\r\n\u001bcSeed Profile: Main Menu > Add Entry\r\n\r\n\r\nAdd Entry:\r\n1. Password\r\n2. 2FA (TOTP)\r\n3. SSH Key\r\n4. Seed Phrase\r\n5. Nostr Key Pair\r\n6. PGP Key\r\n7. Key/Value\r\n8. Managed Account\r\nSelect entry type or press Enter to go back: " + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "invalid_input_resilience": false, + "add_password_quick": false, + "invalid_length_validation": false, + "add_totp": false, + "add_all_entry_types": false, + "retrieve_entry": false, + "search_entries": false, + "list_entries": false, + "modify_entry": false, + "archive_restore": false, + "totp_codes_view": false, + "settings_toggles_lock_unlock": false, + "settings_stats": false, + "graceful_exit": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192300Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192300Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192300Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T192300Z/transcript.clean.txt new file mode 100644 index 00000000..ae92b306 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192300Z/transcript.clean.txt @@ -0,0 +1,81 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +margin clarify moment alley photo logic current ivory robust seed genre cart +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-u_8mekp7/.seedpass/91880BEA7C8182BF/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 91880BEA7C8182BF > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 91880BEA7C8182BF > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192300Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T192300Z/transcript.raw.txt new file mode 100644 index 00000000..ae92b306 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192300Z/transcript.raw.txt @@ -0,0 +1,81 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +margin clarify moment alley photo logic current ivory robust seed genre cart +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-u_8mekp7/.seedpass/91880BEA7C8182BF/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 91880BEA7C8182BF > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 91880BEA7C8182BF > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192426Z/report.json b/artifacts/agent_tui_test/20260223T192426Z/report.json new file mode 100644 index 00000000..8f2fd261 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192426Z/report.json @@ -0,0 +1,43 @@ +{ + "timestamp_utc": "20260223T192426Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-gct9v3zu", + "duration_sec": 29.254, + "seedpass_exit_code": -9, + "status": "failed", + "failure": "Unable to return to main menu within timeout.", + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "failed", + "duration_sec": 27.74452150200159, + "detail": "Unable to return to main menu within timeout." + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "invalid_input_resilience": true, + "add_password_quick": false, + "invalid_length_validation": false, + "add_totp": false, + "add_all_entry_types": false, + "retrieve_entry": false, + "search_entries": false, + "list_entries": false, + "modify_entry": false, + "archive_restore": false, + "totp_codes_view": false, + "settings_toggles_lock_unlock": false, + "settings_stats": false, + "graceful_exit": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192426Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192426Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192426Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T192426Z/transcript.clean.txt new file mode 100644 index 00000000..a319d2d2 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192426Z/transcript.clean.txt @@ -0,0 +1,128 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +brand service usual hurdle rack notable dragon crystal stage pottery galaxy worth +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-gct9v3zu/.seedpass/B6ED75000E224CC1/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: B6ED75000E224CC1 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: B6ED75000E224CC1 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: B6ED75000E224CC1 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: B6ED75000E224CC1 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: B6ED75000E224CC1 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192426Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T192426Z/transcript.raw.txt new file mode 100644 index 00000000..a319d2d2 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192426Z/transcript.raw.txt @@ -0,0 +1,128 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +brand service usual hurdle rack notable dragon crystal stage pottery galaxy worth +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-gct9v3zu/.seedpass/B6ED75000E224CC1/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: B6ED75000E224CC1 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: B6ED75000E224CC1 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: B6ED75000E224CC1 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: B6ED75000E224CC1 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: B6ED75000E224CC1 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192518Z/report.json b/artifacts/agent_tui_test/20260223T192518Z/report.json new file mode 100644 index 00000000..cdadd695 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192518Z/report.json @@ -0,0 +1,43 @@ +{ + "timestamp_utc": "20260223T192518Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-trotpeut", + "duration_sec": 29.709, + "seedpass_exit_code": -9, + "status": "failed", + "failure": "Unable to return to main menu within timeout.", + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "failed", + "duration_sec": 28.199055735, + "detail": "Unable to return to main menu within timeout." + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "invalid_input_resilience": true, + "add_password_quick": true, + "invalid_length_validation": true, + "add_totp": false, + "add_all_entry_types": false, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": false, + "archive_restore": false, + "totp_codes_view": false, + "settings_toggles_lock_unlock": false, + "settings_stats": false, + "graceful_exit": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192518Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192518Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192518Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T192518Z/transcript.clean.txt new file mode 100644 index 00000000..ef4f206e --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192518Z/transcript.clean.txt @@ -0,0 +1,286 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +dog trouble shop pretty faint follow boss pepper armed claim snack crack +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-trotpeut/.seedpass/987BF66A3B37324F/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 987BF66A3B37324F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 987BF66A3B37324F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 987BF66A3B37324F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 987BF66A3B37324F > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: 987BF66A3B37324F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 987BF66A3B37324F > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-trotpeut/.seedpass/987BF66A3B37324F/backups/entries_db_backup_1771874720.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: [wWR47qs'5_B + +Press Enter to continue... +cSeed Profile: 987BF66A3B37324F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 987BF66A3B37324F > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: [wWR47qs'5_B +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 987BF66A3B37324F > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 987BF66A3B37324F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 987BF66A3B37324F > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 987BF66A3B37324F > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 987BF66A3B37324F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 987BF66A3B37324F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 987BF66A3B37324F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 987BF66A3B37324F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 987BF66A3B37324F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192518Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T192518Z/transcript.raw.txt new file mode 100644 index 00000000..ef4f206e --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192518Z/transcript.raw.txt @@ -0,0 +1,286 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +dog trouble shop pretty faint follow boss pepper armed claim snack crack +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-trotpeut/.seedpass/987BF66A3B37324F/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 987BF66A3B37324F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 987BF66A3B37324F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 987BF66A3B37324F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 987BF66A3B37324F > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: 987BF66A3B37324F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 987BF66A3B37324F > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-trotpeut/.seedpass/987BF66A3B37324F/backups/entries_db_backup_1771874720.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: [wWR47qs'5_B + +Press Enter to continue... +cSeed Profile: 987BF66A3B37324F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 987BF66A3B37324F > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: [wWR47qs'5_B +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 987BF66A3B37324F > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 987BF66A3B37324F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 987BF66A3B37324F > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 987BF66A3B37324F > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 987BF66A3B37324F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 987BF66A3B37324F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 987BF66A3B37324F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 987BF66A3B37324F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 987BF66A3B37324F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192626Z/report.json b/artifacts/agent_tui_test/20260223T192626Z/report.json new file mode 100644 index 00000000..733a3cf8 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192626Z/report.json @@ -0,0 +1,43 @@ +{ + "timestamp_utc": "20260223T192626Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-uk08yxgg", + "duration_sec": 29.608, + "seedpass_exit_code": -9, + "status": "failed", + "failure": "Timed out waiting for pattern: \"Seed entry 'agent-seed' added with ID\"\nRecent output:\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 1\r\n\u001bcSeed Profile: Main Menu > Add Entry\r\n\r\n\r\nAdd Entry:\r\n1. Password\r\n2. 2FA (TOTP)\r\n3. SSH Key\r\n4. Seed Phrase\r\n5. Nostr Key Pair\r\n6. PGP Key\r\n7. Key/Value\r\n8. Managed Account\r\nSelect entry type or press Enter to go back: 4\r\n\u001bcSeed Profile: 19E180BD20F62DB0 > Main Menu > Add Entry > Seed Phrase\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\nLabel: agent-seed\r\nWord count (12 or 24, default 24): 12\r\nNotes (optional): \r\nEnter tags (comma-separated, optional): \r\n[+] Checksum updated successfully.\r\nBackup created successfully at '/tmp/seedpass-agent-home-uk08yxgg/.seedpass/19E180BD20F62DB0/backups/entries_db_backup_1771874789.json.enc'.\r\nWARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y\r\n\r\n[+] Seed entry 'agent-seed' added with ID 3.\r\n\r\nIndex: 3\r\nLabel: agent-seed\r\nSeed Phrase:\r\naerobic because blur flock outside essay media boring wing abstract economy nominee\r\nShow Compact Seed QR? (Y/N): n\r\nPress Enter to continue...", + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "failed", + "duration_sec": 28.097440375000588, + "detail": "Timed out waiting for pattern: \"Seed entry 'agent-seed' added with ID\"\nRecent output:\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 1\r\n\u001bcSeed Profile: Main Menu > Add Entry\r\n\r\n\r\nAdd Entry:\r\n1. Password\r\n2. 2FA (TOTP)\r\n3. SSH Key\r\n4. Seed Phrase\r\n5. Nostr Key Pair\r\n6. PGP Key\r\n7. Key/Value\r\n8. Managed Account\r\nSelect entry type or press Enter to go back: 4\r\n\u001bcSeed Profile: 19E180BD20F62DB0 > Main Menu > Add Entry > Seed Phrase\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\nLabel: agent-seed\r\nWord count (12 or 24, default 24): 12\r\nNotes (optional): \r\nEnter tags (comma-separated, optional): \r\n[+] Checksum updated successfully.\r\nBackup created successfully at '/tmp/seedpass-agent-home-uk08yxgg/.seedpass/19E180BD20F62DB0/backups/entries_db_backup_1771874789.json.enc'.\r\nWARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y\r\n\r\n[+] Seed entry 'agent-seed' added with ID 3.\r\n\r\nIndex: 3\r\nLabel: agent-seed\r\nSeed Phrase:\r\naerobic because blur flock outside essay media boring wing abstract economy nominee\r\nShow Compact Seed QR? (Y/N): n\r\nPress Enter to continue..." + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "invalid_input_resilience": true, + "add_password_quick": true, + "invalid_length_validation": true, + "add_totp": true, + "add_all_entry_types": false, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": false, + "archive_restore": false, + "totp_codes_view": false, + "settings_toggles_lock_unlock": false, + "settings_stats": false, + "graceful_exit": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192626Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192626Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192626Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T192626Z/transcript.clean.txt new file mode 100644 index 00000000..22184a09 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192626Z/transcript.clean.txt @@ -0,0 +1,459 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +seek tissue vault oil poverty bachelor rabbit dawn possible spin gaze alpha +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-uk08yxgg/.seedpass/19E180BD20F62DB0/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +1 +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-uk08yxgg/.seedpass/19E180BD20F62DB0/backups/entries_db_backup_1771874789.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: >leEL55$k9*J + +Press Enter to continue... +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: >leEL55$k9*J +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 19E180BD20F62DB0 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 19E180BD20F62DB0 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 19E180BD20F62DB0 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-uk08yxgg/.seedpass/19E180BD20F62DB0/backups/entries_db_backup_1771874789.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=GMVPYD2UVLW2CBJWYI7FLH2PRF4HJWQS&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–„β–„β–€β–ˆβ–ˆβ–€β–ˆΒ β–„β–„β–ˆβ–€β–ˆβ–„β–€β–ˆΒ β–„β–ˆβ–ˆΒ β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€β–€β–ˆβ–€β–ˆβ–„β–€β–„β–ˆΒ β–€β–€β–€β–€β–ˆβ–€β–„β–ˆΒ β–€β–ˆβ–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„β–€β–„β–€β–ˆβ–€β–„β–€β–ˆβ–€β–„Β β–„β–€β–„β–€β–ˆβ–€β–„Β β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–€β–„β–€Β β–€β–„β–€β–ˆβ–„Β Β β–„β–„β–€β–„β–„Β Β β–€Β β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–ˆ +β–ˆβ–ˆΒ β–€Β β–€Β β–€β–„β–ˆβ–„β–ˆΒ β–„β–„Β β–„β–ˆΒ β–€Β β–ˆβ–€β–„Β β–€Β β–„β–„β–€Β β–ˆβ–€Β Β β–„β–€Β β–ˆ +β–ˆβ–„β–„Β β–€Β β–ˆβ–€β–€Β β–€Β β–€β–„β–ˆβ–€β–„β–€β–€β–ˆΒ β–ˆΒ β–„β–€β–„Β β–„β–ˆβ–€β–ˆΒ β–„β–„Β β–„Β β–€β–ˆ +β–ˆβ–ˆβ–ˆβ–€β–„β–€β–ˆβ–€β–„β–ˆβ–€β–€β–€Β Β β–ˆΒ β–€β–„β–€β–ˆβ–€Β Β β–ˆβ–„β–ˆβ–€β–ˆβ–€Β β–„β–„β–ˆβ–„β–€β–€β–ˆβ–ˆ +β–ˆΒ β–„β–„β–„β–€Β β–€β–„β–ˆβ–ˆΒ β–„Β β–„β–„Β β–€β–„β–€β–„β–„Β Β β–€β–„Β β–€β–„β–ˆΒ β–ˆΒ β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ +β–ˆβ–ˆβ–ˆΒ Β Β β–€β–€Β β–ˆΒ Β β–ˆβ–ˆβ–€β–„Β Β Β β–ˆβ–ˆβ–€Β Β β–„β–€β–„β–„β–ˆβ–„Β β–„β–„β–€β–ˆβ–„β–€Β β–ˆ +β–ˆβ–„Β β–ˆβ–ˆβ–€β–„β–€β–„β–€β–ˆβ–€Β β–„β–€Β β–€β–„β–€β–€β–€β–ˆΒ β–„β–ˆβ–€Β β–„β–„β–„β–€Β Β β–„β–„β–€β–€β–„β–ˆ +β–ˆβ–„β–ˆβ–€β–„Β Β β–€Β β–€β–„Β β–„β–„β–„β–„β–„Β β–€β–„β–ˆβ–„Β β–€β–ˆΒ Β β–€β–ˆΒ β–ˆΒ β–„β–€Β β–€β–„β–ˆβ–ˆ +β–ˆβ–„β–„β–„β–€β–ˆβ–„β–€β–ˆΒ Β β–€β–€β–€β–ˆβ–„Β β–„β–ˆβ–ˆβ–„β–„Β β–€β–„β–„β–€β–€β–„Β β–ˆβ–ˆβ–„Β β–€β–ˆΒ β–€β–ˆ +β–ˆβ–€β–ˆΒ β–€β–€Β β–€β–„Β β–€β–„β–ˆΒ Β β–ˆβ–„β–ˆβ–„β–€β–€β–€β–„β–„β–€β–ˆβ–€β–„β–€β–„Β β–€Β β–ˆβ–ˆΒ Β Β β–ˆ +β–ˆβ–€β–„β–„β–„β–€Β β–€Β β–€β–ˆβ–„Β β–„β–ˆβ–€β–„β–ˆβ–ˆΒ β–„Β Β β–„β–ˆβ–„Β β–ˆΒ Β Β β–€β–€Β β–„β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–„β–ˆβ–„β–€β–€β–„β–€β–ˆβ–€β–„Β β–ˆΒ β–„β–ˆβ–ˆβ–„β–ˆΒ β–€Β β–ˆβ–€β–ˆΒ β–€β–€Β β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–€Β Β β–ˆβ–€β–„Β Β β–„Β β–ˆβ–ˆβ–€β–€Β β–„Β Β β–ˆΒ β–€β–€β–€Β β–€β–ˆβ–ˆβ–„β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€β–„β–€Β Β β–„β–ˆΒ Β β–ˆΒ β–€β–ˆΒ Β β–€β–€β–„β–„β–€β–„β–ˆβ–ˆΒ Β Β Β β–„Β β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„β–€β–„β–ˆβ–ˆβ–ˆβ–€β–„β–„β–€β–ˆβ–ˆΒ β–„β–„Β Β β–€β–€β–ˆβ–„β–„Β β–€β–ˆβ–€Β β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: GMVPYD2UVLW2CBJWYI7FLH2PRF4HJWQS + +Press Enter to continue... +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 19E180BD20F62DB0 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 014014 [###################-] 1s + +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-uk08yxgg/.seedpass/19E180BD20F62DB0/backups/entries_db_backup_1771874789.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAjYlVjkoSe+YR/vZAlFG+srTNhmAjqWAFwLYF0OA53NA= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEILE+T9RaXNvsXYG52RvNOypOXgxgAbblumRyyamnYoQw +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-uk08yxgg/.seedpass/19E180BD20F62DB0/backups/entries_db_backup_1771874789.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +aerobic because blur flock outside essay media boring wing abstract economy nominee +Show Compact Seed QR? (Y/N): n +Press Enter to continue... \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192626Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T192626Z/transcript.raw.txt new file mode 100644 index 00000000..c49ce6e1 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192626Z/transcript.raw.txt @@ -0,0 +1,459 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +seek tissue vault oil poverty bachelor rabbit dawn possible spin gaze alpha +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-uk08yxgg/.seedpass/19E180BD20F62DB0/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +1 +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-uk08yxgg/.seedpass/19E180BD20F62DB0/backups/entries_db_backup_1771874789.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: >leEL55$k9*J + +Press Enter to continue... +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: >leEL55$k9*J +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 19E180BD20F62DB0 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 19E180BD20F62DB0 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 19E180BD20F62DB0 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-uk08yxgg/.seedpass/19E180BD20F62DB0/backups/entries_db_backup_1771874789.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=GMVPYD2UVLW2CBJWYI7FLH2PRF4HJWQS&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–„β–„β–€β–ˆβ–ˆβ–€β–ˆΒ β–„β–„β–ˆβ–€β–ˆβ–„β–€β–ˆΒ β–„β–ˆβ–ˆΒ β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€β–€β–ˆβ–€β–ˆβ–„β–€β–„β–ˆΒ β–€β–€β–€β–€β–ˆβ–€β–„β–ˆΒ β–€β–ˆβ–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„β–€β–„β–€β–ˆβ–€β–„β–€β–ˆβ–€β–„Β β–„β–€β–„β–€β–ˆβ–€β–„Β β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–€β–„β–€Β β–€β–„β–€β–ˆβ–„Β Β β–„β–„β–€β–„β–„Β Β β–€Β β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–ˆ +β–ˆβ–ˆΒ β–€Β β–€Β β–€β–„β–ˆβ–„β–ˆΒ β–„β–„Β β–„β–ˆΒ β–€Β β–ˆβ–€β–„Β β–€Β β–„β–„β–€Β β–ˆβ–€Β Β β–„β–€Β β–ˆ +β–ˆβ–„β–„Β β–€Β β–ˆβ–€β–€Β β–€Β β–€β–„β–ˆβ–€β–„β–€β–€β–ˆΒ β–ˆΒ β–„β–€β–„Β β–„β–ˆβ–€β–ˆΒ β–„β–„Β β–„Β β–€β–ˆ +β–ˆβ–ˆβ–ˆβ–€β–„β–€β–ˆβ–€β–„β–ˆβ–€β–€β–€Β Β β–ˆΒ β–€β–„β–€β–ˆβ–€Β Β β–ˆβ–„β–ˆβ–€β–ˆβ–€Β β–„β–„β–ˆβ–„β–€β–€β–ˆβ–ˆ +β–ˆΒ β–„β–„β–„β–€Β β–€β–„β–ˆβ–ˆΒ β–„Β β–„β–„Β β–€β–„β–€β–„β–„Β Β β–€β–„Β β–€β–„β–ˆΒ β–ˆΒ β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ +β–ˆβ–ˆβ–ˆΒ Β Β β–€β–€Β β–ˆΒ Β β–ˆβ–ˆβ–€β–„Β Β Β β–ˆβ–ˆβ–€Β Β β–„β–€β–„β–„β–ˆβ–„Β β–„β–„β–€β–ˆβ–„β–€Β β–ˆ +β–ˆβ–„Β β–ˆβ–ˆβ–€β–„β–€β–„β–€β–ˆβ–€Β β–„β–€Β β–€β–„β–€β–€β–€β–ˆΒ β–„β–ˆβ–€Β β–„β–„β–„β–€Β Β β–„β–„β–€β–€β–„β–ˆ +β–ˆβ–„β–ˆβ–€β–„Β Β β–€Β β–€β–„Β β–„β–„β–„β–„β–„Β β–€β–„β–ˆβ–„Β β–€β–ˆΒ Β β–€β–ˆΒ β–ˆΒ β–„β–€Β β–€β–„β–ˆβ–ˆ +β–ˆβ–„β–„β–„β–€β–ˆβ–„β–€β–ˆΒ Β β–€β–€β–€β–ˆβ–„Β β–„β–ˆβ–ˆβ–„β–„Β β–€β–„β–„β–€β–€β–„Β β–ˆβ–ˆβ–„Β β–€β–ˆΒ β–€β–ˆ +β–ˆβ–€β–ˆΒ β–€β–€Β β–€β–„Β β–€β–„β–ˆΒ Β β–ˆβ–„β–ˆβ–„β–€β–€β–€β–„β–„β–€β–ˆβ–€β–„β–€β–„Β β–€Β β–ˆβ–ˆΒ Β Β β–ˆ +β–ˆβ–€β–„β–„β–„β–€Β β–€Β β–€β–ˆβ–„Β β–„β–ˆβ–€β–„β–ˆβ–ˆΒ β–„Β Β β–„β–ˆβ–„Β β–ˆΒ Β Β β–€β–€Β β–„β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–„β–ˆβ–„β–€β–€β–„β–€β–ˆβ–€β–„Β β–ˆΒ β–„β–ˆβ–ˆβ–„β–ˆΒ β–€Β β–ˆβ–€β–ˆΒ β–€β–€Β β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–€Β Β β–ˆβ–€β–„Β Β β–„Β β–ˆβ–ˆβ–€β–€Β β–„Β Β β–ˆΒ β–€β–€β–€Β β–€β–ˆβ–ˆβ–„β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€β–„β–€Β Β β–„β–ˆΒ Β β–ˆΒ β–€β–ˆΒ Β β–€β–€β–„β–„β–€β–„β–ˆβ–ˆΒ Β Β Β β–„Β β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„β–€β–„β–ˆβ–ˆβ–ˆβ–€β–„β–„β–€β–ˆβ–ˆΒ β–„β–„Β Β β–€β–€β–ˆβ–„β–„Β β–€β–ˆβ–€Β β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: GMVPYD2UVLW2CBJWYI7FLH2PRF4HJWQS + +Press Enter to continue... +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 19E180BD20F62DB0 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 014014 [###################-] 1s + +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-uk08yxgg/.seedpass/19E180BD20F62DB0/backups/entries_db_backup_1771874789.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAjYlVjkoSe+YR/vZAlFG+srTNhmAjqWAFwLYF0OA53NA= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEILE+T9RaXNvsXYG52RvNOypOXgxgAbblumRyyamnYoQw +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: 19E180BD20F62DB0 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: 19E180BD20F62DB0 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-uk08yxgg/.seedpass/19E180BD20F62DB0/backups/entries_db_backup_1771874789.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +aerobic because blur flock outside essay media boring wing abstract economy nominee +Show Compact Seed QR? (Y/N): n +Press Enter to continue... \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192726Z/report.json b/artifacts/agent_tui_test/20260223T192726Z/report.json new file mode 100644 index 00000000..c5b07e8c --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192726Z/report.json @@ -0,0 +1,43 @@ +{ + "timestamp_utc": "20260223T192726Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-kvxeepj9", + "duration_sec": 31.438, + "seedpass_exit_code": 1, + "status": "failed", + "failure": "Process exited before pattern appeared: 'Press Enter to continue\\\\.?'", + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "failed", + "duration_sec": 31.437690142000065, + "detail": "Process exited before pattern appeared: 'Press Enter to continue\\\\.?'" + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "invalid_input_resilience": true, + "add_password_quick": true, + "invalid_length_validation": true, + "add_totp": true, + "add_all_entry_types": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_codes_view": true, + "settings_toggles_lock_unlock": false, + "settings_stats": false, + "graceful_exit": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192726Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192726Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192726Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T192726Z/transcript.clean.txt new file mode 100644 index 00000000..b2dcd3c2 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192726Z/transcript.clean.txt @@ -0,0 +1,979 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +slot credit other demand spot parrot ice ginger close basic penalty please +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +1 +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: F4407AAA1133174F > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +1 +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: F4407AAA1133174F > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874848.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: 8Og*BY[a8 Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: F4407AAA1133174F > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 8Og*BY[a8 Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: F4407AAA1133174F > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: F4407AAA1133174F > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: F4407AAA1133174F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: F4407AAA1133174F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: F4407AAA1133174F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: F4407AAA1133174F > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874849.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=5HYMGMSYBPCJZ4W4LLEFZV2HQTW4HOVI&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–ˆβ–€β–€β–€β–ˆβ–€β–€β–€β–ˆβ–€β–€β–€β–ˆβ–€β–€β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€Β β–„β–€β–„Β β–ˆΒ β–€β–€β–ˆβ–„β–ˆβ–€β–€Β Β β–€β–ˆΒ Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆΒ β–ˆβ–„β–ˆβ–€Β β–ˆΒ β–ˆβ–€β–„β–€β–„β–ˆβ–„β–„Β Β β–„β–ˆβ–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–ˆΒ β–ˆΒ β–ˆβ–€β–ˆβ–€β–„β–€β–ˆΒ β–ˆβ–€β–ˆβ–€β–„β–€β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–„β–„β–€β–€Β β–„β–€Β β–ˆβ–„β–€β–€β–€β–„β–ˆΒ β–„Β β–ˆβ–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–€β–ˆ +β–ˆβ–€β–ˆΒ Β β–€Β β–€Β β–€Β β–ˆΒ Β Β β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–„β–„β–ˆβ–€β–ˆβ–„β–€β–€β–ˆβ–ˆβ–„Β β–„Β β–„Β β–ˆ +β–ˆβ–„β–€β–ˆβ–€β–„β–€β–€β–„β–„Β β–ˆβ–€Β β–„Β β–€β–€β–„β–ˆβ–ˆβ–ˆβ–ˆβ–„β–„β–„β–ˆβ–„β–„β–€Β Β Β β–ˆβ–€β–ˆβ–ˆβ–€β–ˆ +β–ˆΒ β–ˆΒ β–„Β β–€β–€Β β–ˆβ–€β–ˆΒ β–ˆΒ Β β–ˆβ–€β–€Β Β β–€β–ˆΒ Β β–„Β β–€Β β–€β–€β–„β–€β–ˆβ–€β–€β–ˆβ–„β–ˆ +β–ˆβ–ˆβ–€β–„Β β–€β–„β–€β–ˆβ–ˆβ–„Β Β β–„β–€β–ˆβ–€β–€β–€β–€β–€β–„β–ˆΒ β–„β–„β–ˆβ–€β–€β–€β–ˆβ–„β–ˆβ–„Β β–ˆβ–€β–„β–ˆ +β–ˆβ–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–„β–€β–ˆΒ β–„β–„Β β–ˆΒ β–ˆβ–€Β β–€β–ˆΒ β–€β–€β–€β–„Β β–€β–„β–„β–€β–€β–ˆβ–ˆβ–„Β β–ˆ +β–ˆβ–„Β β–€β–ˆβ–„Β β–€β–ˆβ–„β–ˆβ–€Β β–„β–ˆβ–„β–„Β Β β–ˆβ–„β–ˆβ–ˆβ–„Β β–€β–ˆβ–„β–ˆβ–„β–„Β β–ˆβ–„Β Β β–„β–„β–ˆ +β–ˆβ–€β–ˆΒ β–ˆβ–„β–€β–€β–„Β β–ˆΒ β–„β–„β–€β–€Β β–ˆβ–„β–ˆΒ β–„β–ˆβ–€Β Β β–ˆβ–€Β Β Β β–„β–€β–€β–ˆβ–€β–€β–ˆβ–ˆ +β–ˆβ–„Β Β Β β–„β–„β–€β–€β–€β–„β–„β–ˆβ–ˆβ–ˆΒ Β β–„Β β–ˆβ–€β–„β–ˆβ–€β–€β–„β–„β–€β–€Β β–„Β β–ˆΒ β–„β–ˆβ–„β–„β–ˆ +β–ˆβ–€Β Β β–„β–€Β β–€β–„β–„β–„Β β–ˆβ–„Β β–€β–€β–ˆβ–ˆβ–€β–„β–€β–€β–„β–„β–ˆβ–„β–„Β β–„β–ˆβ–€β–ˆβ–€Β β–ˆβ–ˆΒ β–ˆ +β–ˆβ–€β–€β–„β–€Β β–ˆβ–€β–„β–ˆΒ β–€β–„Β β–„β–ˆβ–€β–€β–€β–€β–€Β β–ˆβ–„Β β–„β–ˆβ–ˆβ–€Β β–€β–€β–€Β β–„β–€Β β–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ β–€β–ˆβ–„Β β–€β–„β–ˆβ–€β–€β–€Β Β β–€β–ˆΒ β–„Β Β β–„Β β–ˆβ–€β–ˆΒ β–„β–€β–„β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆβ–ˆΒ β–€Β β–€β–„β–„β–€β–€Β Β β–ˆβ–„β–€β–ˆβ–„β–ˆΒ Β Β β–€β–€β–€Β β–„β–ˆβ–ˆβ–€β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€β–ˆβ–„β–ˆβ–€β–€β–ˆβ–ˆΒ β–„Β β–„β–ˆβ–ˆΒ β–„β–€β–€β–„β–„β–„Β β–ˆβ–ˆΒ β–€β–€β–€Β β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„β–ˆβ–€β–ˆβ–€β–ˆβ–„β–„Β Β Β β–ˆβ–ˆβ–„β–€Β β–ˆβ–€β–ˆβ–ˆβ–€Β β–ˆβ–€β–ˆβ–„β–ˆβ–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: 5HYMGMSYBPCJZ4W4LLEFZV2HQTW4HOVI + +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: F4407AAA1133174F > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: F4407AAA1133174F > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 811580 [###################-] 1s + +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: F4407AAA1133174F > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874849.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAyaMrJQgV0/teySKq36MpaNS97BFsyjTr4RdiMaEoJSA= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIN76mgX5bArNyOL+iG6CXC0LxbVz0Wdsa6wUN/295gyE +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: F4407AAA1133174F > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874849.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +stairs view blush sauce acid bunker patch rival ring way annual today +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: F4407AAA1133174F > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874849.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub1ez3xk2vj6jmue84zrd377d7m40864g2ms967eukmtq05w5k7r2nqs5hv9q +nsec: nsec19cpc3a9fcvtg7l5yx29dvym2l0pstsg0kn5v4mtlftf5lrhay3usk6fh35 +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: F4407AAA1133174F > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874849.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 53C9434B12268AB098DA59D8EEC19D0C49A85954 +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdADFy3besXGfYV9ipy8FLxTnEorCw80EClsOxw +yC+/eT8AAP9Gum46IfY9lbYiPy9Dos0snSkdKh5WEBc7HWppZ7rGoA0OzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBFPJQ0sSJoqwmNpZ2O7BnQxJqFlU +AAoJEO7BnQxJqFlU+GEA/3rudiWmC+mhr3Z7Pv1gTVtLoQ09bWigYcQAaRWEAWMI +APsFmk+CGxdh2AHmVtNKHM4ransMv+0twpH5VuUImFkmAA== +=a4KQ +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: F4407AAA1133174F > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874849.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: F4407AAA1133174F > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874849.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: F4407AAA1133174F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: F4407AAA1133174F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: F4407AAA1133174F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: F4407AAA1133174F > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874849.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: F4407AAA1133174F > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 8Og*BY[a8 Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874850.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: F4407AAA1133174F > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: F4407AAA1133174F > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874850.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: F4407AAA1133174F > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: F4407AAA1133174F > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 035290 [#-------------------] 28s + +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +2026-02-23 14:27:57,591 [ERROR] Failed to initialize BIP-85: Vault is locked [manager.py:1390] +Traceback (most recent call last): + File "/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py", line 1388, in initialize_bip85 + self.clear_bip85_cache() + File "/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py", line 203, in wrapper + raise VaultLockedError("Vault is locked") +seedpass.errors.VaultLockedError: Vault is locked +Error: Failed to initialize BIP-85: Vault is locked +2026-02-23 14:27:57,595 [ERROR] An unexpected error occurred: Failed to initialize BIP-85: Vault is locked [main.py:1460] +Traceback (most recent call last): + File "/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py", line 1388, in initialize_bip85 + self.clear_bip85_cache() + File "/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py", line 203, in wrapper + raise VaultLockedError("Vault is locked") +seedpass.errors.VaultLockedError: Vault is locked + +The above exception was the direct cause of the following exception: + +Traceback (most recent call last): + File "/home/user/Documents/GitHub/SeedPass/src/main.py", line 1434, in main + display_menu( + File "/home/user/Documents/GitHub/SeedPass/src/main.py", line 1229, in display_menu + handle_settings(password_manager) + File "/home/user/Documents/GitHub/SeedPass/src/main.py", line 1052, in handle_settings + password_manager.unlock_vault() + File "/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py", line 524, in unlock_vault + self.initialize_bip85() + File "/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py", line 1392, in initialize_bip85 + raise SeedPassError(f"Failed to initialize BIP-85: {e}") from e +seedpass.core.errors.SeedPassError: Failed to initialize BIP-85: Vault is locked +Error: An unexpected error occurred: Failed to initialize BIP-85: Vault is locked diff --git a/artifacts/agent_tui_test/20260223T192726Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T192726Z/transcript.raw.txt new file mode 100644 index 00000000..7acba6c2 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192726Z/transcript.raw.txt @@ -0,0 +1,980 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +slot credit other demand spot parrot ice ginger close basic penalty please +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +1 +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: F4407AAA1133174F > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +1 +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: F4407AAA1133174F > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874848.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: 8Og*BY[a8 Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: F4407AAA1133174F > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 8Og*BY[a8 Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: F4407AAA1133174F > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: F4407AAA1133174F > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: F4407AAA1133174F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: F4407AAA1133174F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: F4407AAA1133174F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: F4407AAA1133174F > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874849.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=5HYMGMSYBPCJZ4W4LLEFZV2HQTW4HOVI&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–ˆβ–€β–€β–€β–ˆβ–€β–€β–€β–ˆβ–€β–€β–€β–ˆβ–€β–€β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€Β β–„β–€β–„Β β–ˆΒ β–€β–€β–ˆβ–„β–ˆβ–€β–€Β Β β–€β–ˆΒ Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆΒ β–ˆβ–„β–ˆβ–€Β β–ˆΒ β–ˆβ–€β–„β–€β–„β–ˆβ–„β–„Β Β β–„β–ˆβ–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–ˆΒ β–ˆΒ β–ˆβ–€β–ˆβ–€β–„β–€β–ˆΒ β–ˆβ–€β–ˆβ–€β–„β–€β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–„β–„β–€β–€Β β–„β–€Β β–ˆβ–„β–€β–€β–€β–„β–ˆΒ β–„Β β–ˆβ–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–€β–ˆ +β–ˆβ–€β–ˆΒ Β β–€Β β–€Β β–€Β β–ˆΒ Β Β β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–„β–„β–ˆβ–€β–ˆβ–„β–€β–€β–ˆβ–ˆβ–„Β β–„Β β–„Β β–ˆ +β–ˆβ–„β–€β–ˆβ–€β–„β–€β–€β–„β–„Β β–ˆβ–€Β β–„Β β–€β–€β–„β–ˆβ–ˆβ–ˆβ–ˆβ–„β–„β–„β–ˆβ–„β–„β–€Β Β Β β–ˆβ–€β–ˆβ–ˆβ–€β–ˆ +β–ˆΒ β–ˆΒ β–„Β β–€β–€Β β–ˆβ–€β–ˆΒ β–ˆΒ Β β–ˆβ–€β–€Β Β β–€β–ˆΒ Β β–„Β β–€Β β–€β–€β–„β–€β–ˆβ–€β–€β–ˆβ–„β–ˆ +β–ˆβ–ˆβ–€β–„Β β–€β–„β–€β–ˆβ–ˆβ–„Β Β β–„β–€β–ˆβ–€β–€β–€β–€β–€β–„β–ˆΒ β–„β–„β–ˆβ–€β–€β–€β–ˆβ–„β–ˆβ–„Β β–ˆβ–€β–„β–ˆ +β–ˆβ–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–„β–€β–ˆΒ β–„β–„Β β–ˆΒ β–ˆβ–€Β β–€β–ˆΒ β–€β–€β–€β–„Β β–€β–„β–„β–€β–€β–ˆβ–ˆβ–„Β β–ˆ +β–ˆβ–„Β β–€β–ˆβ–„Β β–€β–ˆβ–„β–ˆβ–€Β β–„β–ˆβ–„β–„Β Β β–ˆβ–„β–ˆβ–ˆβ–„Β β–€β–ˆβ–„β–ˆβ–„β–„Β β–ˆβ–„Β Β β–„β–„β–ˆ +β–ˆβ–€β–ˆΒ β–ˆβ–„β–€β–€β–„Β β–ˆΒ β–„β–„β–€β–€Β β–ˆβ–„β–ˆΒ β–„β–ˆβ–€Β Β β–ˆβ–€Β Β Β β–„β–€β–€β–ˆβ–€β–€β–ˆβ–ˆ +β–ˆβ–„Β Β Β β–„β–„β–€β–€β–€β–„β–„β–ˆβ–ˆβ–ˆΒ Β β–„Β β–ˆβ–€β–„β–ˆβ–€β–€β–„β–„β–€β–€Β β–„Β β–ˆΒ β–„β–ˆβ–„β–„β–ˆ +β–ˆβ–€Β Β β–„β–€Β β–€β–„β–„β–„Β β–ˆβ–„Β β–€β–€β–ˆβ–ˆβ–€β–„β–€β–€β–„β–„β–ˆβ–„β–„Β β–„β–ˆβ–€β–ˆβ–€Β β–ˆβ–ˆΒ β–ˆ +β–ˆβ–€β–€β–„β–€Β β–ˆβ–€β–„β–ˆΒ β–€β–„Β β–„β–ˆβ–€β–€β–€β–€β–€Β β–ˆβ–„Β β–„β–ˆβ–ˆβ–€Β β–€β–€β–€Β β–„β–€Β β–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ β–€β–ˆβ–„Β β–€β–„β–ˆβ–€β–€β–€Β Β β–€β–ˆΒ β–„Β Β β–„Β β–ˆβ–€β–ˆΒ β–„β–€β–„β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆβ–ˆΒ β–€Β β–€β–„β–„β–€β–€Β Β β–ˆβ–„β–€β–ˆβ–„β–ˆΒ Β Β β–€β–€β–€Β β–„β–ˆβ–ˆβ–€β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€β–ˆβ–„β–ˆβ–€β–€β–ˆβ–ˆΒ β–„Β β–„β–ˆβ–ˆΒ β–„β–€β–€β–„β–„β–„Β β–ˆβ–ˆΒ β–€β–€β–€Β β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„β–ˆβ–€β–ˆβ–€β–ˆβ–„β–„Β Β Β β–ˆβ–ˆβ–„β–€Β β–ˆβ–€β–ˆβ–ˆβ–€Β β–ˆβ–€β–ˆβ–„β–ˆβ–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: 5HYMGMSYBPCJZ4W4LLEFZV2HQTW4HOVI + +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: F4407AAA1133174F > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: F4407AAA1133174F > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 811580 [###################-] 1s + +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: F4407AAA1133174F > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874849.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAyaMrJQgV0/teySKq36MpaNS97BFsyjTr4RdiMaEoJSA= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIN76mgX5bArNyOL+iG6CXC0LxbVz0Wdsa6wUN/295gyE +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: F4407AAA1133174F > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874849.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +stairs view blush sauce acid bunker patch rival ring way annual today +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: F4407AAA1133174F > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874849.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub1ez3xk2vj6jmue84zrd377d7m40864g2ms967eukmtq05w5k7r2nqs5hv9q +nsec: nsec19cpc3a9fcvtg7l5yx29dvym2l0pstsg0kn5v4mtlftf5lrhay3usk6fh35 +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: F4407AAA1133174F > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874849.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 53C9434B12268AB098DA59D8EEC19D0C49A85954 +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdADFy3besXGfYV9ipy8FLxTnEorCw80EClsOxw +yC+/eT8AAP9Gum46IfY9lbYiPy9Dos0snSkdKh5WEBc7HWppZ7rGoA0OzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBFPJQ0sSJoqwmNpZ2O7BnQxJqFlU +AAoJEO7BnQxJqFlU+GEA/3rudiWmC+mhr3Z7Pv1gTVtLoQ09bWigYcQAaRWEAWMI +APsFmk+CGxdh2AHmVtNKHM4ransMv+0twpH5VuUImFkmAA== +=a4KQ +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: F4407AAA1133174F > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874849.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: F4407AAA1133174F > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874849.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: F4407AAA1133174F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: F4407AAA1133174F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: F4407AAA1133174F > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: F4407AAA1133174F > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874849.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: F4407AAA1133174F > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 8Og*BY[a8 Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874850.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: F4407AAA1133174F > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: F4407AAA1133174F > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-kvxeepj9/.seedpass/F4407AAA1133174F/backups/entries_db_backup_1771874850.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: F4407AAA1133174F > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: F4407AAA1133174F > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 035290 [#-------------------] 28s + +cSeed Profile: F4407AAA1133174F > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +2026-02-23 14:27:57,591 [ERROR] Failed to initialize BIP-85: Vault is locked [manager.py:1390] +Traceback (most recent call last): + File "/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py", line 1388, in initialize_bip85 + self.clear_bip85_cache() + File "/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py", line 203, in wrapper + raise VaultLockedError("Vault is locked") +seedpass.errors.VaultLockedError: Vault is locked +Error: Failed to initialize BIP-85: Vault is locked +2026-02-23 14:27:57,595 [ERROR] An unexpected error occurred: Failed to initialize BIP-85: Vault is locked [main.py:1460] +Traceback (most recent call last): + File "/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py", line 1388, in initialize_bip85 + self.clear_bip85_cache() + File "/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py", line 203, in wrapper + raise VaultLockedError("Vault is locked") +seedpass.errors.VaultLockedError: Vault is locked + +The above exception was the direct cause of the following exception: + +Traceback (most recent call last): + File "/home/user/Documents/GitHub/SeedPass/src/main.py", line 1434, in main + display_menu( + File "/home/user/Documents/GitHub/SeedPass/src/main.py", line 1229, in display_menu + handle_settings(password_manager) + File "/home/user/Documents/GitHub/SeedPass/src/main.py", line 1052, in handle_settings + password_manager.unlock_vault() + File "/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py", line 524, in unlock_vault + self.initialize_bip85() + File "/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py", line 1392, in initialize_bip85 + raise SeedPassError(f"Failed to initialize BIP-85: {e}") from e +seedpass.core.errors.SeedPassError: Failed to initialize BIP-85: Vault is locked +Error: An unexpected error occurred: Failed to initialize BIP-85: Vault is locked + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192857Z/report.json b/artifacts/agent_tui_test/20260223T192857Z/report.json new file mode 100644 index 00000000..398b0751 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192857Z/report.json @@ -0,0 +1,43 @@ +{ + "timestamp_utc": "20260223T192857Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-oo3_tfoo", + "duration_sec": 32.116, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 31.757753636997222, + "detail": null + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "invalid_input_resilience": true, + "add_password_quick": true, + "invalid_length_validation": true, + "add_totp": true, + "add_all_entry_types": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_codes_view": true, + "settings_toggles_lock_unlock": true, + "settings_stats": true, + "graceful_exit": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192857Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192857Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192857Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T192857Z/transcript.clean.txt new file mode 100644 index 00000000..a8ac6657 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192857Z/transcript.clean.txt @@ -0,0 +1,1065 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +garage breeze capital imitate source forest town borrow wine infant list abstract +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +1 +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874939.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: y]MFK6\b>40f + +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: y]MFK6\b>40f +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 6E81BB279FA65F53 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874940.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=EP7ID3WYSQSYFACYJ3NVZVZK545P5S63&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–„β–€β–„β–€Β β–€β–„β–ˆβ–„β–„β–ˆβ–€β–ˆβ–„β–€β–ˆΒ β–„β–ˆβ–ˆΒ β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€Β β–ˆβ–„β–„β–ˆβ–€β–ˆβ–„Β β–€β–€β–€β–€β–ˆβ–€β–„β–ˆΒ β–€β–ˆβ–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„Β β–ˆβ–€β–„Β β–ˆΒ β–ˆβ–€β–„Β β–„β–€β–„β–€β–ˆβ–€β–„Β β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–€Β β–„β–€β–„Β β–€β–„β–„Β Β β–„β–„β–€β–„β–„Β Β β–€Β β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–ˆ +β–ˆβ–ˆΒ Β β–€Β β–€β–€β–€β–ˆβ–ˆβ–ˆβ–„β–ˆβ–ˆΒ β–„β–ˆΒ β–€Β β–ˆβ–€β–„Β β–€Β β–„β–„β–€Β β–ˆΒ Β Β β–€β–€Β β–ˆ +β–ˆβ–€Β β–„β–„β–€β–€β–€β–€β–ˆΒ β–„β–€Β β–€β–ˆβ–„β–€β–ˆβ–€Β β–ˆΒ β–„β–€β–„Β β–„β–€β–€β–ˆΒ β–ˆβ–„β–€β–„Β β–€β–ˆ +β–ˆβ–€β–„Β β–€β–ˆβ–€β–€β–€β–ˆβ–„β–ˆβ–€Β β–„β–€β–ˆΒ β–„β–€β–ˆβ–€Β Β β–ˆβ–„β–ˆβ–€β–ˆβ–€Β β–„β–„β–ˆβ–„β–€β–€β–€β–ˆ +β–ˆβ–€Β β–ˆΒ β–ˆβ–ˆβ–€β–ˆβ–€Β β–„β–ˆβ–„β–ˆβ–€β–„β–€β–„β–€β–„β–„Β Β β–€β–„Β β–€β–„β–€Β Β Β Β β–ˆβ–ˆβ–ˆβ–„β–ˆ +β–ˆβ–€β–„β–ˆβ–ˆβ–€β–„β–€β–ˆβ–„β–„β–€β–€β–„Β β–€Β Β β–€β–ˆβ–ˆβ–€Β Β β–„β–€β–„β–„Β β–€β–€β–ˆΒ β–ˆΒ β–ˆβ–€Β β–ˆ +β–ˆβ–„β–ˆβ–„β–ˆβ–€β–€β–€Β β–ˆΒ Β β–„β–€β–„β–€β–€β–„Β Β β–€β–ˆΒ β–„β–ˆβ–€Β β–„Β β–ˆβ–€Β Β β–„β–€β–€β–€β–„β–ˆ +β–ˆΒ β–„β–€β–ˆβ–„β–€β–€β–ˆβ–„β–€β–ˆΒ β–€Β β–€β–„β–„β–€β–ˆβ–ˆβ–„Β β–€β–ˆΒ Β β–€β–ˆΒ β–ˆΒ β–„β–€Β β–€β–„β–„β–ˆ +β–ˆβ–€β–„β–€Β β–„β–ˆβ–€β–„β–ˆβ–€β–„β–„β–„β–€β–€β–„β–ˆβ–ˆβ–ˆβ–„β–„Β β–€β–„β–„β–€β–€β–„Β β–€β–ˆΒ Β β–€β–ˆΒ β–ˆβ–ˆ +β–ˆβ–€β–ˆβ–ˆΒ β–ˆβ–„β–€Β Β β–„Β β–ˆβ–€β–ˆβ–€β–„β–ˆβ–ˆβ–€β–€β–€β–„β–„β–€β–ˆβ–€β–„β–„β–„β–€Β Β β–€β–„β–„Β Β β–ˆ +β–ˆβ–€β–„β–€β–ˆβ–€β–„β–€Β β–„β–€β–ˆβ–€Β β–„β–ˆβ–„β–€β–€Β β–„Β Β β–„β–ˆβ–„Β β–ˆβ–€Β Β β–€Β Β β–„Β β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–„β–€β–€β–„Β β–„β–€β–€Β β–„β–€β–ˆΒ β–„β–ˆβ–ˆβ–„β–ˆΒ β–€Β β–ˆβ–€β–ˆΒ β–€β–€β–ˆβ–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–ˆβ–ˆΒ β–€Β β–„β–ˆβ–€β–„Β β–ˆβ–ˆβ–€β–€Β β–„Β Β β–ˆΒ β–€β–€β–€Β β–€β–ˆβ–„β–„β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€β–ˆβ–„β–€Β β–„β–€Β Β β–ˆΒ β–€β–ˆΒ Β β–€β–€β–„β–„β–€β–„β–ˆβ–ˆΒ Β β–€β–€β–„Β β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–ˆΒ β–€β–„β–„β–ˆβ–€β–„Β Β β–ˆβ–ˆΒ β–„β–„Β Β β–€β–ˆΒ β–ˆβ–€Β β–€β–€β–€Β β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: EP7ID3WYSQSYFACYJ3NVZVZK545P5S63 + +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 6E81BB279FA65F53 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 117931 [--------------------] 30s + +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874940.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAQB4G9NoBXR0x5H69HWgB8KyS4EG655QNIJn3BbEneHQ= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIHhY9SzfbKQqxp2L69JgW4QHFGiqulxb/GOknu/kxQ+L +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874940.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +congress leopard penalty that height drastic sail chair crew symbol october cupboard +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874940.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub1kg2j6tmenzyws5fksprkraatrtcc0m8y2xpnggc8m7v9wzuagk5s0876tg +nsec: nsec1r3tl3zkzkl979rjkjej56gmhsc4s2wmlhuhkzjwdnyzzjqhp7vlqxhdhyd +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874940.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 744248AA2F2BB848329B1C74B0D1E974F94C049B +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdA6Zhhn6qq2XMWRTXtSt0ofxtKbJkuC2bp2qZ3 +v0MgjEQAAP9DchJgdZ1kj01moD3rfJK8IrJ0fyEzWYgDN/+fMMY/Hw6YzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBHRCSKovK7hIMpscdLDR6XT5TASb +AAoJELDR6XT5TASb1+8A/22nA7kGWBdagpiJ5tL2cph8GoJFU/MvcBeOxLM144y9 +AP9LilPsTm/JtC/oOYrQKM2TY62MLIiaSy6rSJ8MaF7ZCg== +=6X2h +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874940.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874940.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: 6E81BB279FA65F53 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874940.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: y]MFK6\b>40f +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874941.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 6E81BB279FA65F53 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874941.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 6E81BB279FA65F53 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 117931 [##------------------] 27s + +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 6E81BB279FA65F53 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 8 + password: 1 + totp: 1 + ssh: 1 + seed: 1 + pgp: 1 + nostr: 1 + key_value: 1 + managed_account: 1 +Relays configured: 3 +Backups: 3 (dir: /tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 6E81BB279FA65F53 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T192857Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T192857Z/transcript.raw.txt new file mode 100644 index 00000000..b9a308f8 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192857Z/transcript.raw.txt @@ -0,0 +1,1066 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +garage breeze capital imitate source forest town borrow wine infant list abstract +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +1 +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874939.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: y]MFK6\b>40f + +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: y]MFK6\b>40f +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 6E81BB279FA65F53 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874940.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=EP7ID3WYSQSYFACYJ3NVZVZK545P5S63&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–„β–€β–„β–€Β β–€β–„β–ˆβ–„β–„β–ˆβ–€β–ˆβ–„β–€β–ˆΒ β–„β–ˆβ–ˆΒ β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€Β β–ˆβ–„β–„β–ˆβ–€β–ˆβ–„Β β–€β–€β–€β–€β–ˆβ–€β–„β–ˆΒ β–€β–ˆβ–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„Β β–ˆβ–€β–„Β β–ˆΒ β–ˆβ–€β–„Β β–„β–€β–„β–€β–ˆβ–€β–„Β β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–€Β β–„β–€β–„Β β–€β–„β–„Β Β β–„β–„β–€β–„β–„Β Β β–€Β β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–ˆ +β–ˆβ–ˆΒ Β β–€Β β–€β–€β–€β–ˆβ–ˆβ–ˆβ–„β–ˆβ–ˆΒ β–„β–ˆΒ β–€Β β–ˆβ–€β–„Β β–€Β β–„β–„β–€Β β–ˆΒ Β Β β–€β–€Β β–ˆ +β–ˆβ–€Β β–„β–„β–€β–€β–€β–€β–ˆΒ β–„β–€Β β–€β–ˆβ–„β–€β–ˆβ–€Β β–ˆΒ β–„β–€β–„Β β–„β–€β–€β–ˆΒ β–ˆβ–„β–€β–„Β β–€β–ˆ +β–ˆβ–€β–„Β β–€β–ˆβ–€β–€β–€β–ˆβ–„β–ˆβ–€Β β–„β–€β–ˆΒ β–„β–€β–ˆβ–€Β Β β–ˆβ–„β–ˆβ–€β–ˆβ–€Β β–„β–„β–ˆβ–„β–€β–€β–€β–ˆ +β–ˆβ–€Β β–ˆΒ β–ˆβ–ˆβ–€β–ˆβ–€Β β–„β–ˆβ–„β–ˆβ–€β–„β–€β–„β–€β–„β–„Β Β β–€β–„Β β–€β–„β–€Β Β Β Β β–ˆβ–ˆβ–ˆβ–„β–ˆ +β–ˆβ–€β–„β–ˆβ–ˆβ–€β–„β–€β–ˆβ–„β–„β–€β–€β–„Β β–€Β Β β–€β–ˆβ–ˆβ–€Β Β β–„β–€β–„β–„Β β–€β–€β–ˆΒ β–ˆΒ β–ˆβ–€Β β–ˆ +β–ˆβ–„β–ˆβ–„β–ˆβ–€β–€β–€Β β–ˆΒ Β β–„β–€β–„β–€β–€β–„Β Β β–€β–ˆΒ β–„β–ˆβ–€Β β–„Β β–ˆβ–€Β Β β–„β–€β–€β–€β–„β–ˆ +β–ˆΒ β–„β–€β–ˆβ–„β–€β–€β–ˆβ–„β–€β–ˆΒ β–€Β β–€β–„β–„β–€β–ˆβ–ˆβ–„Β β–€β–ˆΒ Β β–€β–ˆΒ β–ˆΒ β–„β–€Β β–€β–„β–„β–ˆ +β–ˆβ–€β–„β–€Β β–„β–ˆβ–€β–„β–ˆβ–€β–„β–„β–„β–€β–€β–„β–ˆβ–ˆβ–ˆβ–„β–„Β β–€β–„β–„β–€β–€β–„Β β–€β–ˆΒ Β β–€β–ˆΒ β–ˆβ–ˆ +β–ˆβ–€β–ˆβ–ˆΒ β–ˆβ–„β–€Β Β β–„Β β–ˆβ–€β–ˆβ–€β–„β–ˆβ–ˆβ–€β–€β–€β–„β–„β–€β–ˆβ–€β–„β–„β–„β–€Β Β β–€β–„β–„Β Β β–ˆ +β–ˆβ–€β–„β–€β–ˆβ–€β–„β–€Β β–„β–€β–ˆβ–€Β β–„β–ˆβ–„β–€β–€Β β–„Β Β β–„β–ˆβ–„Β β–ˆβ–€Β Β β–€Β Β β–„Β β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–„β–€β–€β–„Β β–„β–€β–€Β β–„β–€β–ˆΒ β–„β–ˆβ–ˆβ–„β–ˆΒ β–€Β β–ˆβ–€β–ˆΒ β–€β–€β–ˆβ–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–ˆβ–ˆΒ β–€Β β–„β–ˆβ–€β–„Β β–ˆβ–ˆβ–€β–€Β β–„Β Β β–ˆΒ β–€β–€β–€Β β–€β–ˆβ–„β–„β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€β–ˆβ–„β–€Β β–„β–€Β Β β–ˆΒ β–€β–ˆΒ Β β–€β–€β–„β–„β–€β–„β–ˆβ–ˆΒ Β β–€β–€β–„Β β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–ˆΒ β–€β–„β–„β–ˆβ–€β–„Β Β β–ˆβ–ˆΒ β–„β–„Β Β β–€β–ˆΒ β–ˆβ–€Β β–€β–€β–€Β β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: EP7ID3WYSQSYFACYJ3NVZVZK545P5S63 + +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 6E81BB279FA65F53 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 117931 [--------------------] 30s + +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874940.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAQB4G9NoBXR0x5H69HWgB8KyS4EG655QNIJn3BbEneHQ= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIHhY9SzfbKQqxp2L69JgW4QHFGiqulxb/GOknu/kxQ+L +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874940.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +congress leopard penalty that height drastic sail chair crew symbol october cupboard +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874940.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub1kg2j6tmenzyws5fksprkraatrtcc0m8y2xpnggc8m7v9wzuagk5s0876tg +nsec: nsec1r3tl3zkzkl979rjkjej56gmhsc4s2wmlhuhkzjwdnyzzjqhp7vlqxhdhyd +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874940.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 744248AA2F2BB848329B1C74B0D1E974F94C049B +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdA6Zhhn6qq2XMWRTXtSt0ofxtKbJkuC2bp2qZ3 +v0MgjEQAAP9DchJgdZ1kj01moD3rfJK8IrJ0fyEzWYgDN/+fMMY/Hw6YzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBHRCSKovK7hIMpscdLDR6XT5TASb +AAoJELDR6XT5TASb1+8A/22nA7kGWBdagpiJ5tL2cph8GoJFU/MvcBeOxLM144y9 +AP9LilPsTm/JtC/oOYrQKM2TY62MLIiaSy6rSJ8MaF7ZCg== +=6X2h +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874940.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874940.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: 6E81BB279FA65F53 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874940.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: y]MFK6\b>40f +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874941.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 6E81BB279FA65F53 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups/entries_db_backup_1771874941.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 6E81BB279FA65F53 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 6E81BB279FA65F53 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 117931 [##------------------] 27s + +cSeed Profile: 6E81BB279FA65F53 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 6E81BB279FA65F53 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 8 + password: 1 + totp: 1 + ssh: 1 + seed: 1 + pgp: 1 + nostr: 1 + key_value: 1 + managed_account: 1 +Relays configured: 3 +Backups: 3 (dir: /tmp/seedpass-agent-home-oo3_tfoo/.seedpass/6E81BB279FA65F53/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 6E81BB279FA65F53 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192933Z/report.json b/artifacts/agent_tui_test/20260223T192933Z/report.json new file mode 100644 index 00000000..89d86d84 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192933Z/report.json @@ -0,0 +1,43 @@ +{ + "timestamp_utc": "20260223T192933Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-smqhylt4", + "duration_sec": 31.013, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 30.8225278860009, + "detail": null + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "invalid_input_resilience": true, + "add_password_quick": true, + "invalid_length_validation": true, + "add_totp": true, + "add_all_entry_types": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_codes_view": true, + "settings_toggles_lock_unlock": true, + "settings_stats": true, + "graceful_exit": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192933Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T192933Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T192933Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T192933Z/transcript.clean.txt new file mode 100644 index 00000000..03e809dd --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192933Z/transcript.clean.txt @@ -0,0 +1,1065 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +north brown echo double joy idea pet rescue devote pupil lunar once +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +1 +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: WOw66\f>)cT3 + +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: WOw66\f>)cT3 +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 32B368AFCA3D5083 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=V7B35TLT7GDE6YTNTKOVSZYQKZYOHL7U&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–€β–€β–€β–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆΒ β–ˆβ–ˆβ–ˆΒ Β Β Β β–€Β β–€Β β–€β–€Β β–ˆβ–„Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–€Β Β β–ˆβ–ˆβ–ˆΒ β–„Β β–€β–„β–€β–€Β β–€β–„Β Β β–€Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–„β–€β–„Β β–ˆβ–€β–ˆΒ β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€Β β–„Β Β β–ˆβ–„Β β–€Β β–„Β β–ˆβ–„β–„β–„β–„β–„β–ˆΒ β–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–ˆβ–ˆβ–€Β β–ˆβ–ˆβ–€β–€β–€Β β–ˆβ–€β–ˆβ–€β–€β–€β–ˆβ–€Β Β Β β–„β–„β–ˆβ–„Β β–€β–€β–€β–„β–€β–„Β β–ˆΒ β–„β–ˆβ–ˆ +β–ˆβ–„β–€β–€Β β–ˆΒ β–€β–„β–„β–„β–„Β β–ˆβ–ˆβ–€β–„Β Β β–„β–ˆβ–ˆΒ β–€β–€β–„β–ˆβ–„β–€β–„β–ˆΒ β–€β–„β–„β–ˆΒ β–€β–ˆ +β–ˆβ–€β–ˆΒ Β β–ˆβ–„β–€β–€β–€β–€β–„β–ˆβ–„β–„β–„β–„β–€β–€β–ˆβ–ˆβ–„β–ˆΒ Β β–€β–ˆβ–„Β β–€β–€β–€β–„Β β–€β–€β–€β–ˆβ–ˆ +β–ˆβ–„β–€β–ˆβ–€Β β–ˆβ–€β–€β–„Β β–€Β Β β–ˆΒ β–„β–ˆβ–„β–€β–€β–„Β β–ˆβ–€β–„β–ˆβ–€β–„β–„Β Β β–€Β β–ˆΒ Β β–ˆβ–ˆ +β–ˆΒ Β Β β–„Β Β β–€Β β–€Β β–€β–€Β Β β–„β–ˆΒ β–„β–„β–ˆβ–„β–ˆΒ β–€β–„β–„β–€β–ˆΒ β–„β–€Β Β β–„β–€β–„β–ˆβ–ˆ +β–ˆβ–„β–„β–„β–ˆβ–ˆβ–ˆβ–€β–ˆβ–„β–„β–ˆβ–„β–ˆβ–„Β β–€β–€Β β–€β–„β–ˆΒ β–€β–ˆβ–€β–ˆβ–„β–€Β β–€Β β–„β–„β–„Β β–€β–„β–ˆ +β–ˆβ–ˆβ–ˆβ–ˆβ–„β–€β–ˆβ–€β–€β–€Β β–„Β β–€β–ˆβ–€β–€β–ˆβ–„β–€β–ˆβ–€β–ˆβ–€Β β–ˆΒ β–„Β Β β–„β–€β–„β–„β–ˆβ–€β–ˆβ–„β–ˆ +β–ˆβ–€Β Β β–€β–„Β β–€β–„β–€β–€Β β–„Β β–„β–€β–ˆβ–€β–ˆβ–ˆβ–€β–„Β β–„β–„β–„β–„β–€β–„β–ˆβ–„β–€β–ˆβ–„β–€Β Β β–„β–ˆ +β–ˆβ–„β–ˆΒ Β β–„β–„β–€β–ˆβ–ˆΒ β–„Β β–ˆβ–ˆβ–€β–€β–ˆβ–„Β β–€β–„β–€β–„β–„Β β–€β–€β–ˆβ–€β–ˆβ–ˆβ–„β–„β–„Β β–ˆβ–ˆβ–ˆ +β–ˆβ–€β–€β–€Β Β β–„β–€β–ˆΒ Β β–ˆβ–ˆΒ β–€β–ˆβ–„β–„β–„β–ˆβ–€Β Β β–€β–ˆβ–„β–ˆβ–ˆβ–„β–€Β β–€Β β–€β–„β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ β–ˆβ–„Β β–€β–„Β β–„β–„β–€β–„β–ˆβ–ˆβ–€β–ˆΒ β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ β–„β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–„β–ˆβ–„β–„β–€β–€Β β–„β–„Β Β β–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–€β–€β–€Β β–€Β Β β–€β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆβ–ˆβ–„β–ˆβ–„β–€β–ˆβ–ˆΒ β–ˆβ–ˆβ–€Β β–ˆΒ β–„β–„β–„β–€β–„β–„Β Β Β β–ˆβ–€β–„β–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„Β Β β–ˆβ–€β–„β–€β–€β–€β–„Β β–ˆΒ β–€β–„Β β–ˆβ–€Β Β β–ˆβ–€β–ˆβ–€β–€β–€Β β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: V7B35TLT7GDE6YTNTKOVSZYQKZYOHL7U + +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 32B368AFCA3D5083 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 359933 [####----------------] 24s + +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAVzLg75hcxflhAsb40a8zQ4XSjJkKM3BHeRbyQaKsueE= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEILZ02RBE9nKkn75OkgJ6YRNkuREG29Q9+l7+WRw0ZZPW +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +slam jar during wild soda modify calm horn accuse theme mix hybrid +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub140hghu7f9yaf37yl89gq302gr4kk2jadkrlr3u59pwza320pt46shxm2w9 +nsec: nsec1e8036n7jjhrhmmzezzyv4wwghdnyn8vsflwzlasykkrxur0gnluqfes2r4 +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: A6A64916B6DA98ED727D00E4354185582B522511 +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdA8AMiSp5HKN12T6m75WfwjHXLIROO8hXnYhnf +dq51bOkAAPwPTlt95NMqOcTTZ7C1QAuHepY1IzgKbYySWhoxNI3R3Q7JzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBKamSRa22pjtcn0A5DVBhVgrUiUR +AAoJEDVBhVgrUiUR2XEBAMT3mtQhQzXDQn+I31qDeekJP3ac5LY9h4OZptN2Pzbb +AP9xuCMY44xpl2hK7DeJJCOqoqYwW//2rkNjT8Nm1zN7CQ== +=Yhiv +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: 32B368AFCA3D5083 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: WOw66\f>)cT3 +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874977.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 32B368AFCA3D5083 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874977.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 32B368AFCA3D5083 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 359933 [######--------------] 21s + +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 32B368AFCA3D5083 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 8 + password: 1 + totp: 1 + ssh: 1 + seed: 1 + pgp: 1 + nostr: 1 + key_value: 1 + managed_account: 1 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 32B368AFCA3D5083 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T192933Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T192933Z/transcript.raw.txt new file mode 100644 index 00000000..91e3fd1c --- /dev/null +++ b/artifacts/agent_tui_test/20260223T192933Z/transcript.raw.txt @@ -0,0 +1,1066 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +north brown echo double joy idea pet rescue devote pupil lunar once +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +1 +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: WOw66\f>)cT3 + +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: WOw66\f>)cT3 +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 32B368AFCA3D5083 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=V7B35TLT7GDE6YTNTKOVSZYQKZYOHL7U&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–€β–€β–€β–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆΒ β–ˆβ–ˆβ–ˆΒ Β Β Β β–€Β β–€Β β–€β–€Β β–ˆβ–„Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–€Β Β β–ˆβ–ˆβ–ˆΒ β–„Β β–€β–„β–€β–€Β β–€β–„Β Β β–€Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–„β–€β–„Β β–ˆβ–€β–ˆΒ β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€Β β–„Β Β β–ˆβ–„Β β–€Β β–„Β β–ˆβ–„β–„β–„β–„β–„β–ˆΒ β–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–ˆβ–ˆβ–€Β β–ˆβ–ˆβ–€β–€β–€Β β–ˆβ–€β–ˆβ–€β–€β–€β–ˆβ–€Β Β Β β–„β–„β–ˆβ–„Β β–€β–€β–€β–„β–€β–„Β β–ˆΒ β–„β–ˆβ–ˆ +β–ˆβ–„β–€β–€Β β–ˆΒ β–€β–„β–„β–„β–„Β β–ˆβ–ˆβ–€β–„Β Β β–„β–ˆβ–ˆΒ β–€β–€β–„β–ˆβ–„β–€β–„β–ˆΒ β–€β–„β–„β–ˆΒ β–€β–ˆ +β–ˆβ–€β–ˆΒ Β β–ˆβ–„β–€β–€β–€β–€β–„β–ˆβ–„β–„β–„β–„β–€β–€β–ˆβ–ˆβ–„β–ˆΒ Β β–€β–ˆβ–„Β β–€β–€β–€β–„Β β–€β–€β–€β–ˆβ–ˆ +β–ˆβ–„β–€β–ˆβ–€Β β–ˆβ–€β–€β–„Β β–€Β Β β–ˆΒ β–„β–ˆβ–„β–€β–€β–„Β β–ˆβ–€β–„β–ˆβ–€β–„β–„Β Β β–€Β β–ˆΒ Β β–ˆβ–ˆ +β–ˆΒ Β Β β–„Β Β β–€Β β–€Β β–€β–€Β Β β–„β–ˆΒ β–„β–„β–ˆβ–„β–ˆΒ β–€β–„β–„β–€β–ˆΒ β–„β–€Β Β β–„β–€β–„β–ˆβ–ˆ +β–ˆβ–„β–„β–„β–ˆβ–ˆβ–ˆβ–€β–ˆβ–„β–„β–ˆβ–„β–ˆβ–„Β β–€β–€Β β–€β–„β–ˆΒ β–€β–ˆβ–€β–ˆβ–„β–€Β β–€Β β–„β–„β–„Β β–€β–„β–ˆ +β–ˆβ–ˆβ–ˆβ–ˆβ–„β–€β–ˆβ–€β–€β–€Β β–„Β β–€β–ˆβ–€β–€β–ˆβ–„β–€β–ˆβ–€β–ˆβ–€Β β–ˆΒ β–„Β Β β–„β–€β–„β–„β–ˆβ–€β–ˆβ–„β–ˆ +β–ˆβ–€Β Β β–€β–„Β β–€β–„β–€β–€Β β–„Β β–„β–€β–ˆβ–€β–ˆβ–ˆβ–€β–„Β β–„β–„β–„β–„β–€β–„β–ˆβ–„β–€β–ˆβ–„β–€Β Β β–„β–ˆ +β–ˆβ–„β–ˆΒ Β β–„β–„β–€β–ˆβ–ˆΒ β–„Β β–ˆβ–ˆβ–€β–€β–ˆβ–„Β β–€β–„β–€β–„β–„Β β–€β–€β–ˆβ–€β–ˆβ–ˆβ–„β–„β–„Β β–ˆβ–ˆβ–ˆ +β–ˆβ–€β–€β–€Β Β β–„β–€β–ˆΒ Β β–ˆβ–ˆΒ β–€β–ˆβ–„β–„β–„β–ˆβ–€Β Β β–€β–ˆβ–„β–ˆβ–ˆβ–„β–€Β β–€Β β–€β–„β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ β–ˆβ–„Β β–€β–„Β β–„β–„β–€β–„β–ˆβ–ˆβ–€β–ˆΒ β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ β–„β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–„β–ˆβ–„β–„β–€β–€Β β–„β–„Β Β β–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–€β–€β–€Β β–€Β Β β–€β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆβ–ˆβ–„β–ˆβ–„β–€β–ˆβ–ˆΒ β–ˆβ–ˆβ–€Β β–ˆΒ β–„β–„β–„β–€β–„β–„Β Β Β β–ˆβ–€β–„β–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„Β Β β–ˆβ–€β–„β–€β–€β–€β–„Β β–ˆΒ β–€β–„Β β–ˆβ–€Β Β β–ˆβ–€β–ˆβ–€β–€β–€Β β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: V7B35TLT7GDE6YTNTKOVSZYQKZYOHL7U + +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 32B368AFCA3D5083 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 359933 [####----------------] 24s + +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAVzLg75hcxflhAsb40a8zQ4XSjJkKM3BHeRbyQaKsueE= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEILZ02RBE9nKkn75OkgJ6YRNkuREG29Q9+l7+WRw0ZZPW +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +slam jar during wild soda modify calm horn accuse theme mix hybrid +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub140hghu7f9yaf37yl89gq302gr4kk2jadkrlr3u59pwza320pt46shxm2w9 +nsec: nsec1e8036n7jjhrhmmzezzyv4wwghdnyn8vsflwzlasykkrxur0gnluqfes2r4 +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: A6A64916B6DA98ED727D00E4354185582B522511 +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdA8AMiSp5HKN12T6m75WfwjHXLIROO8hXnYhnf +dq51bOkAAPwPTlt95NMqOcTTZ7C1QAuHepY1IzgKbYySWhoxNI3R3Q7JzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBKamSRa22pjtcn0A5DVBhVgrUiUR +AAoJEDVBhVgrUiUR2XEBAMT3mtQhQzXDQn+I31qDeekJP3ac5LY9h4OZptN2Pzbb +AP9xuCMY44xpl2hK7DeJJCOqoqYwW//2rkNjT8Nm1zN7CQ== +=Yhiv +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: 32B368AFCA3D5083 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874976.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: WOw66\f>)cT3 +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874977.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 32B368AFCA3D5083 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups/entries_db_backup_1771874977.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 32B368AFCA3D5083 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 32B368AFCA3D5083 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 359933 [######--------------] 21s + +cSeed Profile: 32B368AFCA3D5083 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 32B368AFCA3D5083 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 8 + password: 1 + totp: 1 + ssh: 1 + seed: 1 + pgp: 1 + nostr: 1 + key_value: 1 + managed_account: 1 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-smqhylt4/.seedpass/32B368AFCA3D5083/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 32B368AFCA3D5083 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T193209Z/report.json b/artifacts/agent_tui_test/20260223T193209Z/report.json new file mode 100644 index 00000000..a8eabbec --- /dev/null +++ b/artifacts/agent_tui_test/20260223T193209Z/report.json @@ -0,0 +1,43 @@ +{ + "timestamp_utc": "20260223T193209Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-8gpm1yy3", + "duration_sec": 31.532, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 31.327574376002303, + "detail": null + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "invalid_input_resilience": true, + "add_password_quick": true, + "invalid_length_validation": true, + "add_totp": true, + "add_all_entry_types": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_codes_view": true, + "settings_toggles_lock_unlock": true, + "settings_stats": true, + "graceful_exit": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T193209Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T193209Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T193209Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T193209Z/transcript.clean.txt new file mode 100644 index 00000000..ab106367 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T193209Z/transcript.clean.txt @@ -0,0 +1,1065 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +apology siege evolve feel own exit field uncle project grief flavor receive +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +1 +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875132.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: Bj}3'K9n2Z(f + +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Bj}3'K9n2Z(f +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 52B987C68F3551B9 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 52B987C68F3551B9 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 52B987C68F3551B9 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 52B987C68F3551B9 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875132.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=F2TI4QSXGD7GDYWPQYUC7MNPH4T5UMG4&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–€β–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆβ–„β–€β–€Β Β β–€Β β–„β–€Β β–€Β β–€β–€Β β–ˆβ–„Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–ˆΒ β–„β–ˆβ–ˆβ–„β–ˆβ–ˆΒ β–€β–„β–€β–€Β β–€β–„Β Β β–€Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–„Β β–ˆΒ β–„β–€β–„Β β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€Β β–„Β β–€β–ˆβ–„Β Β Β β–„Β β–ˆβ–„β–„β–„β–„β–„β–ˆΒ β–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–ˆβ–„β–ˆβ–€β–ˆβ–„β–€Β Β β–„β–ˆβ–ˆΒ β–„β–ˆβ–€β–ˆβ–ˆβ–„Β Β β–„β–„β–ˆβ–„Β β–€β–€β–€β–„β–€β–„Β β–„Β β–„β–ˆβ–ˆ +β–ˆβ–€β–€Β β–„β–€β–„β–€β–ˆΒ β–ˆβ–„β–€β–„β–ˆβ–ˆβ–„Β β–€β–€β–ˆβ–ˆΒ β–€β–€β–„β–ˆβ–„β–ˆβ–„β–ˆΒ β–€β–ˆβ–ˆβ–ˆΒ β–€β–ˆ +β–ˆβ–„Β β–€β–€Β β–€β–€Β β–ˆβ–€Β β–„β–„β–€β–€β–ˆβ–„β–€β–„β–ˆβ–„β–ˆΒ Β β–€β–ˆβ–„Β β–€β–€β–ˆβ–„Β β–€β–€β–ˆβ–€β–ˆ +β–ˆΒ β–„Β Β β–„β–ˆβ–€β–€β–ˆβ–€β–„β–„β–ˆβ–ˆβ–„Β β–ˆβ–„β–€β–€β–„Β β–ˆβ–€β–„β–ˆβ–€β–„β–„β–„β–€β–ˆΒ β–ˆΒ β–„β–„β–ˆ +β–ˆΒ β–„β–€β–€β–„β–ˆβ–€β–€β–„β–ˆβ–€β–ˆβ–€β–€β–„β–ˆΒ β–€Β β–ˆβ–„β–ˆΒ β–€β–„β–„β–€β–„β–€β–„Β β–„Β Β Β β–„β–ˆβ–ˆ +β–ˆβ–€Β Β β–ˆΒ Β β–€Β β–„β–„Β β–€β–„β–ˆβ–„β–€β–ˆβ–€Β β–„β–ˆΒ β–€β–ˆβ–€β–ˆβ–„β–ˆβ–€β–€Β β–„β–ˆΒ β–€β–€β–„β–ˆ +β–ˆβ–ˆβ–€Β β–€β–€β–„β–€β–€β–„β–„β–€Β β–€Β Β β–„β–€β–„Β β–ˆβ–€β–ˆβ–€Β β–ˆΒ β–„Β Β Β β–€β–„β–„β–ˆβ–€Β Β β–ˆ +β–ˆΒ β–„β–€β–„β–„β–€β–€β–€β–„Β β–€β–„Β β–„Β β–ˆβ–€β–ˆβ–ˆβ–€β–„Β β–„β–„β–„β–„β–€β–„β–€β–„Β β–€Β β–€Β Β Β β–ˆ +β–ˆβ–„β–„β–ˆβ–€Β β–ˆβ–€Β Β β–„Β Β Β β–„β–€β–€β–ˆβ–€Β β–€β–„β–€β–„β–„Β β–€β–€β–€β–ˆβ–„β–ˆβ–€β–„Β β–€β–ˆβ–ˆβ–ˆ +β–ˆβ–€β–€β–„β–„β–„Β β–€β–ˆΒ β–„Β β–€β–„Β Β β–„β–„Β β–„β–€Β Β β–€β–ˆβ–„β–ˆβ–ˆβ–ˆβ–€Β β–€Β β–€β–„β–€β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ Β Β β–€Β Β β–ˆβ–ˆβ–€β–€β–„β–ˆβ–ˆβ–€β–ˆΒ β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ β–„β–€Β Β β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€Β β–€β–€β–ˆβ–„β–„β–€β–„β–„Β Β β–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–€β–€β–€Β β–€Β β–„Β β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆβ–€β–€β–€β–ˆβ–ˆβ–„β–ˆΒ β–ˆβ–ˆβ–€Β β–ˆΒ β–„β–„β–„β–€β–„β–„Β Β Β β–ˆβ–€β–„β–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€Β β–„β–„β–€β–€Β β–€β–€Β Β Β β–ˆΒ β–€β–„Β β–ˆβ–€β–€β–„β–€Β β–ˆβ–€β–ˆβ–„Β β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: F2TI4QSXGD7GDYWPQYUC7MNPH4T5UMG4 + +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 52B987C68F3551B9 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 52B987C68F3551B9 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 652260 [########------------] 18s + +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875132.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEASfSEohRNKx2RUFyC0tap0ZzeQ6FCUaiKZsqqLRUvwIY= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIGFCkanjD+YfbgLk8pO11fv1cPODLaN4mhuuA2SJsTjh +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875132.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +moment broccoli front video shallow air funny resist evidence filter bracket nose +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875132.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub1pvf0tal68hu3ux6zhepawpwq2r0jguun2kp9x8s0u03gelhsf96q2ntxnv +nsec: nsec12enf2q0zpf5fy9eqc0h44t4dhlf5jdl6ln4q2sey7dt9yn2ry9sqj4dku6 +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875132.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 92574CF8A9B160EDEAE3357A2C987729801EE64B +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdA7RTS1NDNWkkAZT1y56qZhhgXRe1WUoAdBQ+r +7z/ZidoAAP92MM8pA0P60Ysemrn7BqpHQU3y3NaGk4MAanoxdVz99BFBzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBJJXTPipsWDt6uM1eiyYdymAHuZL +AAoJECyYdymAHuZLK3gA/iRd7FiaIyhSHMTTN8HWE0FFvGoUfBOgWPpnnt01gWW3 +AQDcE3Q+Ngaux+3YENFIFHznU59+nKoEaDKCO2wu3ARHDw== +=J3OZ +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875132.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875132.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 52B987C68F3551B9 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 52B987C68F3551B9 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: 52B987C68F3551B9 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875133.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Bj}3'K9n2Z(f +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875133.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 52B987C68F3551B9 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875133.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 52B987C68F3551B9 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 52B987C68F3551B9 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 652260 [##########----------] 15s + +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 52B987C68F3551B9 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 8 + password: 1 + totp: 1 + ssh: 1 + seed: 1 + pgp: 1 + nostr: 1 + key_value: 1 + managed_account: 1 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 52B987C68F3551B9 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T193209Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T193209Z/transcript.raw.txt new file mode 100644 index 00000000..0ee4f78e --- /dev/null +++ b/artifacts/agent_tui_test/20260223T193209Z/transcript.raw.txt @@ -0,0 +1,1066 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +apology siege evolve feel own exit field uncle project grief flavor receive +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +1 +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875132.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: Bj}3'K9n2Z(f + +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Bj}3'K9n2Z(f +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 52B987C68F3551B9 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 52B987C68F3551B9 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 52B987C68F3551B9 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 52B987C68F3551B9 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875132.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=F2TI4QSXGD7GDYWPQYUC7MNPH4T5UMG4&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–€β–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆβ–„β–€β–€Β Β β–€Β β–„β–€Β β–€Β β–€β–€Β β–ˆβ–„Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–ˆΒ β–„β–ˆβ–ˆβ–„β–ˆβ–ˆΒ β–€β–„β–€β–€Β β–€β–„Β Β β–€Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–„Β β–ˆΒ β–„β–€β–„Β β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€Β β–„Β β–€β–ˆβ–„Β Β Β β–„Β β–ˆβ–„β–„β–„β–„β–„β–ˆΒ β–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–ˆβ–„β–ˆβ–€β–ˆβ–„β–€Β Β β–„β–ˆβ–ˆΒ β–„β–ˆβ–€β–ˆβ–ˆβ–„Β Β β–„β–„β–ˆβ–„Β β–€β–€β–€β–„β–€β–„Β β–„Β β–„β–ˆβ–ˆ +β–ˆβ–€β–€Β β–„β–€β–„β–€β–ˆΒ β–ˆβ–„β–€β–„β–ˆβ–ˆβ–„Β β–€β–€β–ˆβ–ˆΒ β–€β–€β–„β–ˆβ–„β–ˆβ–„β–ˆΒ β–€β–ˆβ–ˆβ–ˆΒ β–€β–ˆ +β–ˆβ–„Β β–€β–€Β β–€β–€Β β–ˆβ–€Β β–„β–„β–€β–€β–ˆβ–„β–€β–„β–ˆβ–„β–ˆΒ Β β–€β–ˆβ–„Β β–€β–€β–ˆβ–„Β β–€β–€β–ˆβ–€β–ˆ +β–ˆΒ β–„Β Β β–„β–ˆβ–€β–€β–ˆβ–€β–„β–„β–ˆβ–ˆβ–„Β β–ˆβ–„β–€β–€β–„Β β–ˆβ–€β–„β–ˆβ–€β–„β–„β–„β–€β–ˆΒ β–ˆΒ β–„β–„β–ˆ +β–ˆΒ β–„β–€β–€β–„β–ˆβ–€β–€β–„β–ˆβ–€β–ˆβ–€β–€β–„β–ˆΒ β–€Β β–ˆβ–„β–ˆΒ β–€β–„β–„β–€β–„β–€β–„Β β–„Β Β Β β–„β–ˆβ–ˆ +β–ˆβ–€Β Β β–ˆΒ Β β–€Β β–„β–„Β β–€β–„β–ˆβ–„β–€β–ˆβ–€Β β–„β–ˆΒ β–€β–ˆβ–€β–ˆβ–„β–ˆβ–€β–€Β β–„β–ˆΒ β–€β–€β–„β–ˆ +β–ˆβ–ˆβ–€Β β–€β–€β–„β–€β–€β–„β–„β–€Β β–€Β Β β–„β–€β–„Β β–ˆβ–€β–ˆβ–€Β β–ˆΒ β–„Β Β Β β–€β–„β–„β–ˆβ–€Β Β β–ˆ +β–ˆΒ β–„β–€β–„β–„β–€β–€β–€β–„Β β–€β–„Β β–„Β β–ˆβ–€β–ˆβ–ˆβ–€β–„Β β–„β–„β–„β–„β–€β–„β–€β–„Β β–€Β β–€Β Β Β β–ˆ +β–ˆβ–„β–„β–ˆβ–€Β β–ˆβ–€Β Β β–„Β Β Β β–„β–€β–€β–ˆβ–€Β β–€β–„β–€β–„β–„Β β–€β–€β–€β–ˆβ–„β–ˆβ–€β–„Β β–€β–ˆβ–ˆβ–ˆ +β–ˆβ–€β–€β–„β–„β–„Β β–€β–ˆΒ β–„Β β–€β–„Β Β β–„β–„Β β–„β–€Β Β β–€β–ˆβ–„β–ˆβ–ˆβ–ˆβ–€Β β–€Β β–€β–„β–€β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ Β Β β–€Β Β β–ˆβ–ˆβ–€β–€β–„β–ˆβ–ˆβ–€β–ˆΒ β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ β–„β–€Β Β β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€Β β–€β–€β–ˆβ–„β–„β–€β–„β–„Β Β β–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–€β–€β–€Β β–€Β β–„Β β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆβ–€β–€β–€β–ˆβ–ˆβ–„β–ˆΒ β–ˆβ–ˆβ–€Β β–ˆΒ β–„β–„β–„β–€β–„β–„Β Β Β β–ˆβ–€β–„β–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€Β β–„β–„β–€β–€Β β–€β–€Β Β Β β–ˆΒ β–€β–„Β β–ˆβ–€β–€β–„β–€Β β–ˆβ–€β–ˆβ–„Β β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: F2TI4QSXGD7GDYWPQYUC7MNPH4T5UMG4 + +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 52B987C68F3551B9 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 52B987C68F3551B9 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 652260 [########------------] 18s + +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875132.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEASfSEohRNKx2RUFyC0tap0ZzeQ6FCUaiKZsqqLRUvwIY= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIGFCkanjD+YfbgLk8pO11fv1cPODLaN4mhuuA2SJsTjh +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875132.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +moment broccoli front video shallow air funny resist evidence filter bracket nose +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875132.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub1pvf0tal68hu3ux6zhepawpwq2r0jguun2kp9x8s0u03gelhsf96q2ntxnv +nsec: nsec12enf2q0zpf5fy9eqc0h44t4dhlf5jdl6ln4q2sey7dt9yn2ry9sqj4dku6 +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875132.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 92574CF8A9B160EDEAE3357A2C987729801EE64B +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdA7RTS1NDNWkkAZT1y56qZhhgXRe1WUoAdBQ+r +7z/ZidoAAP92MM8pA0P60Ysemrn7BqpHQU3y3NaGk4MAanoxdVz99BFBzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBJJXTPipsWDt6uM1eiyYdymAHuZL +AAoJECyYdymAHuZLK3gA/iRd7FiaIyhSHMTTN8HWE0FFvGoUfBOgWPpnnt01gWW3 +AQDcE3Q+Ngaux+3YENFIFHznU59+nKoEaDKCO2wu3ARHDw== +=J3OZ +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875132.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875132.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 52B987C68F3551B9 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 52B987C68F3551B9 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: 52B987C68F3551B9 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875133.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Bj}3'K9n2Z(f +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875133.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 52B987C68F3551B9 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 52B987C68F3551B9 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups/entries_db_backup_1771875133.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 52B987C68F3551B9 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 52B987C68F3551B9 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 652260 [##########----------] 15s + +cSeed Profile: 52B987C68F3551B9 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 52B987C68F3551B9 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 8 + password: 1 + totp: 1 + ssh: 1 + seed: 1 + pgp: 1 + nostr: 1 + key_value: 1 + managed_account: 1 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-8gpm1yy3/.seedpass/52B987C68F3551B9/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 52B987C68F3551B9 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T194108Z/report.json b/artifacts/agent_tui_test/20260223T194108Z/report.json new file mode 100644 index 00000000..83a58626 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T194108Z/report.json @@ -0,0 +1,43 @@ +{ + "timestamp_utc": "20260223T194108Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-6_btm3dg", + "duration_sec": 31.632, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "full_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 31.35093792200132, + "detail": null + } + ], + "coverage_points": { + "startup_onboarding": true, + "main_menu": true, + "invalid_input_resilience": true, + "add_password_quick": true, + "invalid_length_validation": true, + "add_totp": true, + "add_all_entry_types": true, + "retrieve_entry": true, + "search_entries": true, + "list_entries": true, + "modify_entry": true, + "archive_restore": true, + "totp_codes_view": true, + "settings_toggles_lock_unlock": true, + "settings_stats": true, + "graceful_exit": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T194108Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T194108Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T194108Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T194108Z/transcript.clean.txt new file mode 100644 index 00000000..9100e3f9 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T194108Z/transcript.clean.txt @@ -0,0 +1,1065 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +broccoli quarter pony light glory extra finish extra march medal alcohol dumb +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +1 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875671.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: 0.NykJ0eN"[0 + +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 0.NykJ0eN"[0 +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=5JGBQJG43XITAYJAYOBWFJVLVVBD42VH&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–€β–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–€β–€β–€β–ˆβ–€β–€β–€β–ˆβ–€β–€β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–„β–ˆβ–„β–ˆβ–ˆβ–„β–ˆΒ β–€β–€β–„β–€Β Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€β–€Β β–€β–ˆβ–€Β β–„β–€β–ˆΒ Β Β β–„Β β–„β–ˆβ–„β–€β–„Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„Β β–ˆΒ β–ˆΒ β–„β–€β–ˆΒ β–ˆΒ β–ˆΒ β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–€β–„β–ˆβ–€β–€β–€β–„β–ˆβ–€β–„β–€β–€β–€β–ˆβ–ˆβ–„β–ˆβ–„Β β–€β–ˆβ–ˆβ–€β–ˆβ–€β–€β–€β–ˆ +β–ˆΒ Β β–€Β β–„β–ˆβ–€β–€β–ˆβ–€β–„β–„Β β–€β–€β–€Β β–€Β β–€β–„β–„β–€β–ˆΒ β–€β–ˆβ–€β–„β–„β–„β–„Β β–ˆβ–€β–„β–€β–ˆ +β–ˆβ–€β–ˆβ–€β–„β–„β–ˆβ–€Β β–„β–€β–€β–ˆβ–€β–€β–ˆβ–€Β β–ˆβ–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„Β Β β–€β–€Β β–ˆβ–€Β β–„Β β–ˆ +β–ˆΒ β–€β–ˆβ–ˆβ–„β–„β–€β–„β–€β–€β–„β–ˆΒ β–„β–„β–ˆβ–€β–ˆβ–€β–€β–„β–ˆΒ β–„β–ˆβ–€β–„Β β–€β–ˆβ–ˆΒ Β β–€β–€β–„Β β–ˆ +β–ˆβ–„Β β–€β–„β–€β–€β–€β–ˆβ–„β–„β–„Β β–ˆΒ β–ˆβ–„β–„β–€Β β–ˆβ–ˆβ–ˆβ–ˆβ–„β–ˆβ–€Β β–€β–„Β Β β–ˆβ–€Β Β Β β–„β–ˆ +β–ˆβ–ˆΒ β–ˆβ–„Β β–€β–€β–€β–€β–ˆβ–ˆΒ β–„Β β–ˆβ–ˆβ–€Β β–„Β β–€β–ˆβ–€Β Β β–€β–„Β Β β–„β–ˆΒ β–„Β β–ˆβ–ˆβ–€β–ˆ +β–ˆΒ β–€β–ˆΒ β–€Β β–€β–„β–€Β β–ˆβ–€β–„β–ˆβ–ˆβ–„Β β–ˆβ–„β–ˆΒ β–ˆβ–„β–„Β β–„β–€β–ˆβ–„Β β–€β–„β–€β–ˆβ–€Β β–ˆβ–ˆ +β–ˆβ–ˆβ–ˆβ–€β–€Β β–ˆβ–€β–€β–„β–ˆβ–„Β β–„β–€Β β–€β–„β–„β–ˆβ–„β–ˆβ–ˆβ–„Β β–€β–€Β Β β–ˆΒ β–€β–ˆΒ β–ˆβ–„β–„β–€β–ˆ +β–ˆβ–€β–ˆβ–„Β Β β–ˆβ–€β–€β–„β–„β–€β–„Β Β Β β–„β–„β–€β–„β–€β–„β–ˆΒ Β β–ˆβ–„β–€β–€β–€β–ˆβ–ˆβ–ˆΒ β–„β–„β–„β–ˆβ–ˆ +β–ˆΒ β–€β–„Β β–ˆβ–„β–€β–ˆΒ β–€β–„β–ˆβ–ˆβ–„Β β–€β–ˆΒ Β β–ˆβ–„β–€β–„Β β–„β–ˆβ–€β–„β–ˆΒ β–€β–€β–€β–€β–ˆβ–€β–€β–ˆ +β–ˆΒ β–ˆβ–€Β β–ˆβ–ˆβ–€β–„β–ˆβ–ˆβ–€β–€β–€Β β–€β–€β–„β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€Β β–ˆβ–€β–„β–ˆβ–€β–€Β β–€β–€Β β–„Β Β β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ β–„β–„Β Β β–„β–€Β β–ˆΒ β–€Β Β β–€β–„β–€β–ˆΒ Β β–„Β β–ˆβ–€β–ˆΒ β–„Β Β β–„β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆΒ β–€β–„β–ˆβ–ˆβ–„β–„β–€Β β–ˆβ–€β–€Β β–„β–€β–€β–ˆβ–„β–ˆΒ Β β–€β–€β–€Β β–„β–ˆβ–€β–€β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–„β–„β–€Β β–ˆΒ β–„β–ˆβ–ˆβ–ˆβ–€Β β–„β–ˆβ–ˆβ–„Β β–ˆβ–ˆβ–„β–€Β β–„β–€β–€β–ˆβ–„β–€β–€β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–ˆΒ β–€Β β–„β–€β–„β–ˆβ–€Β Β β–ˆβ–ˆβ–ˆΒ β–€β–ˆβ–€β–€β–€Β β–€β–ˆβ–€Β β–ˆβ–„Β β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: 5JGBQJG43XITAYJAYOBWFJVLVVBD42VH + +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 379220 [########------------] 18s + +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEA1Fk04VEhMXGDavT5dDzTBBQoCPYvrm5U6iM2Sf4R92Y= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIJZSs84cjYCN3n4eJ+1tKu6INyBVHbEXNQ75R0bjOlwo +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +borrow music pretty call approve attack oxygen century actual fabric pool law +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub1mp5g9md5zm9dc98x3y9glq4u8c6jfs2meggd048tnadmwv9f3cxsfj05rh +nsec: nsec1j50e4ed24scmhgdf602368pv79detezv29g4l0n5j6r6zapppqes8gu0f4 +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 5EAA5BE52CF2DC03CEBE0B5065356A5B77E258AA +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdALlay/yEaPb6HMZTrdgqCxZpU6Q0eHH7QVuFG +WuOiPd0AAP9nxtQpwN4eqDTwjtu0FzkrDT359JbLXOlX/2Q5IG3HvxIszQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBF6qW+Us8twDzr4LUGU1alt34liq +AAoJEGU1alt34liqAAMBANkVMu28T1ud4+tgqcKoCei7DJJqufJbb53Pn3ZpfkAr +AQDUp9qN05Y83Y9BcBMfhxYvujjvSUGdleQywz/3dhbMAQ== +=5y+X +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 0.NykJ0eN"[0 +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: FFD7893D5FFBFBCB > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 379220 [#########-----------] 16s + +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 8 + password: 1 + totp: 1 + ssh: 1 + seed: 1 + pgp: 1 + nostr: 1 + key_value: 1 + managed_account: 1 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T194108Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T194108Z/transcript.raw.txt new file mode 100644 index 00000000..fd3909c5 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T194108Z/transcript.raw.txt @@ -0,0 +1,1066 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +broccoli quarter pony light glory extra finish extra march medal alcohol dumb +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +1 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875671.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: 0.NykJ0eN"[0 + +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 0.NykJ0eN"[0 +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=5JGBQJG43XITAYJAYOBWFJVLVVBD42VH&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–€β–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–€β–€β–€β–ˆβ–€β–€β–€β–ˆβ–€β–€β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–„β–ˆβ–„β–ˆβ–ˆβ–„β–ˆΒ β–€β–€β–„β–€Β Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€β–€Β β–€β–ˆβ–€Β β–„β–€β–ˆΒ Β Β β–„Β β–„β–ˆβ–„β–€β–„Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„Β β–ˆΒ β–ˆΒ β–„β–€β–ˆΒ β–ˆΒ β–ˆΒ β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–€β–„β–ˆβ–€β–€β–€β–„β–ˆβ–€β–„β–€β–€β–€β–ˆβ–ˆβ–„β–ˆβ–„Β β–€β–ˆβ–ˆβ–€β–ˆβ–€β–€β–€β–ˆ +β–ˆΒ Β β–€Β β–„β–ˆβ–€β–€β–ˆβ–€β–„β–„Β β–€β–€β–€Β β–€Β β–€β–„β–„β–€β–ˆΒ β–€β–ˆβ–€β–„β–„β–„β–„Β β–ˆβ–€β–„β–€β–ˆ +β–ˆβ–€β–ˆβ–€β–„β–„β–ˆβ–€Β β–„β–€β–€β–ˆβ–€β–€β–ˆβ–€Β β–ˆβ–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„Β Β β–€β–€Β β–ˆβ–€Β β–„Β β–ˆ +β–ˆΒ β–€β–ˆβ–ˆβ–„β–„β–€β–„β–€β–€β–„β–ˆΒ β–„β–„β–ˆβ–€β–ˆβ–€β–€β–„β–ˆΒ β–„β–ˆβ–€β–„Β β–€β–ˆβ–ˆΒ Β β–€β–€β–„Β β–ˆ +β–ˆβ–„Β β–€β–„β–€β–€β–€β–ˆβ–„β–„β–„Β β–ˆΒ β–ˆβ–„β–„β–€Β β–ˆβ–ˆβ–ˆβ–ˆβ–„β–ˆβ–€Β β–€β–„Β Β β–ˆβ–€Β Β Β β–„β–ˆ +β–ˆβ–ˆΒ β–ˆβ–„Β β–€β–€β–€β–€β–ˆβ–ˆΒ β–„Β β–ˆβ–ˆβ–€Β β–„Β β–€β–ˆβ–€Β Β β–€β–„Β Β β–„β–ˆΒ β–„Β β–ˆβ–ˆβ–€β–ˆ +β–ˆΒ β–€β–ˆΒ β–€Β β–€β–„β–€Β β–ˆβ–€β–„β–ˆβ–ˆβ–„Β β–ˆβ–„β–ˆΒ β–ˆβ–„β–„Β β–„β–€β–ˆβ–„Β β–€β–„β–€β–ˆβ–€Β β–ˆβ–ˆ +β–ˆβ–ˆβ–ˆβ–€β–€Β β–ˆβ–€β–€β–„β–ˆβ–„Β β–„β–€Β β–€β–„β–„β–ˆβ–„β–ˆβ–ˆβ–„Β β–€β–€Β Β β–ˆΒ β–€β–ˆΒ β–ˆβ–„β–„β–€β–ˆ +β–ˆβ–€β–ˆβ–„Β Β β–ˆβ–€β–€β–„β–„β–€β–„Β Β Β β–„β–„β–€β–„β–€β–„β–ˆΒ Β β–ˆβ–„β–€β–€β–€β–ˆβ–ˆβ–ˆΒ β–„β–„β–„β–ˆβ–ˆ +β–ˆΒ β–€β–„Β β–ˆβ–„β–€β–ˆΒ β–€β–„β–ˆβ–ˆβ–„Β β–€β–ˆΒ Β β–ˆβ–„β–€β–„Β β–„β–ˆβ–€β–„β–ˆΒ β–€β–€β–€β–€β–ˆβ–€β–€β–ˆ +β–ˆΒ β–ˆβ–€Β β–ˆβ–ˆβ–€β–„β–ˆβ–ˆβ–€β–€β–€Β β–€β–€β–„β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€Β β–ˆβ–€β–„β–ˆβ–€β–€Β β–€β–€Β β–„Β Β β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ β–„β–„Β Β β–„β–€Β β–ˆΒ β–€Β Β β–€β–„β–€β–ˆΒ Β β–„Β β–ˆβ–€β–ˆΒ β–„Β Β β–„β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆΒ β–€β–„β–ˆβ–ˆβ–„β–„β–€Β β–ˆβ–€β–€Β β–„β–€β–€β–ˆβ–„β–ˆΒ Β β–€β–€β–€Β β–„β–ˆβ–€β–€β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–„β–„β–€Β β–ˆΒ β–„β–ˆβ–ˆβ–ˆβ–€Β β–„β–ˆβ–ˆβ–„Β β–ˆβ–ˆβ–„β–€Β β–„β–€β–€β–ˆβ–„β–€β–€β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–ˆΒ β–€Β β–„β–€β–„β–ˆβ–€Β Β β–ˆβ–ˆβ–ˆΒ β–€β–ˆβ–€β–€β–€Β β–€β–ˆβ–€Β β–ˆβ–„Β β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: 5JGBQJG43XITAYJAYOBWFJVLVVBD42VH + +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 379220 [########------------] 18s + +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEA1Fk04VEhMXGDavT5dDzTBBQoCPYvrm5U6iM2Sf4R92Y= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIJZSs84cjYCN3n4eJ+1tKu6INyBVHbEXNQ75R0bjOlwo +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +borrow music pretty call approve attack oxygen century actual fabric pool law +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub1mp5g9md5zm9dc98x3y9glq4u8c6jfs2meggd048tnadmwv9f3cxsfj05rh +nsec: nsec1j50e4ed24scmhgdf602368pv79detezv29g4l0n5j6r6zapppqes8gu0f4 +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 5EAA5BE52CF2DC03CEBE0B5065356A5B77E258AA +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdALlay/yEaPb6HMZTrdgqCxZpU6Q0eHH7QVuFG +WuOiPd0AAP9nxtQpwN4eqDTwjtu0FzkrDT359JbLXOlX/2Q5IG3HvxIszQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBF6qW+Us8twDzr4LUGU1alt34liq +AAoJEGU1alt34liqAAMBANkVMu28T1ud4+tgqcKoCei7DJJqufJbb53Pn3ZpfkAr +AQDUp9qN05Y83Y9BcBMfhxYvujjvSUGdleQywz/3dhbMAQ== +=5y+X +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 0.NykJ0eN"[0 +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: FFD7893D5FFBFBCB > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups/entries_db_backup_1771875672.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: FFD7893D5FFBFBCB > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 379220 [#########-----------] 16s + +cSeed Profile: FFD7893D5FFBFBCB > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 8 + password: 1 + totp: 1 + ssh: 1 + seed: 1 + pgp: 1 + nostr: 1 + key_value: 1 + managed_account: 1 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-6_btm3dg/.seedpass/FFD7893D5FFBFBCB/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: FFD7893D5FFBFBCB > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T194623Z/report.json b/artifacts/agent_tui_test/20260223T194623Z/report.json new file mode 100644 index 00000000..d71582b7 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T194623Z/report.json @@ -0,0 +1,57 @@ +{ + "timestamp_utc": "20260223T194623Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-5b_un_86", + "scenario": "core", + "stress_cycles": null, + "required_coverage_keys": [ + "startup_onboarding", + "main_menu", + "invalid_input_resilience", + "add_password_quick", + "invalid_length_validation", + "retrieve_entry", + "search_entries", + "list_entries", + "graceful_exit" + ], + "duration_sec": 3.148, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "core_scenario", + "description": "Drive deterministic core TUI scenario.", + "status": "passed", + "duration_sec": 3.0497409279996646, + "detail": null + } + ], + "coverage_points": { + "add_all_entry_types": false, + "add_password_quick": true, + "add_totp": false, + "archive_restore": false, + "graceful_exit": true, + "invalid_input_resilience": true, + "invalid_length_validation": true, + "list_entries": true, + "main_menu": true, + "modify_entry": false, + "retrieve_entry": true, + "search_entries": true, + "settings_stats": false, + "settings_toggles_lock_unlock": false, + "startup_onboarding": true, + "stress_cycles": false, + "totp_codes_view": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T194623Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T194623Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T194623Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T194623Z/transcript.clean.txt new file mode 100644 index 00000000..3c750bfd --- /dev/null +++ b/artifacts/agent_tui_test/20260223T194623Z/transcript.clean.txt @@ -0,0 +1,287 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +steak youth kit dune invite veteran risk silk slab kitten prevent tissue +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-5b_un_86/.seedpass/A3193D9EA565C619/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: A3193D9EA565C619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: A3193D9EA565C619 > Main Menu +1 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: A3193D9EA565C619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: A3193D9EA565C619 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: A3193D9EA565C619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: A3193D9EA565C619 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-5b_un_86/.seedpass/A3193D9EA565C619/backups/entries_db_backup_1771875985.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: (!QD1m7Kg4f{ + +Press Enter to continue... +cSeed Profile: A3193D9EA565C619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: A3193D9EA565C619 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: (!QD1m7Kg4f{ +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: A3193D9EA565C619 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: A3193D9EA565C619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: A3193D9EA565C619 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: A3193D9EA565C619 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: A3193D9EA565C619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: A3193D9EA565C619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: A3193D9EA565C619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: A3193D9EA565C619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: A3193D9EA565C619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T194623Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T194623Z/transcript.raw.txt new file mode 100644 index 00000000..fa3e0187 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T194623Z/transcript.raw.txt @@ -0,0 +1,288 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +steak youth kit dune invite veteran risk silk slab kitten prevent tissue +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-5b_un_86/.seedpass/A3193D9EA565C619/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: A3193D9EA565C619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: A3193D9EA565C619 > Main Menu +1 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: A3193D9EA565C619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: A3193D9EA565C619 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: A3193D9EA565C619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: A3193D9EA565C619 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-5b_un_86/.seedpass/A3193D9EA565C619/backups/entries_db_backup_1771875985.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: (!QD1m7Kg4f{ + +Press Enter to continue... +cSeed Profile: A3193D9EA565C619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: A3193D9EA565C619 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: (!QD1m7Kg4f{ +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: A3193D9EA565C619 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: A3193D9EA565C619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: A3193D9EA565C619 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: A3193D9EA565C619 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: A3193D9EA565C619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: A3193D9EA565C619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: A3193D9EA565C619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: A3193D9EA565C619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: A3193D9EA565C619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T194629Z/report.json b/artifacts/agent_tui_test/20260223T194629Z/report.json new file mode 100644 index 00000000..83b88467 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T194629Z/report.json @@ -0,0 +1,56 @@ +{ + "timestamp_utc": "20260223T194629Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-h0n1d15e", + "scenario": "stress", + "stress_cycles": 2, + "required_coverage_keys": [ + "startup_onboarding", + "main_menu", + "add_password_quick", + "invalid_input_resilience", + "retrieve_entry", + "list_entries", + "stress_cycles", + "graceful_exit" + ], + "duration_sec": 3.64, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "stress_scenario", + "description": "Drive deterministic stress TUI scenario.", + "status": "passed", + "duration_sec": 3.4461189139983617, + "detail": null + } + ], + "coverage_points": { + "add_all_entry_types": false, + "add_password_quick": true, + "add_totp": false, + "archive_restore": false, + "graceful_exit": true, + "invalid_input_resilience": true, + "invalid_length_validation": false, + "list_entries": true, + "main_menu": true, + "modify_entry": false, + "retrieve_entry": true, + "search_entries": false, + "settings_stats": false, + "settings_toggles_lock_unlock": false, + "startup_onboarding": true, + "stress_cycles": true, + "totp_codes_view": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T194629Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T194629Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T194629Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T194629Z/transcript.clean.txt new file mode 100644 index 00000000..a0d1d28a --- /dev/null +++ b/artifacts/agent_tui_test/20260223T194629Z/transcript.clean.txt @@ -0,0 +1,424 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +rack merit rack mosquito tongue photo ordinary biology angle work auto slam +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-h0n1d15e/.seedpass/8FA75CB2801664A2/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: stress.example +Enter the username (optional): stress +Enter the URL (optional): https://stress.example +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-h0n1d15e/.seedpass/8FA75CB2801664A2/backups/entries_db_backup_1771875992.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for stress.example: 49j>9'tU$eRT + +Press Enter to continue... +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - stress.example +Enter index to view details or press Enter to go back: +cSeed Profile: 8FA75CB2801664A2 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'stress.example' with length 12. +Username: stress +URL: https://stress.example + +[+] Retrieved Password for stress.example: + +Password: 49j>9'tU$eRT +Associated Username: stress +Associated URL: https://stress.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 8FA75CB2801664A2 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 8FA75CB2801664A2 > Main Menu +1 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - stress.example +Enter index to view details or press Enter to go back: +cSeed Profile: 8FA75CB2801664A2 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'stress.example' with length 12. +Username: stress +URL: https://stress.example + +[+] Retrieved Password for stress.example: + +Password: 49j>9'tU$eRT +Associated Username: stress +Associated URL: https://stress.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 8FA75CB2801664A2 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T194629Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T194629Z/transcript.raw.txt new file mode 100644 index 00000000..c594cc86 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T194629Z/transcript.raw.txt @@ -0,0 +1,425 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +rack merit rack mosquito tongue photo ordinary biology angle work auto slam +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-h0n1d15e/.seedpass/8FA75CB2801664A2/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: stress.example +Enter the username (optional): stress +Enter the URL (optional): https://stress.example +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-h0n1d15e/.seedpass/8FA75CB2801664A2/backups/entries_db_backup_1771875992.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for stress.example: 49j>9'tU$eRT + +Press Enter to continue... +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - stress.example +Enter index to view details or press Enter to go back: +cSeed Profile: 8FA75CB2801664A2 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'stress.example' with length 12. +Username: stress +URL: https://stress.example + +[+] Retrieved Password for stress.example: + +Password: 49j>9'tU$eRT +Associated Username: stress +Associated URL: https://stress.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 8FA75CB2801664A2 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 8FA75CB2801664A2 > Main Menu +1 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - stress.example +Enter index to view details or press Enter to go back: +cSeed Profile: 8FA75CB2801664A2 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 8FA75CB2801664A2 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'stress.example' with length 12. +Username: stress +URL: https://stress.example + +[+] Retrieved Password for stress.example: + +Password: 49j>9'tU$eRT +Associated Username: stress +Associated URL: https://stress.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 8FA75CB2801664A2 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 8FA75CB2801664A2 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T194637Z/report.json b/artifacts/agent_tui_test/20260223T194637Z/report.json new file mode 100644 index 00000000..b16a605f --- /dev/null +++ b/artifacts/agent_tui_test/20260223T194637Z/report.json @@ -0,0 +1,64 @@ +{ + "timestamp_utc": "20260223T194637Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-_qbephpj", + "scenario": "extended", + "stress_cycles": null, + "required_coverage_keys": [ + "startup_onboarding", + "main_menu", + "invalid_input_resilience", + "add_password_quick", + "invalid_length_validation", + "add_totp", + "add_all_entry_types", + "retrieve_entry", + "search_entries", + "list_entries", + "modify_entry", + "archive_restore", + "totp_codes_view", + "settings_toggles_lock_unlock", + "settings_stats", + "graceful_exit" + ], + "duration_sec": 31.822, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "extended_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 31.38411183700009, + "detail": null + } + ], + "coverage_points": { + "add_all_entry_types": true, + "add_password_quick": true, + "add_totp": true, + "archive_restore": true, + "graceful_exit": true, + "invalid_input_resilience": true, + "invalid_length_validation": true, + "list_entries": true, + "main_menu": true, + "modify_entry": true, + "retrieve_entry": true, + "search_entries": true, + "settings_stats": true, + "settings_toggles_lock_unlock": true, + "startup_onboarding": true, + "stress_cycles": false, + "totp_codes_view": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T194637Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T194637Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T194637Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T194637Z/transcript.clean.txt new file mode 100644 index 00000000..06f18caf --- /dev/null +++ b/artifacts/agent_tui_test/20260223T194637Z/transcript.clean.txt @@ -0,0 +1,1065 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +purpose lend width float mosquito vanish excuse vault advance when recipe only +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings.1 + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: F186D62372FF1635 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: F186D62372FF1635 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: iy3l^40N:N)N + +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: F186D62372FF1635 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: iy3l^40N:N)N +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: F186D62372FF1635 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: F186D62372FF1635 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: F186D62372FF1635 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: F186D62372FF1635 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: F186D62372FF1635 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: F186D62372FF1635 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=FAW6M5CM42UJDN6A7LN6N77AD4CNH2LQ&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–€β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆΒ β–„Β Β β–€β–ˆβ–„β–„β–€Β β–€Β β–€β–€Β β–ˆβ–„Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–ˆΒ β–ˆβ–€β–„β–ˆβ–„β–„Β β–€β–„β–€β–€Β β–€β–„Β Β β–€Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–ˆΒ β–„β–€β–ˆβ–€β–ˆβ–€β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€Β β–„β–ˆβ–„β–„β–„β–€β–ˆΒ β–„Β β–ˆβ–„β–„β–„β–„β–„β–ˆΒ β–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–„β–€Β β–„β–„β–€β–€β–„β–ˆβ–„Β β–„β–ˆβ–ˆβ–„β–€β–ˆβ–ˆβ–„Β Β β–„β–„β–ˆβ–„Β β–€β–€β–€β–ˆβ–€β–„β–€β–€Β β–„β–ˆβ–ˆ +β–ˆβ–„β–„β–„β–„Β β–€β–€β–ˆβ–€Β Β β–€β–„β–ˆβ–€β–„β–„β–€β–€β–ˆβ–ˆΒ β–€β–€β–„β–ˆβ–„β–€β–„β–ˆΒ β–€β–ˆβ–ˆβ–ˆΒ β–€β–ˆ +β–ˆβ–€β–„β–ˆβ–„β–ˆβ–€β–€β–ˆβ–„β–„β–€β–„β–ˆβ–ˆβ–ˆΒ β–„β–€β–„β–ˆβ–„β–ˆΒ Β β–€β–ˆβ–„Β β–€β–ˆβ–ˆβ–„Β β–€β–€β–€β–„β–ˆ +β–ˆΒ Β β–„β–„β–€β–„β–€β–€β–„β–„Β Β β–€Β β–€β–€β–„β–„β–€β–€β–„Β β–ˆβ–€β–„β–ˆβ–€β–„Β Β β–ˆβ–€β–„β–ˆΒ β–„β–ˆβ–ˆ +β–ˆΒ Β β–ˆβ–ˆβ–€β–€β–€β–€β–ˆβ–ˆΒ β–€β–„Β β–ˆβ–ˆΒ Β Β β–ˆβ–„β–ˆΒ β–€β–„β–„β–€β–€Β β–„Β β–„β–ˆβ–ˆβ–€β–„β–ˆβ–ˆ +β–ˆβ–€β–ˆΒ Β β–ˆβ–ˆβ–€β–„β–ˆβ–„β–„β–€β–€Β β–€β–€β–ˆβ–€Β β–„β–ˆΒ β–€β–ˆβ–€β–ˆβ–„β–€β–€β–€Β β–ˆβ–„β–€β–„β–€β–„β–ˆ +β–ˆβ–„Β β–€Β β–ˆβ–„β–€β–€Β β–€β–€β–„β–ˆβ–€β–„β–€β–ˆβ–„β–€β–ˆβ–€β–ˆβ–€Β β–ˆΒ β–„Β Β β–„β–ˆβ–„β–„β–ˆβ–€Β Β β–ˆ +β–ˆβ–„β–ˆΒ Β β–„β–ˆβ–€β–€Β Β β–ˆβ–ˆβ–ˆβ–ˆβ–„Β Β β–ˆβ–ˆβ–€β–„Β β–„β–„β–„β–„β–€β–„β–€Β β–€β–€Β β–€Β β–„Β β–ˆ +β–ˆβ–„β–ˆβ–€β–€β–„β–„β–€Β β–€β–€β–€Β Β β–ˆβ–ˆβ–€β–ˆβ–€Β β–€β–„β–€β–„β–„Β β–€β–€β–ˆβ–„β–ˆβ–ˆβ–ˆβ–„β–€β–€β–ˆβ–ˆβ–ˆ +β–ˆβ–€β–€Β β–„β–„β–ˆβ–€β–ˆβ–„β–€β–€β–€Β Β Β β–„Β β–ˆβ–ˆβ–€Β Β β–€β–ˆβ–„β–ˆβ–ˆβ–€β–€Β β–€β–€β–€β–„β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ Β β–„Β β–€Β β–ˆβ–€β–ˆβ–€β–„β–ˆβ–ˆβ–€β–ˆΒ β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ β–„β–€Β β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€Β Β β–€β–€Β β–ˆΒ β–ˆβ–„Β Β β–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–€β–€β–€Β β–€Β β–„β–„β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆβ–„β–„Β β–„β–„β–€β–ˆΒ β–„β–€β–€Β β–ˆΒ β–„β–„β–„β–€β–„β–„Β Β Β β–ˆβ–€β–ˆβ–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€Β β–ˆβ–ˆβ–ˆβ–„Β β–€β–ˆβ–ˆΒ Β β–ˆΒ β–€β–„Β β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€Β Β Β β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: FAW6M5CM42UJDN6A7LN6N77AD4CNH2LQ + +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: F186D62372FF1635 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: F186D62372FF1635 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 702485 [######--------------] 20s + +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: F186D62372FF1635 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAvRwQCDpGBXzAOzDuDRPNnkgwapJ7XFtl/GJe6LRrDGE= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEILKdTOiOLhSimRJlTBYL+QOCypt++575yybXZ1Jk9eZr +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: F186D62372FF1635 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +eager creek attitude team buddy check monitor flock fame member prosper elbow +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: F186D62372FF1635 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub1maf4p7jskx28x9pkccqrwe792eh0jdp6jxjh8v5hmcagzn42qmuse4zgld +nsec: nsec1w2hzaqqhyad7dwvpjnn4mwth7yhg7mx3ygcf9yx7d3ly98a8eurqcskz65 +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: F186D62372FF1635 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 167E1BFE50CB439B2324B3AF9FD5BC1C6743DA15 +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdAokyyWOJgVmKs+IoIxTmtA+gFpPpcZ0khPCxY +ZV3gCukAAQC4UltFEDg9pWPF2BLRmWY5LLFIgeeAvCpzW9Kolqwnsw9HzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBBZ+G/5Qy0ObIySzr5/VvBxnQ9oV +AAoJEJ/VvBxnQ9oV1y8A/jne5sHeoOUeldpLo2W2wblVmFLjS1ZaEpI+6DoOwMxN +AP4zKhDzGbnn3n0bgXjwlQDQhuJgZbkNHyF9xeG6iV+MBg== +=Rkq4 +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: F186D62372FF1635 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: F186D62372FF1635 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: F186D62372FF1635 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: F186D62372FF1635 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: F186D62372FF1635 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: F186D62372FF1635 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: F186D62372FF1635 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: iy3l^40N:N)N +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876001.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: F186D62372FF1635 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: F186D62372FF1635 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876001.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: F186D62372FF1635 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: F186D62372FF1635 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 702485 [########------------] 17s + +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: F186D62372FF1635 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 8 + password: 1 + totp: 1 + ssh: 1 + seed: 1 + pgp: 1 + nostr: 1 + key_value: 1 + managed_account: 1 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: F186D62372FF1635 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T194637Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T194637Z/transcript.raw.txt new file mode 100644 index 00000000..cf6db63c --- /dev/null +++ b/artifacts/agent_tui_test/20260223T194637Z/transcript.raw.txt @@ -0,0 +1,1066 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +purpose lend width float mosquito vanish excuse vault advance when recipe only +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings.1 + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: F186D62372FF1635 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: F186D62372FF1635 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: iy3l^40N:N)N + +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: F186D62372FF1635 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: iy3l^40N:N)N +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: F186D62372FF1635 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: F186D62372FF1635 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: F186D62372FF1635 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: F186D62372FF1635 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: F186D62372FF1635 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: F186D62372FF1635 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=FAW6M5CM42UJDN6A7LN6N77AD4CNH2LQ&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–€β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆΒ β–„Β Β β–€β–ˆβ–„β–„β–€Β β–€Β β–€β–€Β β–ˆβ–„Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–ˆΒ β–ˆβ–€β–„β–ˆβ–„β–„Β β–€β–„β–€β–€Β β–€β–„Β Β β–€Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–ˆΒ β–„β–€β–ˆβ–€β–ˆβ–€β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€Β β–„β–ˆβ–„β–„β–„β–€β–ˆΒ β–„Β β–ˆβ–„β–„β–„β–„β–„β–ˆΒ β–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–„β–€Β β–„β–„β–€β–€β–„β–ˆβ–„Β β–„β–ˆβ–ˆβ–„β–€β–ˆβ–ˆβ–„Β Β β–„β–„β–ˆβ–„Β β–€β–€β–€β–ˆβ–€β–„β–€β–€Β β–„β–ˆβ–ˆ +β–ˆβ–„β–„β–„β–„Β β–€β–€β–ˆβ–€Β Β β–€β–„β–ˆβ–€β–„β–„β–€β–€β–ˆβ–ˆΒ β–€β–€β–„β–ˆβ–„β–€β–„β–ˆΒ β–€β–ˆβ–ˆβ–ˆΒ β–€β–ˆ +β–ˆβ–€β–„β–ˆβ–„β–ˆβ–€β–€β–ˆβ–„β–„β–€β–„β–ˆβ–ˆβ–ˆΒ β–„β–€β–„β–ˆβ–„β–ˆΒ Β β–€β–ˆβ–„Β β–€β–ˆβ–ˆβ–„Β β–€β–€β–€β–„β–ˆ +β–ˆΒ Β β–„β–„β–€β–„β–€β–€β–„β–„Β Β β–€Β β–€β–€β–„β–„β–€β–€β–„Β β–ˆβ–€β–„β–ˆβ–€β–„Β Β β–ˆβ–€β–„β–ˆΒ β–„β–ˆβ–ˆ +β–ˆΒ Β β–ˆβ–ˆβ–€β–€β–€β–€β–ˆβ–ˆΒ β–€β–„Β β–ˆβ–ˆΒ Β Β β–ˆβ–„β–ˆΒ β–€β–„β–„β–€β–€Β β–„Β β–„β–ˆβ–ˆβ–€β–„β–ˆβ–ˆ +β–ˆβ–€β–ˆΒ Β β–ˆβ–ˆβ–€β–„β–ˆβ–„β–„β–€β–€Β β–€β–€β–ˆβ–€Β β–„β–ˆΒ β–€β–ˆβ–€β–ˆβ–„β–€β–€β–€Β β–ˆβ–„β–€β–„β–€β–„β–ˆ +β–ˆβ–„Β β–€Β β–ˆβ–„β–€β–€Β β–€β–€β–„β–ˆβ–€β–„β–€β–ˆβ–„β–€β–ˆβ–€β–ˆβ–€Β β–ˆΒ β–„Β Β β–„β–ˆβ–„β–„β–ˆβ–€Β Β β–ˆ +β–ˆβ–„β–ˆΒ Β β–„β–ˆβ–€β–€Β Β β–ˆβ–ˆβ–ˆβ–ˆβ–„Β Β β–ˆβ–ˆβ–€β–„Β β–„β–„β–„β–„β–€β–„β–€Β β–€β–€Β β–€Β β–„Β β–ˆ +β–ˆβ–„β–ˆβ–€β–€β–„β–„β–€Β β–€β–€β–€Β Β β–ˆβ–ˆβ–€β–ˆβ–€Β β–€β–„β–€β–„β–„Β β–€β–€β–ˆβ–„β–ˆβ–ˆβ–ˆβ–„β–€β–€β–ˆβ–ˆβ–ˆ +β–ˆβ–€β–€Β β–„β–„β–ˆβ–€β–ˆβ–„β–€β–€β–€Β Β Β β–„Β β–ˆβ–ˆβ–€Β Β β–€β–ˆβ–„β–ˆβ–ˆβ–€β–€Β β–€β–€β–€β–„β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ Β β–„Β β–€Β β–ˆβ–€β–ˆβ–€β–„β–ˆβ–ˆβ–€β–ˆΒ β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ β–„β–€Β β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€Β Β β–€β–€Β β–ˆΒ β–ˆβ–„Β Β β–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–€β–€β–€Β β–€Β β–„β–„β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆβ–„β–„Β β–„β–„β–€β–ˆΒ β–„β–€β–€Β β–ˆΒ β–„β–„β–„β–€β–„β–„Β Β Β β–ˆβ–€β–ˆβ–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€Β β–ˆβ–ˆβ–ˆβ–„Β β–€β–ˆβ–ˆΒ Β β–ˆΒ β–€β–„Β β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€Β Β Β β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: FAW6M5CM42UJDN6A7LN6N77AD4CNH2LQ + +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: F186D62372FF1635 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: F186D62372FF1635 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 702485 [######--------------] 20s + +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: F186D62372FF1635 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAvRwQCDpGBXzAOzDuDRPNnkgwapJ7XFtl/GJe6LRrDGE= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEILKdTOiOLhSimRJlTBYL+QOCypt++575yybXZ1Jk9eZr +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: F186D62372FF1635 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +eager creek attitude team buddy check monitor flock fame member prosper elbow +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: F186D62372FF1635 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub1maf4p7jskx28x9pkccqrwe792eh0jdp6jxjh8v5hmcagzn42qmuse4zgld +nsec: nsec1w2hzaqqhyad7dwvpjnn4mwth7yhg7mx3ygcf9yx7d3ly98a8eurqcskz65 +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: F186D62372FF1635 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 167E1BFE50CB439B2324B3AF9FD5BC1C6743DA15 +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdAokyyWOJgVmKs+IoIxTmtA+gFpPpcZ0khPCxY +ZV3gCukAAQC4UltFEDg9pWPF2BLRmWY5LLFIgeeAvCpzW9Kolqwnsw9HzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBBZ+G/5Qy0ObIySzr5/VvBxnQ9oV +AAoJEJ/VvBxnQ9oV1y8A/jne5sHeoOUeldpLo2W2wblVmFLjS1ZaEpI+6DoOwMxN +AP4zKhDzGbnn3n0bgXjwlQDQhuJgZbkNHyF9xeG6iV+MBg== +=Rkq4 +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: F186D62372FF1635 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: F186D62372FF1635 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: F186D62372FF1635 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: F186D62372FF1635 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: F186D62372FF1635 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: F186D62372FF1635 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876000.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: F186D62372FF1635 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: iy3l^40N:N)N +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876001.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: F186D62372FF1635 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: F186D62372FF1635 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups/entries_db_backup_1771876001.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: F186D62372FF1635 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: F186D62372FF1635 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 702485 [########------------] 17s + +cSeed Profile: F186D62372FF1635 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: F186D62372FF1635 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 8 + password: 1 + totp: 1 + ssh: 1 + seed: 1 + pgp: 1 + nostr: 1 + key_value: 1 + managed_account: 1 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-_qbephpj/.seedpass/F186D62372FF1635/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: F186D62372FF1635 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195347Z/report.json b/artifacts/agent_tui_test/20260223T195347Z/report.json new file mode 100644 index 00000000..6bc591f8 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195347Z/report.json @@ -0,0 +1,59 @@ +{ + "timestamp_utc": "20260223T195347Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-tmjifefp", + "scenario": "stress", + "stress_cycles": 4, + "stress_seed": 20260223, + "required_coverage_keys": [ + "startup_onboarding", + "main_menu", + "add_password_quick", + "invalid_input_resilience", + "retrieve_entry", + "list_entries", + "stress_cycles", + "seeded_negative_campaign", + "graceful_exit" + ], + "duration_sec": 4.475, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "stress_scenario", + "description": "Drive deterministic stress TUI scenario.", + "status": "passed", + "duration_sec": 4.381635347999691, + "detail": null + } + ], + "coverage_points": { + "add_all_entry_types": false, + "add_password_quick": true, + "add_totp": false, + "archive_restore": false, + "graceful_exit": true, + "invalid_input_resilience": true, + "invalid_length_validation": false, + "list_entries": true, + "main_menu": true, + "modify_entry": false, + "retrieve_entry": true, + "search_entries": false, + "seeded_negative_campaign": true, + "settings_stats": false, + "settings_toggles_lock_unlock": false, + "startup_onboarding": true, + "stress_cycles": true, + "totp_codes_view": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T195347Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T195347Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195347Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T195347Z/transcript.clean.txt new file mode 100644 index 00000000..db3ad12e --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195347Z/transcript.clean.txt @@ -0,0 +1,750 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +noble easily stumble flush admit into obey gaze exhaust unique weather woman +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-tmjifefp/.seedpass/AE1ADC71C02402F8/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: stress.example +Enter the username (optional): stress +Enter the URL (optional): https://stress.example +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-tmjifefp/.seedpass/AE1ADC71C02402F8/backups/entries_db_backup_1771876429.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for stress.example: o4-A5hE8z^T; + +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 0 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: one +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - stress.example +Enter index to view details or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'stress.example' with length 12. +Username: stress +URL: https://stress.example + +[+] Retrieved Password for stress.example: + +Password: o4-A5hE8z^T; +Associated Username: stress +Associated URL: https://stress.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +1 + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1x +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - stress.example +Enter index to view details or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'stress.example' with length 12. +Username: stress +URL: https://stress.example + +[+] Retrieved Password for stress.example: + +Password: o4-A5hE8z^T; +Associated Username: stress +Associated URL: https://stress.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: AE1ADC71C02402F8 > Main Menu +1 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: x +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 1x +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - stress.example +Enter index to view details or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'stress.example' with length 12. +Username: stress +URL: https://stress.example + +[+] Retrieved Password for stress.example: + +Password: o4-A5hE8z^T; +Associated Username: stress +Associated URL: https://stress.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 0 +Invalid choice. Please select a valid option. +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: index +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - stress.example +Enter index to view details or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'stress.example' with length 12. +Username: stress +URL: https://stress.example + +[+] Retrieved Password for stress.example: + +Password: o4-A5hE8z^T; +Associated Username: stress +Associated URL: https://stress.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T195347Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T195347Z/transcript.raw.txt new file mode 100644 index 00000000..d8bb30ba --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195347Z/transcript.raw.txt @@ -0,0 +1,751 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +noble easily stumble flush admit into obey gaze exhaust unique weather woman +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-tmjifefp/.seedpass/AE1ADC71C02402F8/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: stress.example +Enter the username (optional): stress +Enter the URL (optional): https://stress.example +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-tmjifefp/.seedpass/AE1ADC71C02402F8/backups/entries_db_backup_1771876429.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for stress.example: o4-A5hE8z^T; + +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 0 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: one +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - stress.example +Enter index to view details or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'stress.example' with length 12. +Username: stress +URL: https://stress.example + +[+] Retrieved Password for stress.example: + +Password: o4-A5hE8z^T; +Associated Username: stress +Associated URL: https://stress.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +1 + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1x +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - stress.example +Enter index to view details or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'stress.example' with length 12. +Username: stress +URL: https://stress.example + +[+] Retrieved Password for stress.example: + +Password: o4-A5hE8z^T; +Associated Username: stress +Associated URL: https://stress.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: AE1ADC71C02402F8 > Main Menu +1 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: x +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 1x +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - stress.example +Enter index to view details or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'stress.example' with length 12. +Username: stress +URL: https://stress.example + +[+] Retrieved Password for stress.example: + +Password: o4-A5hE8z^T; +Associated Username: stress +Associated URL: https://stress.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 0 +Invalid choice. Please select a valid option. +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: index +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - stress.example +Enter index to view details or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: AE1ADC71C02402F8 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'stress.example' with length 12. +Username: stress +URL: https://stress.example + +[+] Retrieved Password for stress.example: + +Password: o4-A5hE8z^T; +Associated Username: stress +Associated URL: https://stress.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: AE1ADC71C02402F8 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: AE1ADC71C02402F8 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195510Z/report.json b/artifacts/agent_tui_test/20260223T195510Z/report.json new file mode 100644 index 00000000..90027f66 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195510Z/report.json @@ -0,0 +1,74 @@ +{ + "timestamp_utc": "20260223T195510Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-y9xodvvp", + "scenario": "extended", + "stress_cycles": null, + "stress_seed": null, + "required_coverage_keys": [ + "startup_onboarding", + "main_menu", + "invalid_input_resilience", + "add_password_quick", + "invalid_length_validation", + "add_totp", + "add_all_entry_types", + "retrieve_entry", + "search_entries", + "list_entries", + "modify_entry", + "archive_restore", + "totp_codes_view", + "settings_toggles_lock_unlock", + "settings_stats", + "graceful_exit" + ], + "required_post_conditions": [ + "archive_restore_consistency", + "lock_unlock_recovers_retrieval" + ], + "duration_sec": 32.184, + "seedpass_exit_code": -9, + "status": "failed", + "failure": "Timed out waiting for pattern: 'Archived Entries'\nRecent output:\n\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 8\r\n\u001bcSeed Profile: 838F2A553C9E0619 > Main Menu > Archived Entries\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n[+] Archived Entries:\r\n\r\n0. agent.example\r\nEnter index to manage or press Enter to go back: 0\r\nEnter 'v' to view details, 'r' to restore, or press Enter to go back: r\r\n[+] Checksum updated successfully.\r\nBackup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876514.json.enc'.\r\n[+] Entry at index 0 modified successfully.\r\nPress Enter to continue...\r\nAll entries restored.\r\nPress Enter to continue...\r\n\u001bcSeed Profile: 838F2A553C9E0619 > Main Menu\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 8\r\nPress Enter to continue...", + "steps": [ + { + "step_id": "extended_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "failed", + "duration_sec": 30.673868958998355, + "detail": "Timed out waiting for pattern: 'Archived Entries'\nRecent output:\n\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 8\r\n\u001bcSeed Profile: 838F2A553C9E0619 > Main Menu > Archived Entries\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n[+] Archived Entries:\r\n\r\n0. agent.example\r\nEnter index to manage or press Enter to go back: 0\r\nEnter 'v' to view details, 'r' to restore, or press Enter to go back: r\r\n[+] Checksum updated successfully.\r\nBackup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876514.json.enc'.\r\n[+] Entry at index 0 modified successfully.\r\nPress Enter to continue...\r\nAll entries restored.\r\nPress Enter to continue...\r\n\u001bcSeed Profile: 838F2A553C9E0619 > Main Menu\r\nOnly 0 relay(s) responded with your latest event. Consider adding more relays via Settings.\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 8\r\nPress Enter to continue..." + } + ], + "coverage_points": { + "add_all_entry_types": true, + "add_password_quick": true, + "add_totp": true, + "archive_restore": true, + "graceful_exit": false, + "invalid_input_resilience": true, + "invalid_length_validation": true, + "list_entries": true, + "main_menu": true, + "modify_entry": true, + "retrieve_entry": true, + "search_entries": true, + "seeded_negative_campaign": false, + "settings_stats": false, + "settings_toggles_lock_unlock": false, + "startup_onboarding": true, + "stress_cycles": false, + "totp_codes_view": false + }, + "post_conditions": { + "archive_restore_consistency": false, + "lock_unlock_recovers_retrieval": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T195510Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T195510Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195510Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T195510Z/transcript.clean.txt new file mode 100644 index 00000000..dddebaac --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195510Z/transcript.clean.txt @@ -0,0 +1,820 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +ketchup glow prison slice movie reduce penalty attend labor oval snake program +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: A4l8E7-][nYe + +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: A4l8E7-][nYe +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 838F2A553C9E0619 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 838F2A553C9E0619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 838F2A553C9E0619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 838F2A553C9E0619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=FO3W6ALH23EEF2OHPJ4Q5IDYTS3UOWDL&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–€β–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–„β–ˆβ–€β–ˆβ–„β–„β–„β–ˆβ–„β–„β–€β–„Β β–ˆβ–€β–ˆβ–„β–€Β β–„Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–„β–€β–„β–ˆβ–„β–€β–„β–ˆβ–€β–ˆβ–„Β β–€β–€β–€β–„β–€β–„Β β–€β–€β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–ˆβ–€β–„β–€β–„β–€β–ˆβ–€β–„β–€β–„Β β–ˆΒ β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–€β–€β–ˆβ–€β–€β–€β–„Β β–ˆβ–€β–ˆβ–„β–€β–„β–„β–„β–„β–ˆβ–€β–ˆβ–€β–„Β β–ˆβ–ˆΒ Β β–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–€β–€β–ˆ +β–ˆβ–„β–€β–„β–ˆβ–„Β β–€β–€β–ˆβ–„β–„Β β–€Β β–ˆβ–„β–€β–ˆβ–„β–€β–ˆβ–€Β β–ˆβ–„β–€β–„β–„β–ˆβ–„Β Β Β β–„β–€β–„β–ˆβ–ˆ +β–ˆΒ β–ˆβ–€Β β–„β–€β–€β–ˆβ–„Β β–„β–€β–„β–€β–ˆβ–€Β Β β–€Β β–€β–ˆβ–€Β β–„Β Β Β β–„β–„Β β–ˆβ–€Β β–„β–€β–€β–ˆ +β–ˆβ–€β–ˆΒ Β β–„Β β–€Β β–€β–€β–€β–€Β β–„β–€β–€β–„β–„β–„Β β–„β–€Β β–ˆΒ Β β–„β–„β–€β–„β–„β–€Β β–ˆβ–€Β β–„β–ˆ +β–ˆβ–ˆβ–„β–„β–€Β Β β–€β–€Β β–€β–„Β β–€Β β–ˆβ–„β–„β–€β–„β–ˆβ–„Β β–„β–„β–€β–€β–€β–„β–€β–„β–ˆβ–€β–„β–ˆβ–€Β Β β–ˆ +β–ˆβ–€β–ˆβ–€β–ˆβ–„β–„β–€β–„Β Β β–ˆΒ β–ˆβ–€β–„β–ˆβ–ˆΒ β–€β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ Β β–ˆ +β–ˆβ–„Β β–ˆβ–€β–ˆβ–„β–€Β Β β–ˆβ–€β–€β–„β–„Β Β Β β–„β–„β–„Β β–€β–„β–ˆβ–ˆβ–ˆβ–€β–„β–ˆβ–€β–„β–„β–€Β β–ˆβ–€Β β–ˆ +β–ˆβ–ˆΒ β–„β–ˆβ–„β–„β–€β–€β–ˆΒ β–ˆβ–€β–€β–€β–„β–„β–€β–„β–€β–„β–„Β β–ˆΒ β–ˆβ–€β–€β–ˆβ–„Β β–ˆβ–ˆβ–€Β β–ˆβ–€β–€β–ˆ +β–ˆΒ β–ˆΒ Β β–ˆΒ β–€Β β–ˆβ–ˆβ–„β–ˆβ–„β–€Β β–€Β β–„β–ˆβ–„Β β–ˆβ–„β–ˆβ–„β–€β–ˆβ–€β–€Β β–€β–„β–„β–„Β β–ˆβ–ˆβ–ˆ +β–ˆβ–ˆΒ β–€β–€β–„β–„β–€β–„β–€β–„Β β–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–„β–€β–„β–„β–ˆβ–„β–€β–€β–„β–€β–ˆβ–€Β β–ˆβ–„β–€β–ˆΒ Β β–„β–ˆ +β–ˆβ–„β–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–ˆβ–„β–„β–€Β β–€β–„β–ˆβ–„Β β–ˆΒ Β Β Β β–€β–€β–ˆβ–ˆΒ β–€Β β–€β–€Β β–ˆΒ β–„β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ Β β–„β–„β–€β–„β–„β–„β–€β–ˆβ–€β–ˆβ–„β–€Β β–„β–„β–ˆβ–„β–„Β β–ˆβ–€β–ˆΒ β–„β–„β–ˆβ–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–„β–„β–€β–€β–€Β Β β–ˆβ–€β–„β–„Β Β Β β–€Β Β β–ˆβ–ˆβ–„Β β–€β–€β–€Β Β β–ˆβ–€β–ˆβ–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–€β–„β–„Β β–„β–€Β β–„β–€β–€Β β–ˆΒ β–„β–„β–„β–ˆβ–„β–€Β Β Β β–€Β Β β–„β–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€Β β–„β–€β–ˆβ–„Β β–„β–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–€β–ˆΒ Β β–ˆΒ β–„β–€β–„Β β–ˆΒ β–ˆβ–€β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: FO3W6ALH23EEF2OHPJ4Q5IDYTS3UOWDL + +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 838F2A553C9E0619 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 838F2A553C9E0619 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 485226 [########------------] 17s + +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEA/xTLxJw+pDqWRc6GishGIlOSpgSiBPbviyGmD8+05fc= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIIoDOF9ZdPmMTrPahebdV5qhKVIn4lrpZU9KBfV6hQ+y +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +slight defense rural innocent ocean scissors style result risk cabbage indicate frog +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub1m9w6crsqdd6eu7feglgwulrrc55lfpnkvac7j8uu2vxjfh39nhnsa369zz +nsec: nsec1qfwzlrwrsvkcmt3vnus3uch0d2zqqcy8g8tzd34q055d7p4sj0gsk9qep2 +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 1301DCFD8045FFB5A73783F0B10256F695E90633 +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdAqhy/NTnn8LiQLRfLNY7L/d3Xam5/TwEayac8 +q1sFuO0AAP4hDYBMPKJvSglCZVQOKs0OwN3SlgTx0n10JlzC2i2YWg6gzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBBMB3P2ARf+1pzeD8LECVvaV6QYz +AAoJELECVvaV6QYzuk4A/0E/9Jv2AEav0XtB81XdyjXLopNnPX07hOwRPwtf43ci +AP9VRFUdTJ+E0UaS9oLb+x9ADkNn8LEep/SuZ2X1/9WRCA== +=aprO +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 838F2A553C9E0619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 838F2A553C9E0619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: 838F2A553C9E0619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: A4l8E7-][nYe +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876514.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 838F2A553C9E0619 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876514.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +Press Enter to continue... \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195510Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T195510Z/transcript.raw.txt new file mode 100644 index 00000000..ddf95bc8 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195510Z/transcript.raw.txt @@ -0,0 +1,820 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +ketchup glow prison slice movie reduce penalty attend labor oval snake program +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: A4l8E7-][nYe + +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: A4l8E7-][nYe +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 838F2A553C9E0619 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 838F2A553C9E0619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 838F2A553C9E0619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 838F2A553C9E0619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=FO3W6ALH23EEF2OHPJ4Q5IDYTS3UOWDL&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–€β–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–„β–ˆβ–€β–ˆβ–„β–„β–„β–ˆβ–„β–„β–€β–„Β β–ˆβ–€β–ˆβ–„β–€Β β–„Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–„β–€β–„β–ˆβ–„β–€β–„β–ˆβ–€β–ˆβ–„Β β–€β–€β–€β–„β–€β–„Β β–€β–€β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–ˆβ–€β–„β–€β–„β–€β–ˆβ–€β–„β–€β–„Β β–ˆΒ β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–€β–€β–ˆβ–€β–€β–€β–„Β β–ˆβ–€β–ˆβ–„β–€β–„β–„β–„β–„β–ˆβ–€β–ˆβ–€β–„Β β–ˆβ–ˆΒ Β β–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–€β–€β–ˆ +β–ˆβ–„β–€β–„β–ˆβ–„Β β–€β–€β–ˆβ–„β–„Β β–€Β β–ˆβ–„β–€β–ˆβ–„β–€β–ˆβ–€Β β–ˆβ–„β–€β–„β–„β–ˆβ–„Β Β Β β–„β–€β–„β–ˆβ–ˆ +β–ˆΒ β–ˆβ–€Β β–„β–€β–€β–ˆβ–„Β β–„β–€β–„β–€β–ˆβ–€Β Β β–€Β β–€β–ˆβ–€Β β–„Β Β Β β–„β–„Β β–ˆβ–€Β β–„β–€β–€β–ˆ +β–ˆβ–€β–ˆΒ Β β–„Β β–€Β β–€β–€β–€β–€Β β–„β–€β–€β–„β–„β–„Β β–„β–€Β β–ˆΒ Β β–„β–„β–€β–„β–„β–€Β β–ˆβ–€Β β–„β–ˆ +β–ˆβ–ˆβ–„β–„β–€Β Β β–€β–€Β β–€β–„Β β–€Β β–ˆβ–„β–„β–€β–„β–ˆβ–„Β β–„β–„β–€β–€β–€β–„β–€β–„β–ˆβ–€β–„β–ˆβ–€Β Β β–ˆ +β–ˆβ–€β–ˆβ–€β–ˆβ–„β–„β–€β–„Β Β β–ˆΒ β–ˆβ–€β–„β–ˆβ–ˆΒ β–€β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ Β β–ˆ +β–ˆβ–„Β β–ˆβ–€β–ˆβ–„β–€Β Β β–ˆβ–€β–€β–„β–„Β Β Β β–„β–„β–„Β β–€β–„β–ˆβ–ˆβ–ˆβ–€β–„β–ˆβ–€β–„β–„β–€Β β–ˆβ–€Β β–ˆ +β–ˆβ–ˆΒ β–„β–ˆβ–„β–„β–€β–€β–ˆΒ β–ˆβ–€β–€β–€β–„β–„β–€β–„β–€β–„β–„Β β–ˆΒ β–ˆβ–€β–€β–ˆβ–„Β β–ˆβ–ˆβ–€Β β–ˆβ–€β–€β–ˆ +β–ˆΒ β–ˆΒ Β β–ˆΒ β–€Β β–ˆβ–ˆβ–„β–ˆβ–„β–€Β β–€Β β–„β–ˆβ–„Β β–ˆβ–„β–ˆβ–„β–€β–ˆβ–€β–€Β β–€β–„β–„β–„Β β–ˆβ–ˆβ–ˆ +β–ˆβ–ˆΒ β–€β–€β–„β–„β–€β–„β–€β–„Β β–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–„β–€β–„β–„β–ˆβ–„β–€β–€β–„β–€β–ˆβ–€Β β–ˆβ–„β–€β–ˆΒ Β β–„β–ˆ +β–ˆβ–„β–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–ˆβ–„β–„β–€Β β–€β–„β–ˆβ–„Β β–ˆΒ Β Β Β β–€β–€β–ˆβ–ˆΒ β–€Β β–€β–€Β β–ˆΒ β–„β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ Β β–„β–„β–€β–„β–„β–„β–€β–ˆβ–€β–ˆβ–„β–€Β β–„β–„β–ˆβ–„β–„Β β–ˆβ–€β–ˆΒ β–„β–„β–ˆβ–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–„β–„β–€β–€β–€Β Β β–ˆβ–€β–„β–„Β Β Β β–€Β Β β–ˆβ–ˆβ–„Β β–€β–€β–€Β Β β–ˆβ–€β–ˆβ–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–€β–„β–„Β β–„β–€Β β–„β–€β–€Β β–ˆΒ β–„β–„β–„β–ˆβ–„β–€Β Β Β β–€Β Β β–„β–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€Β β–„β–€β–ˆβ–„Β β–„β–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–€β–ˆΒ Β β–ˆΒ β–„β–€β–„Β β–ˆΒ β–ˆβ–€β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: FO3W6ALH23EEF2OHPJ4Q5IDYTS3UOWDL + +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 838F2A553C9E0619 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 838F2A553C9E0619 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 485226 [########------------] 17s + +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEA/xTLxJw+pDqWRc6GishGIlOSpgSiBPbviyGmD8+05fc= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIIoDOF9ZdPmMTrPahebdV5qhKVIn4lrpZU9KBfV6hQ+y +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +slight defense rural innocent ocean scissors style result risk cabbage indicate frog +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub1m9w6crsqdd6eu7feglgwulrrc55lfpnkvac7j8uu2vxjfh39nhnsa369zz +nsec: nsec1qfwzlrwrsvkcmt3vnus3uch0d2zqqcy8g8tzd34q055d7p4sj0gsk9qep2 +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 1301DCFD8045FFB5A73783F0B10256F695E90633 +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdAqhy/NTnn8LiQLRfLNY7L/d3Xam5/TwEayac8 +q1sFuO0AAP4hDYBMPKJvSglCZVQOKs0OwN3SlgTx0n10JlzC2i2YWg6gzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBBMB3P2ARf+1pzeD8LECVvaV6QYz +AAoJELECVvaV6QYzuk4A/0E/9Jv2AEav0XtB81XdyjXLopNnPX07hOwRPwtf43ci +AP9VRFUdTJ+E0UaS9oLb+x9ADkNn8LEep/SuZ2X1/9WRCA== +=aprO +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 838F2A553C9E0619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 838F2A553C9E0619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: 838F2A553C9E0619 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876513.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: A4l8E7-][nYe +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876514.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 838F2A553C9E0619 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 838F2A553C9E0619 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-y9xodvvp/.seedpass/838F2A553C9E0619/backups/entries_db_backup_1771876514.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 838F2A553C9E0619 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +Press Enter to continue... \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195604Z/report.json b/artifacts/agent_tui_test/20260223T195604Z/report.json new file mode 100644 index 00000000..c91ef5f4 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195604Z/report.json @@ -0,0 +1,74 @@ +{ + "timestamp_utc": "20260223T195604Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-gvwg35yq", + "scenario": "extended", + "stress_cycles": null, + "stress_seed": null, + "required_coverage_keys": [ + "startup_onboarding", + "main_menu", + "invalid_input_resilience", + "add_password_quick", + "invalid_length_validation", + "add_totp", + "add_all_entry_types", + "retrieve_entry", + "search_entries", + "list_entries", + "modify_entry", + "archive_restore", + "totp_codes_view", + "settings_toggles_lock_unlock", + "settings_stats", + "graceful_exit" + ], + "required_post_conditions": [ + "archive_restore_consistency", + "lock_unlock_recovers_retrieval" + ], + "duration_sec": 58.479, + "seedpass_exit_code": -9, + "status": "failed", + "failure": "Timed out waiting for pattern: 'Retrieved Password for agent\\\\.example'\nRecent output:\n...\r\nDecrypting seed...\r\nConnecting to relays...\r\nPress Enter to continue...\r\n\u001bcSeed Profile: Main Menu > Settings\r\n\r\n\r\nSettings:\r\n1. Profiles\r\n2. Nostr\r\n3. Change password\r\n4. Verify Script Checksum\r\n5. Generate Script Checksum\r\n6. Backup Parent Seed\r\n7. Export database\r\n8. Import database\r\n9. Export 2FA codes\r\n10. Set additional backup location\r\n11. KDF strength & benchmark\r\n12. Set inactivity timeout\r\n13. Lock Vault\r\n14. Stats\r\n15. Toggle Secret Mode\r\n16. Toggle Offline Mode (default ON)\r\n17. Toggle Quick Unlock\r\nSelect an option or press Enter to go back: \r\n\u001bcSeed Profile: 2CEE29FCE43AFB18 > Main Menu\r\n\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 2\r\n\u001bcSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Retrieve Entry\r\n\r\nEnter the index number of the entry to retrieve: 0\r\nRetrieving password for 'agent.example' with length 12.\r\nUsername: agent2\r\nURL: https://agent.example\r\n[+] Password for 'agent.example' copied to clipboard. Will clear in 45 seconds.\r\nPress Enter to continue...", + "steps": [ + { + "step_id": "extended_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "failed", + "duration_sec": 56.9674957419993, + "detail": "Timed out waiting for pattern: 'Retrieved Password for agent\\\\.example'\nRecent output:\n...\r\nDecrypting seed...\r\nConnecting to relays...\r\nPress Enter to continue...\r\n\u001bcSeed Profile: Main Menu > Settings\r\n\r\n\r\nSettings:\r\n1. Profiles\r\n2. Nostr\r\n3. Change password\r\n4. Verify Script Checksum\r\n5. Generate Script Checksum\r\n6. Backup Parent Seed\r\n7. Export database\r\n8. Import database\r\n9. Export 2FA codes\r\n10. Set additional backup location\r\n11. KDF strength & benchmark\r\n12. Set inactivity timeout\r\n13. Lock Vault\r\n14. Stats\r\n15. Toggle Secret Mode\r\n16. Toggle Offline Mode (default ON)\r\n17. Toggle Quick Unlock\r\nSelect an option or press Enter to go back: \r\n\u001bcSeed Profile: 2CEE29FCE43AFB18 > Main Menu\r\n\r\n\r\n Select an option:\r\n 1. Add Entry\r\n 2. Retrieve Entry\r\n 3. Search Entries\r\n 4. List Entries\r\n 5. Modify an Existing Entry\r\n 6. 2FA Codes\r\n 7. Settings\r\n 8. List Archived\r\n \r\nEnter your choice (1-8) or press Enter to exit: 2\r\n\u001bcSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Retrieve Entry\r\n\r\nEnter the index number of the entry to retrieve: 0\r\nRetrieving password for 'agent.example' with length 12.\r\nUsername: agent2\r\nURL: https://agent.example\r\n[+] Password for 'agent.example' copied to clipboard. Will clear in 45 seconds.\r\nPress Enter to continue..." + } + ], + "coverage_points": { + "add_all_entry_types": true, + "add_password_quick": true, + "add_totp": true, + "archive_restore": true, + "graceful_exit": false, + "invalid_input_resilience": true, + "invalid_length_validation": true, + "list_entries": true, + "main_menu": true, + "modify_entry": true, + "retrieve_entry": true, + "search_entries": true, + "seeded_negative_campaign": false, + "settings_stats": false, + "settings_toggles_lock_unlock": true, + "startup_onboarding": true, + "stress_cycles": false, + "totp_codes_view": true + }, + "post_conditions": { + "archive_restore_consistency": true, + "lock_unlock_recovers_retrieval": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T195604Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T195604Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195604Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T195604Z/transcript.clean.txt new file mode 100644 index 00000000..62eefdfa --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195604Z/transcript.clean.txt @@ -0,0 +1,1009 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +ketchup wool river art stomach select orange horse patrol theory finger resemble +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876567.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: Sw3re?RL#4>9 + +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Sw3re?RL#4>9 +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=B3RUXQKHLMCEE6EEYIZC2ZUTW2V3X6VY&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–€β–€β–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–„β–ˆΒ β–ˆβ–€β–„Β Β β–„β–„β–ˆβ–€β–ˆβ–„β–€β–ˆΒ β–„β–ˆβ–ˆΒ β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€Β β–„β–ˆβ–ˆΒ β–€Β β–„Β β–€β–€β–€β–€β–ˆβ–€β–„β–ˆΒ β–€β–ˆβ–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„Β β–„Β β–ˆβ–€β–„Β β–ˆβ–€β–„Β β–„β–€β–„β–€β–ˆβ–€β–„Β β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–„β–€β–ˆβ–„Β β–€β–„β–„β–„Β Β β–„β–„β–€β–„β–„Β Β β–€Β β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–ˆ +β–ˆΒ Β Β β–€β–„β–„β–€β–€β–€β–€β–€β–„β–„β–€Β β–„β–ˆβ–„β–€Β β–ˆβ–€β–„Β β–€Β β–„β–„β–€β–€β–ˆβ–€Β β–ˆβ–€β–€Β β–ˆ +β–ˆβ–„Β β–€β–„Β β–„β–€β–ˆβ–„Β β–ˆβ–€β–€Β β–ˆβ–„β–ˆβ–€β–„Β β–ˆΒ β–„β–€β–„Β β–„β–€β–€β–ˆΒ β–„β–ˆβ–„β–ˆΒ β–€β–ˆ +β–ˆβ–€β–„β–„β–€Β β–„β–€β–ˆβ–„β–ˆΒ β–€β–ˆβ–ˆβ–„β–ˆΒ β–„Β β–ˆβ–€Β Β β–ˆβ–„β–ˆβ–€β–ˆβ–€β–„β–„β–„β–ˆβ–„β–€β–ˆβ–€β–ˆ +β–ˆβ–€Β β–ˆβ–„Β β–ˆβ–€β–„Β β–ˆβ–€β–ˆβ–„Β β–€Β Β β–„β–€β–„β–„Β Β β–€β–„Β β–€β–„β–€β–„Β Β β–„β–ˆβ–ˆβ–€β–„β–ˆ +β–ˆβ–„β–ˆβ–ˆβ–„Β Β β–€β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ Β Β β–€β–ˆβ–€Β Β β–„β–€β–„β–„β–€β–€Β β–„β–„β–„β–ˆβ–ˆβ–€Β β–ˆ +β–ˆβ–€β–ˆΒ β–ˆΒ β–€β–€β–€Β Β β–ˆΒ Β β–„β–„β–€β–„β–ˆβ–€β–€β–ˆΒ β–„β–ˆβ–€Β β–„Β β–„β–€Β β–€β–ˆβ–„β–€β–€β–„β–ˆ +β–ˆβ–ˆβ–„Β β–ˆβ–ˆβ–€β–€β–ˆΒ β–ˆβ–„Β β–„β–„β–€β–€β–€β–€β–„β–ˆβ–„Β β–€β–ˆΒ Β β–€β–ˆΒ β–ˆβ–„β–„β–€Β β–€β–ˆβ–ˆβ–ˆ +β–ˆβ–„β–ˆβ–„β–„β–€β–€β–€β–„Β β–„β–€β–„β–„β–ˆβ–„β–€β–ˆβ–ˆβ–ˆβ–„β–„Β β–€β–„β–„β–€β–€β–„Β Β β–„Β β–„β–€β–ˆΒ β–€β–ˆ +β–ˆβ–€β–ˆΒ Β β–„β–„β–€β–„β–€β–ˆβ–„Β β–€Β Β β–„β–ˆβ–€β–€β–€β–€β–„β–„β–€β–ˆβ–€β–„β–€Β Β Β β–€Β β–ˆΒ Β Β β–ˆ +β–ˆβ–€β–„β–ˆβ–„Β Β β–€β–€β–ˆβ–€Β β–€β–€Β β–ˆβ–„β–€β–€Β β–„Β Β β–„β–ˆβ–„Β β–ˆβ–„Β Β β–€Β β–€β–ˆΒ β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–„Β Β Β β–„β–€β–„Β β–„β–„Β β–ˆΒ β–„β–ˆβ–ˆβ–„β–ˆΒ β–€Β β–ˆβ–€β–ˆΒ β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–€Β Β β–„β–€β–ˆΒ Β β–„Β β–ˆβ–ˆβ–€β–€Β β–„Β Β β–ˆΒ β–€β–€β–€Β β–€β–ˆΒ β–€β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€β–„Β β–„β–ˆβ–„β–ˆΒ Β Β β–„β–€β–ˆΒ Β β–€β–€β–„β–„β–€β–„β–ˆβ–ˆΒ Β β–ˆβ–ˆβ–„Β β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€Β β–ˆβ–ˆβ–ˆβ–ˆβ–„β–€β–„β–ˆΒ β–ˆβ–ˆΒ β–„β–„Β Β β–€β–€Β β–€Β Β β–€β–ˆβ–ˆΒ β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: B3RUXQKHLMCEE6EEYIZC2ZUTW2V3X6VY + +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 318916 [#####---------------] 22s + +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEATmM+y88fQuVB8Hk/kKhOZEqYI+6PAYlEjgjSaYRDAcg= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIOn0WP3Hb6gLcAGcLMS3npiA2+eodJIhe+/B3OMxkKZo +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +conduct impact monkey wool box ski lunch female nominee pond vocal viable +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub17kxczmvhuw7rh8h3hh9swj5cgn5qrgxkwdjwl2srfcynd9t9khfs26f8hp +nsec: nsec1q0x7h3z8excst6q8ljf7dx03u0xu2fg8z24v49v8tvzddn8qx8mqn8xxzm +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 4AF996771A1C9BADF2211DDB1BAC2C74E8A06928 +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdA/nqSb8DuoHf3e5BnGACsM/nyObbPZ97Vstof +DPc/UrEAAPwJKhqbMt+ZwxmC0I6YK7bI58rLsUTkeOvX6wYm4l7vpxMHzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBEr5lncaHJut8iEd2xusLHTooGko +AAoJEBusLHTooGko8i0BAMaWzb/EZ0GuN+GF5SQ6eotic/JurxOeBvFj37ySmRH8 +AQDacAEOIXAcltEIATGpYQ4X45EtJk2kOoMdNRKigGJLDA== +=Qd0g +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Sw3re?RL#4>9 +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 2CEE29FCE43AFB18 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +No archived entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > 2FA Codes +No archived entries found. +Press Enter to return to the menu. +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > 2FA Codes +No archived entries found. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 318916 [#######-------------] 19s + +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +No archived entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Retrieve Entry + +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example +[+] Password for 'agent.example' copied to clipboard. Will clear in 45 seconds. +Press Enter to continue... \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195604Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T195604Z/transcript.raw.txt new file mode 100644 index 00000000..a04a6963 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195604Z/transcript.raw.txt @@ -0,0 +1,1009 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +ketchup wool river art stomach select orange horse patrol theory finger resemble +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876567.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: Sw3re?RL#4>9 + +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Sw3re?RL#4>9 +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=B3RUXQKHLMCEE6EEYIZC2ZUTW2V3X6VY&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–€β–€β–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–„β–ˆΒ β–ˆβ–€β–„Β Β β–„β–„β–ˆβ–€β–ˆβ–„β–€β–ˆΒ β–„β–ˆβ–ˆΒ β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€Β β–„β–ˆβ–ˆΒ β–€Β β–„Β β–€β–€β–€β–€β–ˆβ–€β–„β–ˆΒ β–€β–ˆβ–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„Β β–„Β β–ˆβ–€β–„Β β–ˆβ–€β–„Β β–„β–€β–„β–€β–ˆβ–€β–„Β β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–„β–€β–ˆβ–„Β β–€β–„β–„β–„Β Β β–„β–„β–€β–„β–„Β Β β–€Β β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–ˆ +β–ˆΒ Β Β β–€β–„β–„β–€β–€β–€β–€β–€β–„β–„β–€Β β–„β–ˆβ–„β–€Β β–ˆβ–€β–„Β β–€Β β–„β–„β–€β–€β–ˆβ–€Β β–ˆβ–€β–€Β β–ˆ +β–ˆβ–„Β β–€β–„Β β–„β–€β–ˆβ–„Β β–ˆβ–€β–€Β β–ˆβ–„β–ˆβ–€β–„Β β–ˆΒ β–„β–€β–„Β β–„β–€β–€β–ˆΒ β–„β–ˆβ–„β–ˆΒ β–€β–ˆ +β–ˆβ–€β–„β–„β–€Β β–„β–€β–ˆβ–„β–ˆΒ β–€β–ˆβ–ˆβ–„β–ˆΒ β–„Β β–ˆβ–€Β Β β–ˆβ–„β–ˆβ–€β–ˆβ–€β–„β–„β–„β–ˆβ–„β–€β–ˆβ–€β–ˆ +β–ˆβ–€Β β–ˆβ–„Β β–ˆβ–€β–„Β β–ˆβ–€β–ˆβ–„Β β–€Β Β β–„β–€β–„β–„Β Β β–€β–„Β β–€β–„β–€β–„Β Β β–„β–ˆβ–ˆβ–€β–„β–ˆ +β–ˆβ–„β–ˆβ–ˆβ–„Β Β β–€β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ Β Β β–€β–ˆβ–€Β Β β–„β–€β–„β–„β–€β–€Β β–„β–„β–„β–ˆβ–ˆβ–€Β β–ˆ +β–ˆβ–€β–ˆΒ β–ˆΒ β–€β–€β–€Β Β β–ˆΒ Β β–„β–„β–€β–„β–ˆβ–€β–€β–ˆΒ β–„β–ˆβ–€Β β–„Β β–„β–€Β β–€β–ˆβ–„β–€β–€β–„β–ˆ +β–ˆβ–ˆβ–„Β β–ˆβ–ˆβ–€β–€β–ˆΒ β–ˆβ–„Β β–„β–„β–€β–€β–€β–€β–„β–ˆβ–„Β β–€β–ˆΒ Β β–€β–ˆΒ β–ˆβ–„β–„β–€Β β–€β–ˆβ–ˆβ–ˆ +β–ˆβ–„β–ˆβ–„β–„β–€β–€β–€β–„Β β–„β–€β–„β–„β–ˆβ–„β–€β–ˆβ–ˆβ–ˆβ–„β–„Β β–€β–„β–„β–€β–€β–„Β Β β–„Β β–„β–€β–ˆΒ β–€β–ˆ +β–ˆβ–€β–ˆΒ Β β–„β–„β–€β–„β–€β–ˆβ–„Β β–€Β Β β–„β–ˆβ–€β–€β–€β–€β–„β–„β–€β–ˆβ–€β–„β–€Β Β Β β–€Β β–ˆΒ Β Β β–ˆ +β–ˆβ–€β–„β–ˆβ–„Β Β β–€β–€β–ˆβ–€Β β–€β–€Β β–ˆβ–„β–€β–€Β β–„Β Β β–„β–ˆβ–„Β β–ˆβ–„Β Β β–€Β β–€β–ˆΒ β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–„Β Β Β β–„β–€β–„Β β–„β–„Β β–ˆΒ β–„β–ˆβ–ˆβ–„β–ˆΒ β–€Β β–ˆβ–€β–ˆΒ β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–€Β Β β–„β–€β–ˆΒ Β β–„Β β–ˆβ–ˆβ–€β–€Β β–„Β Β β–ˆΒ β–€β–€β–€Β β–€β–ˆΒ β–€β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€β–„Β β–„β–ˆβ–„β–ˆΒ Β Β β–„β–€β–ˆΒ Β β–€β–€β–„β–„β–€β–„β–ˆβ–ˆΒ Β β–ˆβ–ˆβ–„Β β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€Β β–ˆβ–ˆβ–ˆβ–ˆβ–„β–€β–„β–ˆΒ β–ˆβ–ˆΒ β–„β–„Β Β β–€β–€Β β–€Β Β β–€β–ˆβ–ˆΒ β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: B3RUXQKHLMCEE6EEYIZC2ZUTW2V3X6VY + +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 318916 [#####---------------] 22s + +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEATmM+y88fQuVB8Hk/kKhOZEqYI+6PAYlEjgjSaYRDAcg= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIOn0WP3Hb6gLcAGcLMS3npiA2+eodJIhe+/B3OMxkKZo +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +conduct impact monkey wool box ski lunch female nominee pond vocal viable +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub17kxczmvhuw7rh8h3hh9swj5cgn5qrgxkwdjwl2srfcynd9t9khfs26f8hp +nsec: nsec1q0x7h3z8excst6q8ljf7dx03u0xu2fg8z24v49v8tvzddn8qx8mqn8xxzm +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 4AF996771A1C9BADF2211DDB1BAC2C74E8A06928 +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdA/nqSb8DuoHf3e5BnGACsM/nyObbPZ97Vstof +DPc/UrEAAPwJKhqbMt+ZwxmC0I6YK7bI58rLsUTkeOvX6wYm4l7vpxMHzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBEr5lncaHJut8iEd2xusLHTooGko +AAoJEBusLHTooGko8i0BAMaWzb/EZ0GuN+GF5SQ6eotic/JurxOeBvFj37ySmRH8 +AQDacAEOIXAcltEIATGpYQ4X45EtJk2kOoMdNRKigGJLDA== +=Qd0g +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Sw3re?RL#4>9 +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 2CEE29FCE43AFB18 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-gvwg35yq/.seedpass/2CEE29FCE43AFB18/backups/entries_db_backup_1771876568.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +Press Enter to continue... +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +No archived entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > 2FA Codes +No archived entries found. +Press Enter to return to the menu. +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > 2FA Codes +No archived entries found. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 318916 [#######-------------] 19s + +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu +No archived entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 2CEE29FCE43AFB18 > Main Menu > Retrieve Entry + +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example +[+] Password for 'agent.example' copied to clipboard. Will clear in 45 seconds. +Press Enter to continue... \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195720Z/report.json b/artifacts/agent_tui_test/20260223T195720Z/report.json new file mode 100644 index 00000000..0fc3883d --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195720Z/report.json @@ -0,0 +1,74 @@ +{ + "timestamp_utc": "20260223T195720Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-f_yj1_os", + "scenario": "extended", + "stress_cycles": null, + "stress_seed": null, + "required_coverage_keys": [ + "startup_onboarding", + "main_menu", + "invalid_input_resilience", + "add_password_quick", + "invalid_length_validation", + "add_totp", + "add_all_entry_types", + "retrieve_entry", + "search_entries", + "list_entries", + "modify_entry", + "archive_restore", + "totp_codes_view", + "settings_toggles_lock_unlock", + "settings_stats", + "graceful_exit" + ], + "required_post_conditions": [ + "archive_restore_consistency", + "lock_unlock_recovers_retrieval" + ], + "duration_sec": 33.578, + "seedpass_exit_code": -11, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "extended_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 32.675647964002565, + "detail": null + } + ], + "coverage_points": { + "add_all_entry_types": true, + "add_password_quick": true, + "add_totp": true, + "archive_restore": true, + "graceful_exit": true, + "invalid_input_resilience": true, + "invalid_length_validation": true, + "list_entries": true, + "main_menu": true, + "modify_entry": true, + "retrieve_entry": true, + "search_entries": true, + "seeded_negative_campaign": false, + "settings_stats": true, + "settings_toggles_lock_unlock": true, + "startup_onboarding": true, + "stress_cycles": false, + "totp_codes_view": true + }, + "post_conditions": { + "archive_restore_consistency": true, + "lock_unlock_recovers_retrieval": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T195720Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T195720Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195720Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T195720Z/transcript.clean.txt new file mode 100644 index 00000000..c4c32c6d --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195720Z/transcript.clean.txt @@ -0,0 +1,1113 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +total elegant metal discover leg bunker notice oval beauty holiday marine guide +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876642.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: Op}"560o&PDw + +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Op}"560o&PDw +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=HOSOCJFB72CTCJAHRGGHWVOIJ3ILCF3E&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–„β–€β–„β–€β–„β–ˆβ–€Β β–„β–„β–ˆβ–€β–ˆβ–„β–€β–ˆΒ β–„β–ˆβ–ˆΒ β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€β–ˆΒ β–ˆβ–ˆβ–ˆβ–ˆΒ β–„Β β–€β–€β–€β–€β–ˆβ–€β–„β–ˆΒ β–€β–ˆβ–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„Β β–ˆΒ β–ˆβ–€β–ˆΒ β–ˆβ–€β–„Β β–„β–€β–„β–€β–ˆβ–€β–„Β β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–„β–ˆβ–ˆβ–€β–„Β β–„β–„β–„Β Β β–„β–„β–€β–„β–„Β Β β–€Β β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–ˆ +β–ˆΒ β–„Β β–€Β Β β–€Β β–€β–ˆβ–ˆβ–€β–€Β β–„β–„β–ˆΒ β–€Β β–ˆβ–€β–„Β β–€Β β–„β–„β–€β–€β–„Β β–€β–ˆβ–„β–€Β β–ˆ +β–ˆβ–ˆβ–€Β β–€Β β–€β–€β–€β–ˆΒ β–€β–€Β β–ˆβ–ˆβ–„β–ˆβ–„Β Β β–ˆΒ β–„β–€β–„Β β–„β–€β–€β–ˆΒ β–ˆβ–ˆΒ Β Β β–€β–ˆ +β–ˆβ–ˆΒ β–€Β β–ˆΒ β–€Β β–ˆΒ β–ˆβ–„β–ˆβ–„β–ˆΒ β–„β–„Β β–ˆβ–€Β Β β–ˆβ–„β–ˆβ–€β–ˆβ–€Β Β β–„β–ˆβ–„β–€Β β–ˆβ–ˆ +β–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–„β–€β–€β–ˆβ–ˆβ–„Β β–ˆΒ β–€β–ˆβ–€β–„β–€β–„β–„Β Β β–€β–„Β β–€β–„β–€β–ˆβ–ˆβ–„β–„β–ˆβ–ˆβ–ˆβ–„β–ˆ +β–ˆβ–ˆΒ β–€β–„β–ˆβ–„β–€β–„β–„β–€β–ˆΒ β–ˆβ–€β–„Β Β β–„β–ˆβ–ˆβ–€Β Β β–„β–€β–„β–„β–€β–€Β β–„β–„β–ˆβ–ˆΒ β–€Β β–ˆ +β–ˆβ–ˆΒ Β Β β–„Β β–€β–ˆΒ β–€β–„β–€β–€β–€Β β–€β–„β–€Β β–€β–ˆΒ β–„β–ˆβ–€Β β–„β–„β–„β–€Β β–€β–„β–ˆΒ β–€β–„β–ˆ +β–ˆβ–„β–„Β β–€β–ˆβ–€β–€β–ˆβ–ˆβ–„Β β–€β–ˆβ–€Β β–„β–ˆβ–€β–ˆβ–ˆβ–„Β β–€β–ˆΒ Β β–€β–ˆΒ β–€Β β–„β–€Β β–€β–„β–ˆβ–ˆ +β–ˆβ–„β–ˆΒ β–€β–€β–„β–€β–„β–„β–„Β β–€β–„Β β–„β–ˆβ–„β–ˆβ–ˆβ–„β–„Β β–€β–„β–„β–€β–€β–„Β Β Β Β β–„β–€β–ˆβ–„Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆβ–„β–€β–„β–„β–„Β β–„β–„β–ˆβ–„β–€β–€β–€β–„β–„β–€β–ˆβ–€β–„Β Β β–€Β β–ˆβ–„β–€β–„Β Β β–ˆ +β–ˆβ–€β–„β–„Β β–ˆβ–€β–€β–„Β Β β–„β–„β–ˆΒ β–€β–„β–ˆβ–ˆβ–€β–„Β Β β–„β–ˆβ–„Β β–ˆβ–€β–€Β β–€β–€β–€β–€β–€β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–„β–€Β Β β–€β–ˆβ–ˆβ–„β–„β–„β–€β–ˆΒ β–„β–ˆβ–ˆβ–„β–ˆΒ β–€Β β–ˆβ–€β–ˆΒ β–€β–€β–€Β β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–€β–ˆβ–€β–„β–€β–„Β Β β–„Β β–ˆβ–ˆβ–€β–€Β β–„Β Β β–ˆΒ β–€β–€β–€Β β–€β–ˆΒ β–€β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€Β β–„β–„Β β–€β–„Β Β β–ˆΒ β–€β–ˆΒ Β β–€β–€β–„β–„β–€β–„β–ˆβ–ˆΒ Β β–ˆΒ β–„Β β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€Β β–„β–€β–ˆβ–€β–„β–€β–„β–€β–€β–ˆβ–ˆΒ β–„β–„Β Β β–€β–„β–ˆβ–ˆβ–„Β β–€Β β–ˆΒ β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: HOSOCJFB72CTCJAHRGGHWVOIJ3ILCF3E + +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 801817 [###############-----] 7s + +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAcZUsZ1w6OIm4pFkwh/WOMEF+zDEEx4dJHSCuhQLbPbU= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIOwcZZd5WYSb/mxtG3eIuOuntFUBYtNnNLem+G1Sz6rd +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +frequent cattle approve depend cook sample cabin episode cube arrest purpose immense +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub16xwt66cenuk7zruqrnt0ex2eddl6yrpre207sgteux8yq9sgs65qa9cuhv +nsec: nsec18mwnqhv5umdadvjeyk4w2hh883ek8pd65rr2t80w3y9v6udym3wqzu3flm +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 87C83D56825E81B42FA12ED0DD87F68D30F6700A +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdAJZkxv05nMWsL6g5llhFQ5MYlCdpKDoOstBTm +HYFFdLIAAP9k0Lq2lOUx014/yW9t5AV9M175OnUxxwKn4AYybXdrqBCxzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBIfIPVaCXoG0L6Eu0N2H9o0w9nAK +AAoJEN2H9o0w9nAKMX4BAJspg9Z/J5PBTLhBqLE5/Mzw/4Sj09FcSdqMjNbDdPCs +AQCx1AW87NlP3eT9bS+jChXk3Aw9Wc48sycFUPBF+8MiBw== +=4//T +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Op}"560o&PDw +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 020F1E7482DFB6A4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +No archived entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > 2FA Codes +No archived entries found. +Press Enter to return to the menu. +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > 2FA Codes +No archived entries found. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 801817 [#################---] 4s + +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +No archived entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Retrieve Entry + +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example +[+] Password for 'agent.example' copied to clipboard. Will clear in 45 seconds. +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Entry Actions + + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 8 + password: 1 + totp: 1 + ssh: 1 + seed: 1 + pgp: 1 + nostr: 1 + key_value: 1 + managed_account: 1 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T195720Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T195720Z/transcript.raw.txt new file mode 100644 index 00000000..72f47216 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195720Z/transcript.raw.txt @@ -0,0 +1,1114 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +total elegant metal discover leg bunker notice oval beauty holiday marine guide +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876642.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: Op}"560o&PDw + +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Op}"560o&PDw +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=HOSOCJFB72CTCJAHRGGHWVOIJ3ILCF3E&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–„β–€β–„β–€β–„β–ˆβ–€Β β–„β–„β–ˆβ–€β–ˆβ–„β–€β–ˆΒ β–„β–ˆβ–ˆΒ β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€β–ˆΒ β–ˆβ–ˆβ–ˆβ–ˆΒ β–„Β β–€β–€β–€β–€β–ˆβ–€β–„β–ˆΒ β–€β–ˆβ–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„Β β–ˆΒ β–ˆβ–€β–ˆΒ β–ˆβ–€β–„Β β–„β–€β–„β–€β–ˆβ–€β–„Β β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆβ–€β–ˆβ–ˆβ–„β–ˆβ–ˆβ–€β–„Β β–„β–„β–„Β Β β–„β–„β–€β–„β–„Β Β β–€Β β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–€β–ˆβ–ˆ +β–ˆΒ β–„Β β–€Β Β β–€Β β–€β–ˆβ–ˆβ–€β–€Β β–„β–„β–ˆΒ β–€Β β–ˆβ–€β–„Β β–€Β β–„β–„β–€β–€β–„Β β–€β–ˆβ–„β–€Β β–ˆ +β–ˆβ–ˆβ–€Β β–€Β β–€β–€β–€β–ˆΒ β–€β–€Β β–ˆβ–ˆβ–„β–ˆβ–„Β Β β–ˆΒ β–„β–€β–„Β β–„β–€β–€β–ˆΒ β–ˆβ–ˆΒ Β Β β–€β–ˆ +β–ˆβ–ˆΒ β–€Β β–ˆΒ β–€Β β–ˆΒ β–ˆβ–„β–ˆβ–„β–ˆΒ β–„β–„Β β–ˆβ–€Β Β β–ˆβ–„β–ˆβ–€β–ˆβ–€Β Β β–„β–ˆβ–„β–€Β β–ˆβ–ˆ +β–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–„β–€β–€β–ˆβ–ˆβ–„Β β–ˆΒ β–€β–ˆβ–€β–„β–€β–„β–„Β Β β–€β–„Β β–€β–„β–€β–ˆβ–ˆβ–„β–„β–ˆβ–ˆβ–ˆβ–„β–ˆ +β–ˆβ–ˆΒ β–€β–„β–ˆβ–„β–€β–„β–„β–€β–ˆΒ β–ˆβ–€β–„Β Β β–„β–ˆβ–ˆβ–€Β Β β–„β–€β–„β–„β–€β–€Β β–„β–„β–ˆβ–ˆΒ β–€Β β–ˆ +β–ˆβ–ˆΒ Β Β β–„Β β–€β–ˆΒ β–€β–„β–€β–€β–€Β β–€β–„β–€Β β–€β–ˆΒ β–„β–ˆβ–€Β β–„β–„β–„β–€Β β–€β–„β–ˆΒ β–€β–„β–ˆ +β–ˆβ–„β–„Β β–€β–ˆβ–€β–€β–ˆβ–ˆβ–„Β β–€β–ˆβ–€Β β–„β–ˆβ–€β–ˆβ–ˆβ–„Β β–€β–ˆΒ Β β–€β–ˆΒ β–€Β β–„β–€Β β–€β–„β–ˆβ–ˆ +β–ˆβ–„β–ˆΒ β–€β–€β–„β–€β–„β–„β–„Β β–€β–„Β β–„β–ˆβ–„β–ˆβ–ˆβ–„β–„Β β–€β–„β–„β–€β–€β–„Β Β Β Β β–„β–€β–ˆβ–„Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆβ–„β–€β–„β–„β–„Β β–„β–„β–ˆβ–„β–€β–€β–€β–„β–„β–€β–ˆβ–€β–„Β Β β–€Β β–ˆβ–„β–€β–„Β Β β–ˆ +β–ˆβ–€β–„β–„Β β–ˆβ–€β–€β–„Β Β β–„β–„β–ˆΒ β–€β–„β–ˆβ–ˆβ–€β–„Β Β β–„β–ˆβ–„Β β–ˆβ–€β–€Β β–€β–€β–€β–€β–€β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–„β–€Β Β β–€β–ˆβ–ˆβ–„β–„β–„β–€β–ˆΒ β–„β–ˆβ–ˆβ–„β–ˆΒ β–€Β β–ˆβ–€β–ˆΒ β–€β–€β–€Β β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–€β–ˆβ–€β–„β–€β–„Β Β β–„Β β–ˆβ–ˆβ–€β–€Β β–„Β Β β–ˆΒ β–€β–€β–€Β β–€β–ˆΒ β–€β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–€Β β–„β–„Β β–€β–„Β Β β–ˆΒ β–€β–ˆΒ Β β–€β–€β–„β–„β–€β–„β–ˆβ–ˆΒ Β β–ˆΒ β–„Β β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€Β β–„β–€β–ˆβ–€β–„β–€β–„β–€β–€β–ˆβ–ˆΒ β–„β–„Β Β β–€β–„β–ˆβ–ˆβ–„Β β–€Β β–ˆΒ β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: HOSOCJFB72CTCJAHRGGHWVOIJ3ILCF3E + +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 801817 [###############-----] 7s + +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAcZUsZ1w6OIm4pFkwh/WOMEF+zDEEx4dJHSCuhQLbPbU= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIOwcZZd5WYSb/mxtG3eIuOuntFUBYtNnNLem+G1Sz6rd +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +frequent cattle approve depend cook sample cabin episode cube arrest purpose immense +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub16xwt66cenuk7zruqrnt0ex2eddl6yrpre207sgteux8yq9sgs65qa9cuhv +nsec: nsec18mwnqhv5umdadvjeyk4w2hh883ek8pd65rr2t80w3y9v6udym3wqzu3flm +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 87C83D56825E81B42FA12ED0DD87F68D30F6700A +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdAJZkxv05nMWsL6g5llhFQ5MYlCdpKDoOstBTm +HYFFdLIAAP9k0Lq2lOUx014/yW9t5AV9M175OnUxxwKn4AYybXdrqBCxzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBIfIPVaCXoG0L6Eu0N2H9o0w9nAK +AAoJEN2H9o0w9nAKMX4BAJspg9Z/J5PBTLhBqLE5/Mzw/4Sj09FcSdqMjNbDdPCs +AQCx1AW87NlP3eT9bS+jChXk3Aw9Wc48sycFUPBF+8MiBw== +=4//T +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: Op}"560o&PDw +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 020F1E7482DFB6A4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups/entries_db_backup_1771876643.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +No archived entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > 2FA Codes +No archived entries found. +Press Enter to return to the menu. +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > 2FA Codes +No archived entries found. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 801817 [#################---] 4s + +cSeed Profile: 020F1E7482DFB6A4 > Main Menu +No archived entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 020F1E7482DFB6A4 > Main Menu > Retrieve Entry + +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example +[+] Password for 'agent.example' copied to clipboard. Will clear in 45 seconds. +Press Enter to continue... +cSeed Profile: 020F1E7482DFB6A4 > Entry Actions + + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 8 + password: 1 + totp: 1 + ssh: 1 + seed: 1 + pgp: 1 + nostr: 1 + key_value: 1 + managed_account: 1 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-f_yj1_os/.seedpass/020F1E7482DFB6A4/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 020F1E7482DFB6A4 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195810Z/report.json b/artifacts/agent_tui_test/20260223T195810Z/report.json new file mode 100644 index 00000000..c09ec941 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195810Z/report.json @@ -0,0 +1,74 @@ +{ + "timestamp_utc": "20260223T195810Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-fjwh1hoo", + "scenario": "extended", + "stress_cycles": null, + "stress_seed": null, + "required_coverage_keys": [ + "startup_onboarding", + "main_menu", + "invalid_input_resilience", + "add_password_quick", + "invalid_length_validation", + "add_totp", + "add_all_entry_types", + "retrieve_entry", + "search_entries", + "list_entries", + "modify_entry", + "archive_restore", + "totp_codes_view", + "settings_toggles_lock_unlock", + "settings_stats", + "graceful_exit" + ], + "required_post_conditions": [ + "archive_restore_consistency", + "lock_unlock_recovers_retrieval" + ], + "duration_sec": 32.945, + "seedpass_exit_code": -11, + "status": "failed", + "failure": "SeedPass exited with non-zero code: -11", + "steps": [ + { + "step_id": "extended_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 32.24307111899907, + "detail": null + } + ], + "coverage_points": { + "add_all_entry_types": true, + "add_password_quick": true, + "add_totp": true, + "archive_restore": true, + "graceful_exit": true, + "invalid_input_resilience": true, + "invalid_length_validation": true, + "list_entries": true, + "main_menu": true, + "modify_entry": true, + "retrieve_entry": true, + "search_entries": true, + "seeded_negative_campaign": false, + "settings_stats": true, + "settings_toggles_lock_unlock": true, + "startup_onboarding": true, + "stress_cycles": false, + "totp_codes_view": true + }, + "post_conditions": { + "archive_restore_consistency": true, + "lock_unlock_recovers_retrieval": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T195810Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T195810Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195810Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T195810Z/transcript.clean.txt new file mode 100644 index 00000000..b37b0056 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195810Z/transcript.clean.txt @@ -0,0 +1,1113 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +science lazy grocery awkward rib high wool mimic parent snack illness piano +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 41983442A308EAB4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 41983442A308EAB4 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876693.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: 306:Jps#Xi#S + +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 41983442A308EAB4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 306:Jps#Xi#S +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 41983442A308EAB4 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 41983442A308EAB4 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 41983442A308EAB4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 41983442A308EAB4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 41983442A308EAB4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 41983442A308EAB4 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876693.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=FR7Y7CQRAQONPZIQBY5B7RPO7N4ZJBIL&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆβ–ˆβ–„β–ˆβ–ˆΒ Β Β Β β–€Β β–€Β β–€β–€Β β–ˆβ–„Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–€β–„β–ˆβ–„β–€Β Β β–ˆΒ β–€β–„β–€β–€Β β–€β–„Β Β β–€Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–„β–€β–„β–€β–ˆΒ β–ˆβ–€β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€Β β–ˆβ–€β–ˆΒ Β β–€Β Β β–„Β β–ˆβ–„β–„β–„β–„β–„β–ˆΒ β–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–„β–„Β Β β–„β–ˆβ–€β–„β–ˆβ–€β–ˆβ–€Β β–„β–ˆβ–€β–ˆβ–ˆβ–„Β Β β–„β–„β–ˆβ–„Β β–€β–€β–€β–„Β β–„β–€β–€β–„β–„β–ˆβ–ˆ +β–ˆβ–€β–€β–„β–ˆΒ β–€β–€Β β–€β–ˆβ–„Β β–€Β β–„β–„β–„β–€β–€β–ˆβ–ˆΒ β–€β–€β–„β–ˆβ–„β–€β–„β–ˆΒ Β β–„β–„Β Β β–€β–ˆ +β–ˆΒ Β Β Β β–€Β β–€β–„β–ˆβ–€β–„Β β–„β–„Β β–ˆβ–„β–€β–ˆβ–ˆβ–„β–ˆΒ Β β–€β–ˆβ–„Β β–€β–ˆβ–ˆβ–„Β β–€β–€Β β–„β–ˆ +β–ˆβ–„β–„β–€Β β–€β–€β–€Β Β β–€β–€β–„β–„Β β–„Β β–ˆβ–„β–€β–€β–„Β β–ˆβ–€β–„β–ˆβ–€β–„Β β–ˆβ–€β–ˆβ–„β–ˆΒ β–„Β β–ˆ +β–ˆβ–„β–€β–ˆΒ β–€β–€β–€Β β–„β–„β–€β–€Β Β Β β–ˆΒ β–„Β β–ˆβ–„β–ˆΒ β–€β–„β–„β–€β–„β–„β–ˆβ–€β–„Β β–€β–ˆβ–„β–ˆβ–ˆ +β–ˆΒ β–„Β Β β–ˆβ–„β–€β–„Β β–€β–ˆΒ β–ˆβ–„β–ˆβ–€β–€Β β–€β–„β–ˆΒ β–€β–ˆβ–€β–ˆβ–„Β Β β–€Β β–ˆβ–„Β β–„β–€β–„β–ˆ +β–ˆβ–„β–ˆΒ β–€β–„β–„β–€β–€Β β–€β–ˆΒ β–ˆβ–€β–„β–ˆβ–€β–„Β β–ˆβ–€β–ˆβ–€Β β–ˆΒ β–„Β Β Β β–ˆβ–„β–„β–ˆβ–€β–€β–ˆβ–ˆ +β–ˆΒ β–€Β β–„β–€β–ˆβ–€β–€Β β–„β–ˆβ–€β–€β–ˆΒ β–ˆβ–€β–ˆβ–ˆβ–€β–„Β β–„β–„β–„β–„β–€β–„β–€β–ˆβ–ˆβ–ˆΒ β–€Β β–€β–„β–ˆ +β–ˆβ–„β–„Β β–„β–€β–„β–€Β β–„β–ˆβ–ˆΒ β–„β–„β–ˆβ–€β–ˆβ–„β–„β–€β–„β–€β–„β–„Β β–€β–€β–ˆβ–€β–ˆβ–ˆβ–€β–„β–ˆβ–€β–ˆβ–ˆβ–ˆ +β–ˆβ–€β–€β–„Β β–ˆβ–„β–€Β β–ˆβ–€Β β–€β–„Β β–ˆβ–„Β β–€Β β–€Β Β β–€β–ˆβ–„β–ˆβ–ˆΒ Β Β β–€Β β–€Β β–„β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ β–€β–„Β β–ˆβ–„β–€β–€Β β–€β–„β–ˆβ–ˆβ–€β–ˆΒ β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ β–„β–€Β Β β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€Β β–ˆΒ β–„Β β–„β–€β–ˆβ–„Β Β β–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–€β–€β–€Β β–€Β β–„β–ˆβ–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆβ–„Β β–„β–ˆβ–€β–€β–ˆΒ β–€β–€β–€Β β–ˆΒ β–„β–„β–„β–€β–„β–„Β Β Β β–ˆβ–„Β β–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–ˆβ–ˆβ–€Β β–€β–€β–€β–€β–„Β Β β–ˆΒ β–€β–„Β β–ˆβ–€β–€Β β–ˆβ–„β–ˆβ–€β–„β–ˆΒ β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: FR7Y7CQRAQONPZIQBY5B7RPO7N4ZJBIL + +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 41983442A308EAB4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 41983442A308EAB4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 578953 [########------------] 17s + +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: 41983442A308EAB4 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876693.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAPiynEMRRfH+1MgzGavVK9h2dkJwPPXdYTfGGXtMQK2o= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIDjBXNhBo577lJeYf/UE53Cg/8BOuAr41GbfItYdRDA0 +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: 41983442A308EAB4 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876693.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +crucial certain unit frost width large interest engine pioneer cart sleep joke +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: 41983442A308EAB4 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876693.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub1qxrlgdtga7hpepjfdn4r9xq6kwgku7fgl34pdl92f7502thf9y9qtlrvsv +nsec: nsec1ruxvj07hjpu32htyx6puxhwdr0l74zc7t0sz9kzel04wk4lzf84syap2dy +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: 41983442A308EAB4 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876694.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 02AAFF940DCB615ADA399930F14762761B32E1E1 +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdA0b4KwqpxoB2RTihKjBTo/7sijvQqwLgiYBmL +byBi2EMAAP47O8HxNocFR6Y5JflzOOM6NBpMAvD2ckhQg3DURuZTig9QzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBAKq/5QNy2Fa2jmZMPFHYnYbMuHh +AAoJEPFHYnYbMuHh/PAA/iIhntVe6/0PaVvVYqeaLgbDlcFSfiueHe6d7VmL/5O6 +AP9VLbdJ6XB/1tq/H04rvt7GpnqN2TcsoSC17TyWDABOAg== +=JCSx +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: 41983442A308EAB4 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876694.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: 41983442A308EAB4 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876694.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 41983442A308EAB4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 41983442A308EAB4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: 41983442A308EAB4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 41983442A308EAB4 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876694.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 41983442A308EAB4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 306:Jps#Xi#S +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876694.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 41983442A308EAB4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 41983442A308EAB4 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876694.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +No archived entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 41983442A308EAB4 > Main Menu > 2FA Codes +No archived entries found. +Press Enter to return to the menu. +cSeed Profile: 41983442A308EAB4 > Main Menu > 2FA Codes +No archived entries found. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 578953 [###########---------] 13s + +cSeed Profile: 41983442A308EAB4 > Main Menu +No archived entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 41983442A308EAB4 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 41983442A308EAB4 > Main Menu > Retrieve Entry + +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example +[+] Password for 'agent.example' copied to clipboard. Will clear in 45 seconds. +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Entry Actions + + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 41983442A308EAB4 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 8 + password: 1 + totp: 1 + ssh: 1 + seed: 1 + pgp: 1 + nostr: 1 + key_value: 1 + managed_account: 1 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 41983442A308EAB4 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T195810Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T195810Z/transcript.raw.txt new file mode 100644 index 00000000..eb0c47da --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195810Z/transcript.raw.txt @@ -0,0 +1,1114 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +science lazy grocery awkward rib high wool mimic parent snack illness piano +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 41983442A308EAB4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 41983442A308EAB4 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876693.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: 306:Jps#Xi#S + +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 41983442A308EAB4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 306:Jps#Xi#S +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 41983442A308EAB4 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 41983442A308EAB4 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 41983442A308EAB4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 41983442A308EAB4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 41983442A308EAB4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: 41983442A308EAB4 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876693.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=FR7Y7CQRAQONPZIQBY5B7RPO7N4ZJBIL&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆβ–ˆβ–„β–ˆβ–ˆΒ Β Β Β β–€Β β–€Β β–€β–€Β β–ˆβ–„Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–€β–„β–ˆβ–„β–€Β Β β–ˆΒ β–€β–„β–€β–€Β β–€β–„Β Β β–€Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–„β–€β–„β–€β–ˆΒ β–ˆβ–€β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€Β β–ˆβ–€β–ˆΒ Β β–€Β Β β–„Β β–ˆβ–„β–„β–„β–„β–„β–ˆΒ β–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–ˆ +β–ˆβ–„β–„Β Β β–„β–ˆβ–€β–„β–ˆβ–€β–ˆβ–€Β β–„β–ˆβ–€β–ˆβ–ˆβ–„Β Β β–„β–„β–ˆβ–„Β β–€β–€β–€β–„Β β–„β–€β–€β–„β–„β–ˆβ–ˆ +β–ˆβ–€β–€β–„β–ˆΒ β–€β–€Β β–€β–ˆβ–„Β β–€Β β–„β–„β–„β–€β–€β–ˆβ–ˆΒ β–€β–€β–„β–ˆβ–„β–€β–„β–ˆΒ Β β–„β–„Β Β β–€β–ˆ +β–ˆΒ Β Β Β β–€Β β–€β–„β–ˆβ–€β–„Β β–„β–„Β β–ˆβ–„β–€β–ˆβ–ˆβ–„β–ˆΒ Β β–€β–ˆβ–„Β β–€β–ˆβ–ˆβ–„Β β–€β–€Β β–„β–ˆ +β–ˆβ–„β–„β–€Β β–€β–€β–€Β Β β–€β–€β–„β–„Β β–„Β β–ˆβ–„β–€β–€β–„Β β–ˆβ–€β–„β–ˆβ–€β–„Β β–ˆβ–€β–ˆβ–„β–ˆΒ β–„Β β–ˆ +β–ˆβ–„β–€β–ˆΒ β–€β–€β–€Β β–„β–„β–€β–€Β Β Β β–ˆΒ β–„Β β–ˆβ–„β–ˆΒ β–€β–„β–„β–€β–„β–„β–ˆβ–€β–„Β β–€β–ˆβ–„β–ˆβ–ˆ +β–ˆΒ β–„Β Β β–ˆβ–„β–€β–„Β β–€β–ˆΒ β–ˆβ–„β–ˆβ–€β–€Β β–€β–„β–ˆΒ β–€β–ˆβ–€β–ˆβ–„Β Β β–€Β β–ˆβ–„Β β–„β–€β–„β–ˆ +β–ˆβ–„β–ˆΒ β–€β–„β–„β–€β–€Β β–€β–ˆΒ β–ˆβ–€β–„β–ˆβ–€β–„Β β–ˆβ–€β–ˆβ–€Β β–ˆΒ β–„Β Β Β β–ˆβ–„β–„β–ˆβ–€β–€β–ˆβ–ˆ +β–ˆΒ β–€Β β–„β–€β–ˆβ–€β–€Β β–„β–ˆβ–€β–€β–ˆΒ β–ˆβ–€β–ˆβ–ˆβ–€β–„Β β–„β–„β–„β–„β–€β–„β–€β–ˆβ–ˆβ–ˆΒ β–€Β β–€β–„β–ˆ +β–ˆβ–„β–„Β β–„β–€β–„β–€Β β–„β–ˆβ–ˆΒ β–„β–„β–ˆβ–€β–ˆβ–„β–„β–€β–„β–€β–„β–„Β β–€β–€β–ˆβ–€β–ˆβ–ˆβ–€β–„β–ˆβ–€β–ˆβ–ˆβ–ˆ +β–ˆβ–€β–€β–„Β β–ˆβ–„β–€Β β–ˆβ–€Β β–€β–„Β β–ˆβ–„Β β–€Β β–€Β Β β–€β–ˆβ–„β–ˆβ–ˆΒ Β Β β–€Β β–€Β β–„β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ β–€β–„Β β–ˆβ–„β–€β–€Β β–€β–„β–ˆβ–ˆβ–€β–ˆΒ β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ β–„β–€Β Β β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€Β β–ˆΒ β–„Β β–„β–€β–ˆβ–„Β Β β–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–€β–€β–€Β β–€Β β–„β–ˆβ–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆβ–„Β β–„β–ˆβ–€β–€β–ˆΒ β–€β–€β–€Β β–ˆΒ β–„β–„β–„β–€β–„β–„Β Β Β β–ˆβ–„Β β–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–ˆβ–ˆβ–€Β β–€β–€β–€β–€β–„Β Β β–ˆΒ β–€β–„Β β–ˆβ–€β–€Β β–ˆβ–„β–ˆβ–€β–„β–ˆΒ β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: FR7Y7CQRAQONPZIQBY5B7RPO7N4ZJBIL + +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 41983442A308EAB4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: 41983442A308EAB4 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 578953 [########------------] 17s + +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: 41983442A308EAB4 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876693.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAPiynEMRRfH+1MgzGavVK9h2dkJwPPXdYTfGGXtMQK2o= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIDjBXNhBo577lJeYf/UE53Cg/8BOuAr41GbfItYdRDA0 +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: 41983442A308EAB4 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876693.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +crucial certain unit frost width large interest engine pioneer cart sleep joke +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: 41983442A308EAB4 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876693.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub1qxrlgdtga7hpepjfdn4r9xq6kwgku7fgl34pdl92f7502thf9y9qtlrvsv +nsec: nsec1ruxvj07hjpu32htyx6puxhwdr0l74zc7t0sz9kzel04wk4lzf84syap2dy +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: 41983442A308EAB4 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876694.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: 02AAFF940DCB615ADA399930F14762761B32E1E1 +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdA0b4KwqpxoB2RTihKjBTo/7sijvQqwLgiYBmL +byBi2EMAAP47O8HxNocFR6Y5JflzOOM6NBpMAvD2ckhQg3DURuZTig9QzQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBAKq/5QNy2Fa2jmZMPFHYnYbMuHh +AAoJEPFHYnYbMuHh/PAA/iIhntVe6/0PaVvVYqeaLgbDlcFSfiueHe6d7VmL/5O6 +AP9VLbdJ6XB/1tq/H04rvt7GpnqN2TcsoSC17TyWDABOAg== +=JCSx +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: 41983442A308EAB4 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876694.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: 41983442A308EAB4 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876694.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 41983442A308EAB4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 41983442A308EAB4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: 41983442A308EAB4 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: 41983442A308EAB4 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876694.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 41983442A308EAB4 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 306:Jps#Xi#S +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876694.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: 41983442A308EAB4 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: 41983442A308EAB4 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups/entries_db_backup_1771876694.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Main Menu +No archived entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: 41983442A308EAB4 > Main Menu > 2FA Codes +No archived entries found. +Press Enter to return to the menu. +cSeed Profile: 41983442A308EAB4 > Main Menu > 2FA Codes +No archived entries found. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 578953 [###########---------] 13s + +cSeed Profile: 41983442A308EAB4 > Main Menu +No archived entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 41983442A308EAB4 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 41983442A308EAB4 > Main Menu > Retrieve Entry + +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example +[+] Password for 'agent.example' copied to clipboard. Will clear in 45 seconds. +Press Enter to continue... +cSeed Profile: 41983442A308EAB4 > Entry Actions + + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 41983442A308EAB4 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 8 + password: 1 + totp: 1 + ssh: 1 + seed: 1 + pgp: 1 + nostr: 1 + key_value: 1 + managed_account: 1 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-fjwh1hoo/.seedpass/41983442A308EAB4/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: 41983442A308EAB4 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195857Z/report.json b/artifacts/agent_tui_test/20260223T195857Z/report.json new file mode 100644 index 00000000..442b5984 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195857Z/report.json @@ -0,0 +1,64 @@ +{ + "timestamp_utc": "20260223T195857Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-u6y3w9ir", + "scenario": "core", + "stress_cycles": null, + "stress_seed": null, + "required_coverage_keys": [ + "startup_onboarding", + "main_menu", + "invalid_input_resilience", + "add_password_quick", + "invalid_length_validation", + "retrieve_entry", + "search_entries", + "list_entries", + "graceful_exit" + ], + "required_post_conditions": [], + "duration_sec": 2.936, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "core_scenario", + "description": "Drive deterministic core TUI scenario.", + "status": "passed", + "duration_sec": 2.868767048999871, + "detail": null + } + ], + "coverage_points": { + "add_all_entry_types": false, + "add_password_quick": true, + "add_totp": false, + "archive_restore": false, + "graceful_exit": true, + "invalid_input_resilience": true, + "invalid_length_validation": true, + "list_entries": true, + "main_menu": true, + "modify_entry": false, + "retrieve_entry": true, + "search_entries": true, + "seeded_negative_campaign": false, + "settings_stats": false, + "settings_toggles_lock_unlock": false, + "startup_onboarding": true, + "stress_cycles": false, + "totp_codes_view": false + }, + "post_conditions": { + "archive_restore_consistency": false, + "lock_unlock_recovers_retrieval": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T195857Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T195857Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195857Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T195857Z/transcript.clean.txt new file mode 100644 index 00000000..fe15af11 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195857Z/transcript.clean.txt @@ -0,0 +1,287 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +sibling word paper intact weasel soon staff bargain child toss swarm pistol +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-u6y3w9ir/.seedpass/332992710872853C/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 332992710872853C > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 332992710872853C > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 332992710872853C > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 332992710872853C > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: 332992710872853C > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 332992710872853C > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-u6y3w9ir/.seedpass/332992710872853C/backups/entries_db_backup_1771876740.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: 4K9[*oz1Lo&O + +Press Enter to continue... +cSeed Profile: 332992710872853C > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 332992710872853C > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 4K9[*oz1Lo&O +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 332992710872853C > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 332992710872853C > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 332992710872853C > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 332992710872853C > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 332992710872853C > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 332992710872853C > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 332992710872853C > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 332992710872853C > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 332992710872853C > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T195857Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T195857Z/transcript.raw.txt new file mode 100644 index 00000000..d1f29bb4 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195857Z/transcript.raw.txt @@ -0,0 +1,288 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +sibling word paper intact weasel soon staff bargain child toss swarm pistol +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-u6y3w9ir/.seedpass/332992710872853C/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: 332992710872853C > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: 332992710872853C > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 332992710872853C > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 332992710872853C > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: 332992710872853C > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 332992710872853C > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-u6y3w9ir/.seedpass/332992710872853C/backups/entries_db_backup_1771876740.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: 4K9[*oz1Lo&O + +Press Enter to continue... +cSeed Profile: 332992710872853C > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: 332992710872853C > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 4K9[*oz1Lo&O +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: 332992710872853C > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: 332992710872853C > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: 332992710872853C > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: 332992710872853C > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: 332992710872853C > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: 332992710872853C > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: 332992710872853C > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: 332992710872853C > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: 332992710872853C > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195904Z/report.json b/artifacts/agent_tui_test/20260223T195904Z/report.json new file mode 100644 index 00000000..fb7091dc --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195904Z/report.json @@ -0,0 +1,64 @@ +{ + "timestamp_utc": "20260223T195904Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-qky92rjl", + "scenario": "stress", + "stress_cycles": 2, + "stress_seed": 1337, + "required_coverage_keys": [ + "startup_onboarding", + "main_menu", + "add_password_quick", + "invalid_input_resilience", + "retrieve_entry", + "list_entries", + "stress_cycles", + "seeded_negative_campaign", + "graceful_exit" + ], + "required_post_conditions": [], + "duration_sec": 3.391, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "stress_scenario", + "description": "Drive deterministic stress TUI scenario.", + "status": "passed", + "duration_sec": 3.3109931079998205, + "detail": null + } + ], + "coverage_points": { + "add_all_entry_types": false, + "add_password_quick": true, + "add_totp": false, + "archive_restore": false, + "graceful_exit": true, + "invalid_input_resilience": true, + "invalid_length_validation": false, + "list_entries": true, + "main_menu": true, + "modify_entry": false, + "retrieve_entry": true, + "search_entries": false, + "seeded_negative_campaign": true, + "settings_stats": false, + "settings_toggles_lock_unlock": false, + "startup_onboarding": true, + "stress_cycles": true, + "totp_codes_view": false + }, + "post_conditions": { + "archive_restore_consistency": false, + "lock_unlock_recovers_retrieval": false + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T195904Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T195904Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195904Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T195904Z/transcript.clean.txt new file mode 100644 index 00000000..215aafa0 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195904Z/transcript.clean.txt @@ -0,0 +1,424 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +bike flip shop total analyst lava emotion luggage monster maximum wrist child +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-qky92rjl/.seedpass/B68ABA022AA73707/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: B68ABA022AA73707 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: stress.example +Enter the username (optional): stress +Enter the URL (optional): https://stress.example +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-qky92rjl/.seedpass/B68ABA022AA73707/backups/entries_db_backup_1771876747.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for stress.example: nnG3&Lz]N#23 + +Press Enter to continue... +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: one +Invalid choice. Please select a valid option. +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: one +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: B68ABA022AA73707 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0x1 +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: B68ABA022AA73707 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: B68ABA022AA73707 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - stress.example +Enter index to view details or press Enter to go back: +cSeed Profile: B68ABA022AA73707 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: B68ABA022AA73707 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'stress.example' with length 12. +Username: stress +URL: https://stress.example + +[+] Retrieved Password for stress.example: + +Password: nnG3&Lz]N#23 +Associated Username: stress +Associated URL: https://stress.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: B68ABA022AA73707 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: x +Invalid choice. Please select a valid option. +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: one +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: B68ABA022AA73707 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: index +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: B68ABA022AA73707 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: B68ABA022AA73707 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - stress.example +Enter index to view details or press Enter to go back: +cSeed Profile: B68ABA022AA73707 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: B68ABA022AA73707 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'stress.example' with length 12. +Username: stress +URL: https://stress.example + +[+] Retrieved Password for stress.example: + +Password: nnG3&Lz]N#23 +Associated Username: stress +Associated URL: https://stress.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: B68ABA022AA73707 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T195904Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T195904Z/transcript.raw.txt new file mode 100644 index 00000000..7886a041 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195904Z/transcript.raw.txt @@ -0,0 +1,425 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +bike flip shop total analyst lava emotion luggage monster maximum wrist child +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-qky92rjl/.seedpass/B68ABA022AA73707/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: B68ABA022AA73707 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: stress.example +Enter the username (optional): stress +Enter the URL (optional): https://stress.example +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-qky92rjl/.seedpass/B68ABA022AA73707/backups/entries_db_backup_1771876747.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for stress.example: nnG3&Lz]N#23 + +Press Enter to continue... +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: one +Invalid choice. Please select a valid option. +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: one +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: B68ABA022AA73707 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0x1 +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: B68ABA022AA73707 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: B68ABA022AA73707 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - stress.example +Enter index to view details or press Enter to go back: +cSeed Profile: B68ABA022AA73707 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: B68ABA022AA73707 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'stress.example' with length 12. +Username: stress +URL: https://stress.example + +[+] Retrieved Password for stress.example: + +Password: nnG3&Lz]N#23 +Associated Username: stress +Associated URL: https://stress.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: B68ABA022AA73707 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: x +Invalid choice. Please select a valid option. +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: one +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: B68ABA022AA73707 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: index +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: B68ABA022AA73707 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: B68ABA022AA73707 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - stress.example +Enter index to view details or press Enter to go back: +cSeed Profile: B68ABA022AA73707 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: B68ABA022AA73707 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'stress.example' with length 12. +Username: stress +URL: https://stress.example + +[+] Retrieved Password for stress.example: + +Password: nnG3&Lz]N#23 +Associated Username: stress +Associated URL: https://stress.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: B68ABA022AA73707 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: B68ABA022AA73707 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195911Z/report.json b/artifacts/agent_tui_test/20260223T195911Z/report.json new file mode 100644 index 00000000..9ee431f5 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195911Z/report.json @@ -0,0 +1,74 @@ +{ + "timestamp_utc": "20260223T195911Z", + "command": [ + "/home/user/Documents/GitHub/SeedPass/.venv/bin/python", + "/home/user/Documents/GitHub/SeedPass/src/main.py", + "--no-clipboard" + ], + "repo_root": "/home/user/Documents/GitHub/SeedPass", + "home_dir": "/tmp/seedpass-agent-home-f1a0vwbh", + "scenario": "extended", + "stress_cycles": null, + "stress_seed": null, + "required_coverage_keys": [ + "startup_onboarding", + "main_menu", + "invalid_input_resilience", + "add_password_quick", + "invalid_length_validation", + "add_totp", + "add_all_entry_types", + "retrieve_entry", + "search_entries", + "list_entries", + "modify_entry", + "archive_restore", + "totp_codes_view", + "settings_toggles_lock_unlock", + "settings_stats", + "graceful_exit" + ], + "required_post_conditions": [ + "archive_restore_consistency", + "lock_unlock_recovers_retrieval" + ], + "duration_sec": 32.211, + "seedpass_exit_code": 0, + "status": "passed", + "failure": null, + "steps": [ + { + "step_id": "extended_scenario", + "description": "Drive end-to-end deterministic TUI coverage workflow.", + "status": "passed", + "duration_sec": 32.00917801000105, + "detail": null + } + ], + "coverage_points": { + "add_all_entry_types": true, + "add_password_quick": true, + "add_totp": true, + "archive_restore": true, + "graceful_exit": true, + "invalid_input_resilience": true, + "invalid_length_validation": true, + "list_entries": true, + "main_menu": true, + "modify_entry": true, + "retrieve_entry": true, + "search_entries": true, + "seeded_negative_campaign": false, + "settings_stats": true, + "settings_toggles_lock_unlock": true, + "startup_onboarding": true, + "stress_cycles": false, + "totp_codes_view": true + }, + "post_conditions": { + "archive_restore_consistency": true, + "lock_unlock_recovers_retrieval": true + }, + "transcript_clean": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T195911Z/transcript.clean.txt", + "transcript_raw": "/home/user/Documents/GitHub/SeedPass/artifacts/agent_tui_test/20260223T195911Z/transcript.raw.txt" +} \ No newline at end of file diff --git a/artifacts/agent_tui_test/20260223T195911Z/transcript.clean.txt b/artifacts/agent_tui_test/20260223T195911Z/transcript.clean.txt new file mode 100644 index 00000000..b4e0228a --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195911Z/transcript.clean.txt @@ -0,0 +1,1113 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +series salad chase belt furnace token junk agent trade glove tomato empty +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: D4C2D59F95930932 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: D4C2D59F95930932 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876753.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: 8O=bRa"5A^m3 + +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: D4C2D59F95930932 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 8O=bRa"5A^m3 +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: D4C2D59F95930932 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: D4C2D59F95930932 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: D4C2D59F95930932 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: D4C2D59F95930932 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: D4C2D59F95930932 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: D4C2D59F95930932 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=JD4OTOJ36N62O3PSC2MBBRMK4R6ATGQH&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–€β–€β–ˆβ–€β–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆΒ Β β–ˆβ–ˆΒ Β Β β–„β–€Β β–€Β β–€β–€Β β–ˆβ–„Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–€β–€Β β–€β–ˆβ–„β–„β–ˆΒ β–€β–„β–€β–€Β β–€β–„Β Β β–€Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–„β–€β–„β–€β–ˆβ–€β–„β–€β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€Β β–„β–€β–„β–„β–ˆβ–„β–ˆΒ β–„Β β–ˆβ–„β–„β–„β–„β–„β–ˆΒ β–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–ˆ +β–ˆΒ Β Β β–ˆβ–€β–„β–€β–„β–„Β Β Β Β β–ˆβ–„β–€β–ˆβ–ˆβ–„Β Β β–„β–„β–ˆβ–„Β β–€β–€β–€β–ˆΒ Β β–„Β β–€β–„β–ˆβ–ˆ +β–ˆβ–€β–ˆβ–„β–ˆβ–€β–€β–€β–€Β β–€β–„β–€β–ˆβ–„β–€β–„Β Β β–„β–ˆβ–ˆΒ β–€β–€β–„β–ˆβ–„β–€β–„β–ˆΒ β–€β–„β–„β–„Β β–€β–ˆ +β–ˆβ–ˆΒ β–„β–„β–€β–„β–€β–€Β Β β–€β–€β–„Β β–€β–€Β β–€β–„β–ˆβ–„β–ˆΒ Β β–€β–ˆβ–„Β β–€β–ˆβ–€β–„Β β–€β–€β–ˆβ–€β–ˆ +β–ˆβ–„β–ˆβ–€β–ˆΒ β–„β–€Β β–ˆβ–ˆβ–„Β β–ˆβ–„β–ˆβ–ˆβ–„β–„β–€β–€β–„Β β–ˆβ–€β–„β–ˆβ–€β–„Β Β β–ˆβ–ˆβ–„β–ˆΒ Β β–„β–ˆ +β–ˆβ–€Β β–„β–€β–ˆβ–„β–€β–€Β Β β–„β–€β–ˆβ–€β–€β–ˆΒ β–€Β β–ˆβ–„β–ˆΒ β–€β–„β–„β–€β–€β–ˆβ–„β–€β–€β–ˆβ–€β–„β–„β–ˆβ–ˆ +β–ˆβ–€β–€β–€β–„β–€β–ˆβ–€β–€β–€β–ˆβ–€Β β–ˆβ–€β–ˆβ–€β–€β–„β–€β–„β–ˆΒ β–€β–ˆβ–€β–ˆβ–„β–„β–€β–€Β β–ˆβ–„Β β–„β–€β–„β–ˆ +β–ˆβ–ˆβ–„Β β–„β–ˆΒ β–€β–€β–ˆβ–„β–€β–„β–ˆβ–ˆβ–„β–€β–ˆβ–„β–€β–ˆβ–€β–ˆβ–€Β β–ˆΒ β–„Β Β Β β–ˆβ–„β–„β–ˆβ–€β–€β–„β–ˆ +β–ˆβ–ˆβ–€β–€Β β–ˆβ–€β–€Β β–€β–„Β β–ˆΒ β–„β–„Β β–€β–ˆβ–ˆβ–€β–„Β β–„β–„β–„β–„β–€β–„β–ˆβ–„Β β–€β–„β–€Β β–ˆβ–€β–ˆ +β–ˆβ–„β–„β–„β–€β–„β–ˆβ–€Β β–ˆβ–ˆβ–€β–ˆβ–€β–„β–ˆβ–€β–ˆΒ β–„β–€β–„β–€β–„β–„Β β–€β–€Β Β β–„β–ˆβ–„β–„Β β–„β–ˆβ–ˆβ–ˆ +β–ˆβ–€β–€β–€β–„β–„β–€β–€β–„β–ˆβ–€β–„Β β–„Β Β β–„β–„β–ˆΒ β–€Β Β β–€β–ˆβ–„β–ˆβ–ˆβ–€Β Β β–€β–€Β β–€Β β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ Β β–ˆβ–€Β β–ˆβ–€β–„β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆΒ β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ β–„β–€β–€β–ˆβ–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–€Β β–„β–„β–€β–ˆβ–„β–ˆβ–„Β Β β–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–€β–€β–€Β β–€Β β–„Β β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆΒ Β Β β–„β–„β–„β–ˆΒ β–€β–€β–€Β β–ˆΒ β–„β–„β–„β–€β–„β–„Β Β Β β–ˆβ–„Β β–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„Β Β Β β–„β–„β–€β–ˆβ–ˆβ–ˆΒ β–ˆΒ β–€β–„Β β–ˆβ–€Β β–„Β β–€β–ˆβ–€β–„Β Β β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: JD4OTOJ36N62O3PSC2MBBRMK4R6ATGQH + +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: D4C2D59F95930932 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: D4C2D59F95930932 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 447326 [#########-----------] 16s + +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: D4C2D59F95930932 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEA7WEA5n75ov8dpPh82MxKfX5klZqb44dswnmTWNp+Ljg= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIGFrH1lkgsQRXsZd90u6orwen1smBoZWqXlW+lgBiQBm +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: D4C2D59F95930932 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +bone garment crouch enrich outdoor vault casual toe pupil safe alley struggle +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: D4C2D59F95930932 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub1phl2pv9cjgz497hh90dht8l3ygsulmcttjw4tveku7yjhksddvnqkv7wkv +nsec: nsec1f3ula2u5t73qftwy60hrdgtg5kyk6etqugd3m567hs8m8crr407qgyk9yf +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: D4C2D59F95930932 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: DE27A3CC3E44882FFFC82C7A78C40FF10EC48504 +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdAj0v6Ig9gPRp/atWzcpVn49mZM+Ib69D5OdSb +mKioluUAAQC2SsksYpt3WXC0YeMU0TpttyCI9tMfohEHlWkTARWF2g4+zQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBN4no8w+RIgv/8gsenjED/EOxIUE +AAoJEHjED/EOxIUEXLABAPAjwGuidUaTUDHr1JqYyDYz53EXBMzbmBKzGAAkEZhR +APwPkQ2eh0ylcmi1a7ApTRvJy1PCVVJxWBtPYR3cswR5BA== +=ztvn +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: D4C2D59F95930932 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: D4C2D59F95930932 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: D4C2D59F95930932 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: D4C2D59F95930932 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: D4C2D59F95930932 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: D4C2D59F95930932 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: D4C2D59F95930932 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 8O=bRa"5A^m3 +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: D4C2D59F95930932 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: D4C2D59F95930932 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +No archived entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: D4C2D59F95930932 > Main Menu > 2FA Codes +No archived entries found. +Press Enter to return to the menu. +cSeed Profile: D4C2D59F95930932 > Main Menu > 2FA Codes +No archived entries found. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 447326 [###########---------] 13s + +cSeed Profile: D4C2D59F95930932 > Main Menu +No archived entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: D4C2D59F95930932 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: D4C2D59F95930932 > Main Menu > Retrieve Entry + +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example +[+] Password for 'agent.example' copied to clipboard. Will clear in 45 seconds. +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Entry Actions + + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: D4C2D59F95930932 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 8 + password: 1 + totp: 1 + ssh: 1 + seed: 1 + pgp: 1 + nostr: 1 + key_value: 1 + managed_account: 1 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: D4C2D59F95930932 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. diff --git a/artifacts/agent_tui_test/20260223T195911Z/transcript.raw.txt b/artifacts/agent_tui_test/20260223T195911Z/transcript.raw.txt new file mode 100644 index 00000000..9d3685e6 --- /dev/null +++ b/artifacts/agent_tui_test/20260223T195911Z/transcript.raw.txt @@ -0,0 +1,1114 @@ +Startup Options: +1. Continue +2. Restore from backup +Select an option: 1 +Initialized checksum for '/home/user/Documents/GitHub/SeedPass/src/seedpass/core/manager.py'. +Choose an option: +1. Paste in an existing seed in full +2. Enter an existing seed one word at a time +3. Generate a new seed +4. Restore from Nostr +5. Restore from local backup +Enter choice (1/2/3/4/5): 3 +Your new BIP-85 seed phrase is: +series salad chase belt furnace token junk agent trade glove tomato empty +Please write this down and keep it in a safe place! +Do you want to use this generated seed? (Y/N): Y +Enter a new password: ************* +Confirm your password: ************* +c +=== Seed Profile Stats === +Total entries: 0 + password: 0 + totp: 0 + ssh: 0 + seed: 0 + pgp: 0 + nostr: 0 + key_value: 0 + managed_account: 0 +Relays configured: 3 +Backups: 0 (dir: /tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to continue. + +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 99 +Invalid choice. Please select a valid option. +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 9 +Invalid choice. +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: D4C2D59F95930932 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: abc +Error: Index must be a number. +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: D4C2D59F95930932 > Main Menu > Add Entry > Password +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Choose mode: [Q]uick or [A]dvanced? q +Enter the label or website name: agent.example +Enter the username (optional): agent +Enter the URL (optional): https://agent.example +Enter desired password length (default 16): 3 +Error: Password length must be between 8 and 128. +Enter desired password length (default 16): 12 +Include special characters? (Y/n): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876753.json.enc'. +[+] Entry added successfully at index 0. + +[+] Password generated and indexed with ID 0. + +Password for agent.example: 8O=bRa"5A^m3 + +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: D4C2D59F95930932 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 8O=bRa"5A^m3 +Associated Username: agent +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 3 +cSeed Profile: D4C2D59F95930932 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter search string: agent +cSeed Profile: D4C2D59F95930932 > Main Menu > Search Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Search Results: + +0. Password - agent.example (agent) +Enter index to view details or press Enter to go back: +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: D4C2D59F95930932 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: D4C2D59F95930932 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +Enter index to view details or press Enter to go back: +cSeed Profile: D4C2D59F95930932 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 2 +cSeed Profile: D4C2D59F95930932 > Main Menu > Add Entry > 2FA (TOTP) +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +Add TOTP: +1. Make 2FA +2. Import 2FA (paste otpauth URI or secret) +Select option or press Enter to go back: 1 +Label: agent-totp +Period (default 30): +Digits (default 6): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. + +[+] TOTP entry added with ID 1. + +Add this URI to your authenticator app: +otpauth://totp/agent-totp?secret=JD4OTOJ36N62O3PSC2MBBRMK4R6ATGQH&period=30&digits=6 +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆβ–€β–€β–€β–ˆβ–€β–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–€β–€β–ˆβ–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–ˆΒ Β β–ˆβ–ˆΒ Β Β β–„β–€Β β–€Β β–€β–€Β β–ˆβ–„Β Β Β β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆΒ β–€β–€Β β–€β–ˆβ–„β–„β–ˆΒ β–€β–„β–€β–€Β β–€β–„Β Β β–€Β β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆΒ β–„β–€β–„β–€β–ˆβ–€β–„β–€β–„Β β–„β–€β–ˆβ–€β–ˆΒ β–ˆΒ β–ˆΒ β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆ +β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–€β–€Β β–„β–€β–„β–„β–ˆβ–„β–ˆΒ β–„Β β–ˆβ–„β–„β–„β–„β–„β–ˆΒ β–€β–ˆβ–€β–€β–€β–€β–€β–ˆβ–ˆβ–€β–ˆ +β–ˆΒ Β Β β–ˆβ–€β–„β–€β–„β–„Β Β Β Β β–ˆβ–„β–€β–ˆβ–ˆβ–„Β Β β–„β–„β–ˆβ–„Β β–€β–€β–€β–ˆΒ Β β–„Β β–€β–„β–ˆβ–ˆ +β–ˆβ–€β–ˆβ–„β–ˆβ–€β–€β–€β–€Β β–€β–„β–€β–ˆβ–„β–€β–„Β Β β–„β–ˆβ–ˆΒ β–€β–€β–„β–ˆβ–„β–€β–„β–ˆΒ β–€β–„β–„β–„Β β–€β–ˆ +β–ˆβ–ˆΒ β–„β–„β–€β–„β–€β–€Β Β β–€β–€β–„Β β–€β–€Β β–€β–„β–ˆβ–„β–ˆΒ Β β–€β–ˆβ–„Β β–€β–ˆβ–€β–„Β β–€β–€β–ˆβ–€β–ˆ +β–ˆβ–„β–ˆβ–€β–ˆΒ β–„β–€Β β–ˆβ–ˆβ–„Β β–ˆβ–„β–ˆβ–ˆβ–„β–„β–€β–€β–„Β β–ˆβ–€β–„β–ˆβ–€β–„Β Β β–ˆβ–ˆβ–„β–ˆΒ Β β–„β–ˆ +β–ˆβ–€Β β–„β–€β–ˆβ–„β–€β–€Β Β β–„β–€β–ˆβ–€β–€β–ˆΒ β–€Β β–ˆβ–„β–ˆΒ β–€β–„β–„β–€β–€β–ˆβ–„β–€β–€β–ˆβ–€β–„β–„β–ˆβ–ˆ +β–ˆβ–€β–€β–€β–„β–€β–ˆβ–€β–€β–€β–ˆβ–€Β β–ˆβ–€β–ˆβ–€β–€β–„β–€β–„β–ˆΒ β–€β–ˆβ–€β–ˆβ–„β–„β–€β–€Β β–ˆβ–„Β β–„β–€β–„β–ˆ +β–ˆβ–ˆβ–„Β β–„β–ˆΒ β–€β–€β–ˆβ–„β–€β–„β–ˆβ–ˆβ–„β–€β–ˆβ–„β–€β–ˆβ–€β–ˆβ–€Β β–ˆΒ β–„Β Β Β β–ˆβ–„β–„β–ˆβ–€β–€β–„β–ˆ +β–ˆβ–ˆβ–€β–€Β β–ˆβ–€β–€Β β–€β–„Β β–ˆΒ β–„β–„Β β–€β–ˆβ–ˆβ–€β–„Β β–„β–„β–„β–„β–€β–„β–ˆβ–„Β β–€β–„β–€Β β–ˆβ–€β–ˆ +β–ˆβ–„β–„β–„β–€β–„β–ˆβ–€Β β–ˆβ–ˆβ–€β–ˆβ–€β–„β–ˆβ–€β–ˆΒ β–„β–€β–„β–€β–„β–„Β β–€β–€Β Β β–„β–ˆβ–„β–„Β β–„β–ˆβ–ˆβ–ˆ +β–ˆβ–€β–€β–€β–„β–„β–€β–€β–„β–ˆβ–€β–„Β β–„Β Β β–„β–„β–ˆΒ β–€Β Β β–€β–ˆβ–„β–ˆβ–ˆβ–€Β Β β–€β–€Β β–€Β β–ˆβ–€β–ˆ +β–ˆβ–€β–€β–€β–€β–€β–€β–€β–ˆΒ Β β–ˆβ–€Β β–ˆβ–€β–„β–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆΒ β–€β–ˆβ–ˆβ–„Β β–ˆβ–€β–ˆΒ β–„β–€β–€β–ˆβ–ˆ +β–ˆΒ β–ˆβ–€β–€β–€β–ˆΒ β–ˆβ–€β–€Β β–„β–„β–€β–ˆβ–„β–ˆβ–„Β Β β–ˆβ–€β–„Β β–„β–ˆΒ β–ˆΒ β–€β–€β–€Β β–€Β β–„Β β–ˆ +β–ˆΒ β–ˆΒ Β Β β–ˆΒ β–ˆβ–ˆΒ Β Β β–„β–„β–„β–ˆΒ β–€β–€β–€Β β–ˆΒ β–„β–„β–„β–€β–„β–„Β Β Β β–ˆβ–„Β β–€β–ˆβ–ˆ +β–ˆΒ β–€β–€β–€β–€β–€Β β–ˆβ–€β–„Β Β Β β–„β–„β–€β–ˆβ–ˆβ–ˆΒ β–ˆΒ β–€β–„Β β–ˆβ–€Β β–„Β β–€β–ˆβ–€β–„Β Β β–€β–ˆ +β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ +Secret: JD4OTOJ36N62O3PSC2MBBRMK4R6ATGQH + +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: D4C2D59F95930932 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. +cSeed Profile: D4C2D59F95930932 > Main Menu > 2FA Codes +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 447326 [#########-----------] 16s + +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 3 +cSeed Profile: D4C2D59F95930932 > Main Menu > Add Entry > SSH Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label (key): agent-ssh +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. +WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): y + +[+] SSH key entry added with ID 2. + +Public Key: +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEA7WEA5n75ov8dpPh82MxKfX5klZqb44dswnmTWNp+Ljg= +-----END PUBLIC KEY----- + +Private Key: +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIGFrH1lkgsQRXsZd90u6orwen1smBoZWqXlW+lgBiQBm +-----END PRIVATE KEY----- + +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 4 +cSeed Profile: D4C2D59F95930932 > Main Menu > Add Entry > Seed Phrase +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-seed +Word count (12 or 24, default 24): 12 +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. +WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): y + +[+] Seed entry 'agent-seed' added with ID 3. + +Index: 3 +Label: agent-seed +Seed Phrase: +bone garment crouch enrich outdoor vault casual toe pupil safe alley struggle +Show Compact Seed QR? (Y/N): n +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 5 +cSeed Profile: D4C2D59F95930932 > Main Menu > Add Entry > Nostr Key Pair +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-nostr +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. + +[+] Nostr key entry added with ID 4. + +npub: npub1phl2pv9cjgz497hh90dht8l3ygsulmcttjw4tveku7yjhksddvnqkv7wkv +nsec: nsec1f3ula2u5t73qftwy60hrdgtg5kyk6etqugd3m567hs8m8crr407qgyk9yf +Show QR code for npub? (Y/N): n +WARNING: Displaying the nsec QR reveals your private key. Continue? (Y/N): n +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 6 +cSeed Profile: D4C2D59F95930932 > Main Menu > Add Entry > PGP Key +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-pgp +Key type (ed25519 or rsa, default ed25519): +User ID (optional): +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. +WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): y + +[+] PGP key entry added with ID 5. + +Fingerprint: DE27A3CC3E44882FFFC82C7A78C40FF10EC48504 +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xVgEOG1DgBYJKwYBBAHaRw8BAQdAj0v6Ig9gPRp/atWzcpVn49mZM+Ib69D5OdSb +mKioluUAAQC2SsksYpt3WXC0YeMU0TpttyCI9tMfohEHlWkTARWF2g4+zQDChAQT +FggALAUCOG1DgAIbDgILCQIVCAIWAgIeARYhBN4no8w+RIgv/8gsenjED/EOxIUE +AAoJEHjED/EOxIUEXLABAPAjwGuidUaTUDHr1JqYyDYz53EXBMzbmBKzGAAkEZhR +APwPkQ2eh0ylcmi1a7ApTRvJy1PCVVJxWBtPYR3cswR5BA== +=ztvn +-----END PGP PRIVATE KEY BLOCK----- + +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 7 +cSeed Profile: D4C2D59F95930932 > Main Menu > Add Entry > Key/Value +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-kv +Key: token +Value: abc123 +Notes (optional): +Enter tags (comma-separated, optional): +Add custom field? (y/N): n +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. + +[+] Key/Value entry added with ID 6. + +Value: abc123 +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 1 +cSeed Profile: Main Menu > Add Entry + + +Add Entry: +1. Password +2. 2FA (TOTP) +3. SSH Key +4. Seed Phrase +5. Nostr Key Pair +6. PGP Key +7. Key/Value +8. Managed Account +Select entry type or press Enter to go back: 8 +cSeed Profile: D4C2D59F95930932 > Main Menu > Add Entry > Managed Account +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Label: agent-managed +Notes (optional): +Enter tags (comma-separated, optional): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. + +[+] Managed account 'agent-managed' added with ID 7. + +Reveal seed now? (y/N): n +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 4 +cSeed Profile: D4C2D59F95930932 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: 1 +cSeed Profile: D4C2D59F95930932 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entries: + +0. Password - agent.example +1. Totp - agent-totp +2. Ssh - agent-ssh +3. Seed - agent-seed +4. Nostr - agent-nostr +5. Pgp - agent-pgp +6. Key_value - agent-kv +7. Managed_account - agent-managed +Enter index to view details or press Enter to go back: +cSeed Profile: D4C2D59F95930932 > Main Menu > List Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +List Entries: +1. All +2. Password +3. Totp +4. Ssh +5. Seed +6. Pgp +7. Nostr +8. Key Value +9. Managed Account +Select entry type or press Enter to go back: +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 5 +cSeed Profile: D4C2D59F95930932 > Main Menu > Modify Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to modify: 0 +Modifying entry for 'agent.example' (Index: 0): +Current Label: agent.example +Current Username: agent +Current URL: https://agent.example +Current Archived Status: Active +Enter new label (leave blank to keep "agent.example"): +Enter new username (leave blank to keep "agent"): agent2 +Enter new URL (leave blank to keep "https://agent.example"): +Archive this password? (Y/N, current: N): n +Enter new notes (leave blank to keep "N/A"): +Edit custom fields? (y/N): n +Enter tags (comma-separated, leave blank to keep current): +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. +[+] Entry at index 0 modified successfully. +Entry updated successfully for index 0. +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: D4C2D59F95930932 > Main Menu > Retrieve Entry +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example + +[+] Retrieved Password for agent.example: + +Password: 8O=bRa"5A^m3 +Associated Username: agent2 +Associated URL: https://agent.example +Archived Status: Active +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: A +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. +[+] Entry at index 0 modified successfully. +cSeed Profile: D4C2D59F95930932 > Entry Actions +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Entry Actions: +U. Unarchive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +cSeed Profile: D4C2D59F95930932 > Main Menu > Archived Entries +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + +[+] Archived Entries: + +0. agent.example +Enter index to manage or press Enter to go back: 0 +Enter 'v' to view details, 'r' to restore, or press Enter to go back: r +[+] Checksum updated successfully. +Backup created successfully at '/tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups/entries_db_backup_1771876754.json.enc'. +[+] Entry at index 0 modified successfully. +Press Enter to continue... +All entries restored. +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +Only 0 relay(s) responded with your latest event. Consider adding more relays via Settings. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 8 +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Main Menu +No archived entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 6 +cSeed Profile: D4C2D59F95930932 > Main Menu > 2FA Codes +No archived entries found. +Press Enter to return to the menu. +cSeed Profile: D4C2D59F95930932 > Main Menu > 2FA Codes +No archived entries found. +Press Enter to return to the menu. + +Imported 2FA Codes: +[1] agent-totp: 447326 [###########---------] 13s + +cSeed Profile: D4C2D59F95930932 > Main Menu +No archived entries found. + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 15 +Secret mode is currently OFF +Enable secret mode? (y/n, blank to keep): y +Clipboard clear delay in seconds [45]: +Secret mode enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 16 +Offline mode is currently ON +Enable offline mode? (y/n, blank to keep): n +Offline mode disabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 17 +Quick Unlock is currently OFF +Enable Quick Unlock? (y/n, blank to keep): y +Quick Unlock enabled. +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 13 +Vault locked. Please re-enter your password. +Enter your master password: ************* +Deriving key... +Decrypting seed... +Connecting to relays... +Press Enter to continue... +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: D4C2D59F95930932 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 2 +cSeed Profile: D4C2D59F95930932 > Main Menu > Retrieve Entry + +Enter the index number of the entry to retrieve: 0 +Retrieving password for 'agent.example' with length 12. +Username: agent2 +URL: https://agent.example +[+] Password for 'agent.example' copied to clipboard. Will clear in 45 seconds. +Press Enter to continue... +cSeed Profile: D4C2D59F95930932 > Entry Actions + + +[+] Entry Actions: +A. Archive +N. Add Note +C. Add Custom Field +H. Add Hidden Field +E. Edit +T. Edit Tags +Select an action or press Enter to return: +cSeed Profile: D4C2D59F95930932 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: 7 +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: 14 +c +=== Seed Profile Stats === +Total entries: 8 + password: 1 + totp: 1 + ssh: 1 + seed: 1 + pgp: 1 + nostr: 1 + key_value: 1 + managed_account: 1 +Relays configured: 3 +Backups: 2 (dir: /tmp/seedpass-agent-home-f1a0vwbh/.seedpass/D4C2D59F95930932/backups) +Schema version: 4 +Database checksum ok: no +Script checksum ok: yes +Snapshot chunks: 0 +Pending deltas: 0 +Press Enter to continue. + +cSeed Profile: Main Menu > Settings + + +Settings: +1. Profiles +2. Nostr +3. Change password +4. Verify Script Checksum +5. Generate Script Checksum +6. Backup Parent Seed +7. Export database +8. Import database +9. Export 2FA codes +10. Set additional backup location +11. KDF strength & benchmark +12. Set inactivity timeout +13. Lock Vault +14. Stats +15. Toggle Secret Mode +16. Toggle Offline Mode (default ON) +17. Toggle Quick Unlock +Select an option or press Enter to go back: +cSeed Profile: D4C2D59F95930932 > Main Menu + + + Select an option: + 1. Add Entry + 2. Retrieve Entry + 3. Search Entries + 4. List Entries + 5. Modify an Existing Entry + 6. 2FA Codes + 7. Settings + 8. List Archived + +Enter your choice (1-8) or press Enter to exit: +Exiting the program. + \ No newline at end of file diff --git a/artifacts/coverage/coverage.full.after_workers.json b/artifacts/coverage/coverage.full.after_workers.json new file mode 100644 index 00000000..587a865a --- /dev/null +++ b/artifacts/coverage/coverage.full.after_workers.json @@ -0,0 +1 @@ +{"meta": {"format": 3, "version": "7.10.1", "timestamp": "2026-02-23T15:22:22.584028", "branch_coverage": false, "show_contexts": false}, "files": {"src/constants.py": {"executed_lines": [3, 4, 7, 15, 16, 17, 22, 23, 28, 33, 35, 36, 37, 45, 46, 47, 50, 53, 56, 62], "summary": {"covered_lines": 20, "num_statements": 22, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [38, 39], "excluded_lines": [], "functions": {"initialize_app": {"executed_lines": [35, 36, 37], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [38, 39], "excluded_lines": []}, "": {"executed_lines": [3, 4, 7, 15, 16, 17, 22, 23, 28, 33, 45, 46, 47, 50, 53, 56, 62], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 4, 7, 15, 16, 17, 22, 23, 28, 33, 35, 36, 37, 45, 46, 47, 50, 53, 56, 62], "summary": {"covered_lines": 20, "num_statements": 22, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [38, 39], "excluded_lines": []}}}, "src/local_bip85/__init__.py": {"executed_lines": [3, 5, 7, 8, 15], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [9, 10, 11], "excluded_lines": [], "functions": {"": {"executed_lines": [3, 5, 7, 8, 15], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [9, 10, 11], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 5, 7, 8, 15], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [9, 10, 11], "excluded_lines": []}}}, "src/local_bip85/bip85.py": {"executed_lines": [3, 16, 17, 18, 19, 20, 21, 23, 25, 27, 28, 29, 32, 35, 36, 38, 41, 42, 50, 51, 52, 54, 55, 61, 86, 87, 88, 89, 90, 91, 94, 96, 97, 98, 99, 101, 102, 103, 105, 107, 118, 119, 120, 121, 122, 123, 125, 126, 127, 128, 129, 130, 132, 138, 139, 142, 143, 149, 151, 152, 153, 154], "summary": {"covered_lines": 60, "num_statements": 75, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [56, 57, 58, 59, 108, 111, 114, 144, 145, 146, 147, 155, 156, 157, 158], "excluded_lines": [], "functions": {"BIP85.__init__": {"executed_lines": [50, 51, 52, 54, 55], "summary": {"covered_lines": 5, "num_statements": 9, "percent_covered": 55.55555555555556, "percent_covered_display": "56", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [56, 57, 58, 59], "excluded_lines": []}, "BIP85.derive_entropy": {"executed_lines": [86, 87, 88, 89, 90, 91, 94, 96, 97, 98, 99, 101, 102, 103, 105, 107, 118, 119, 120, 121, 122, 123], "summary": {"covered_lines": 22, "num_statements": 25, "percent_covered": 88.0, "percent_covered_display": "88", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [108, 111, 114], "excluded_lines": []}, "BIP85.derive_mnemonic": {"executed_lines": [126, 127, 128, 129, 130, 132, 138, 139, 142, 143], "summary": {"covered_lines": 10, "num_statements": 14, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [144, 145, 146, 147], "excluded_lines": []}, "BIP85.derive_symmetric_key": {"executed_lines": [151, 152, 153, 154], "summary": {"covered_lines": 4, "num_statements": 8, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [155, 156, 157, 158], "excluded_lines": []}, "": {"executed_lines": [3, 16, 17, 18, 19, 20, 21, 23, 25, 27, 28, 29, 32, 35, 36, 38, 41, 42, 61, 125, 149], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"Bip85Error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BIP85": {"executed_lines": [50, 51, 52, 54, 55, 86, 87, 88, 89, 90, 91, 94, 96, 97, 98, 99, 101, 102, 103, 105, 107, 118, 119, 120, 121, 122, 123, 126, 127, 128, 129, 130, 132, 138, 139, 142, 143, 151, 152, 153, 154], "summary": {"covered_lines": 41, "num_statements": 56, "percent_covered": 73.21428571428571, "percent_covered_display": "73", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [56, 57, 58, 59, 108, 111, 114, 144, 145, 146, 147, 155, 156, 157, 158], "excluded_lines": []}, "": {"executed_lines": [3, 16, 17, 18, 19, 20, 21, 23, 25, 27, 28, 29, 32, 35, 36, 38, 41, 42, 61, 125, 149], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/main.py": {"executed_lines": [2, 3, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 33, 40, 41, 42, 47, 49, 51, 58, 60, 61, 62, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 84, 87, 88, 90, 91, 92, 93, 95, 96, 98, 101, 102, 104, 105, 106, 107, 108, 110, 112, 113, 116, 117, 134, 149, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 162, 165, 166, 172, 173, 174, 183, 184, 185, 186, 188, 189, 193, 194, 195, 200, 210, 223, 225, 226, 227, 231, 232, 233, 234, 236, 237, 241, 242, 245, 247, 248, 249, 250, 251, 252, 254, 271, 276, 282, 283, 284, 288, 289, 290, 291, 292, 298, 316, 324, 325, 326, 327, 328, 330, 331, 332, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 363, 372, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 389, 391, 393, 395, 398, 399, 400, 401, 402, 404, 405, 408, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 426, 427, 432, 435, 437, 438, 439, 449, 450, 457, 458, 459, 465, 470, 473, 490, 492, 493, 494, 495, 496, 501, 514, 516, 517, 520, 521, 524, 525, 526, 527, 530, 531, 532, 533, 534, 535, 542, 545, 547, 548, 551, 552, 553, 554, 557, 558, 559, 560, 563, 571, 572, 573, 574, 579, 582, 584, 585, 588, 590, 591, 592, 593, 598, 601, 635, 637, 638, 640, 641, 644, 651, 652, 657, 658, 659, 660, 661, 662, 663, 666, 672, 673, 676, 677, 678, 684, 733, 752, 754, 755, 756, 757, 758, 759, 760, 768, 769, 770, 775, 776, 777, 778, 781, 782, 783, 784, 785, 791, 792, 793, 794, 795, 796, 797, 803, 805, 806, 807, 808, 809, 810, 811, 819, 820, 825, 826, 827, 828, 831, 832, 833, 834, 840, 842, 843, 844, 845, 846, 847, 848, 856, 857, 862, 863, 864, 865, 868, 869, 870, 871, 872, 878, 917, 971, 973, 974, 979, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1006, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1019, 1020, 1023, 1026, 1029, 1032, 1037, 1040, 1041, 1042, 1043, 1046, 1049, 1056, 1058, 1061, 1064, 1067, 1068, 1073, 1081, 1092, 1093, 1094, 1095, 1096, 1097, 1102, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1117, 1118, 1119, 1123, 1124, 1126, 1129, 1130, 1131, 1132, 1133, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1165, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1183, 1184, 1187, 1190, 1193, 1196, 1199, 1202, 1205, 1208, 1209, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1234, 1237, 1247, 1248, 1249, 1250, 1251, 1253, 1254, 1255, 1256, 1260, 1265, 1270, 1276, 1278, 1279, 1280, 1286, 1287, 1289, 1290, 1292, 1293, 1295, 1296, 1298, 1300, 1301, 1302, 1310, 1311, 1312, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1327, 1328, 1329, 1335, 1338, 1339, 1340, 1350, 1352, 1355, 1356, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1368, 1369, 1370, 1371, 1372, 1373, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1403, 1404, 1405, 1406, 1407, 1416, 1418, 1430, 1431, 1433, 1434, 1470, 1473], "summary": {"covered_lines": 578, "num_statements": 1067, "percent_covered": 54.170571696344894, "percent_covered_display": "54", "missing_lines": 489, "excluded_lines": 5}, "missing_lines": [8, 63, 64, 124, 125, 126, 127, 128, 129, 131, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 161, 175, 181, 190, 191, 201, 202, 204, 205, 206, 207, 216, 217, 218, 219, 220, 228, 229, 238, 239, 257, 260, 261, 268, 270, 272, 273, 285, 286, 293, 294, 295, 302, 303, 304, 305, 306, 308, 309, 310, 311, 312, 313, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 365, 366, 388, 390, 392, 394, 396, 403, 428, 429, 430, 440, 446, 447, 453, 454, 455, 456, 466, 467, 468, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 497, 498, 503, 504, 505, 506, 507, 508, 509, 510, 511, 518, 519, 522, 523, 528, 529, 536, 537, 538, 539, 540, 549, 550, 555, 556, 561, 562, 564, 570, 575, 576, 577, 586, 587, 594, 595, 596, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 642, 643, 653, 654, 655, 656, 664, 665, 667, 668, 669, 670, 671, 674, 675, 679, 680, 681, 686, 687, 688, 689, 690, 691, 692, 693, 695, 696, 697, 698, 699, 701, 704, 705, 706, 707, 708, 709, 710, 711, 713, 714, 715, 716, 717, 718, 719, 720, 721, 723, 724, 725, 726, 727, 728, 729, 730, 735, 736, 737, 738, 739, 740, 741, 743, 744, 745, 746, 747, 749, 761, 762, 763, 764, 766, 767, 771, 772, 773, 774, 779, 780, 786, 787, 788, 789, 790, 798, 799, 800, 812, 813, 814, 815, 817, 818, 821, 822, 823, 824, 829, 830, 835, 836, 837, 849, 850, 851, 852, 854, 855, 858, 859, 860, 861, 866, 867, 873, 874, 875, 880, 881, 886, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 914, 919, 920, 921, 922, 923, 924, 925, 926, 927, 929, 930, 935, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 968, 1005, 1007, 1015, 1016, 1017, 1018, 1021, 1022, 1024, 1025, 1027, 1028, 1030, 1031, 1033, 1034, 1035, 1036, 1038, 1039, 1044, 1045, 1047, 1048, 1050, 1051, 1052, 1053, 1054, 1055, 1057, 1059, 1060, 1062, 1063, 1065, 1066, 1070, 1147, 1148, 1185, 1186, 1188, 1189, 1191, 1192, 1194, 1195, 1197, 1198, 1200, 1201, 1203, 1204, 1206, 1207, 1303, 1309, 1313, 1314, 1315, 1316, 1326, 1330, 1331, 1332, 1333, 1336, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1351, 1353, 1374, 1391, 1408, 1409, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1474], "excluded_lines": [333, 334, 367, 368, 369], "functions": {"_warn_missing_optional_dependencies": {"executed_lines": [60, 61, 62], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [63, 64], "excluded_lines": []}, "load_global_config": {"executed_lines": [73, 74, 75, 76, 77, 78, 79, 80, 81], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "configure_logging": {"executed_lines": [87, 88, 90, 91, 92, 93, 95, 96, 98, 101, 102, 104, 105, 106, 107, 108, 110, 112, 113], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "confirm_action": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [124, 125, 126, 127, 128, 129, 131], "excluded_lines": []}, "drain_notifications": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146], "excluded_lines": []}, "get_notification_text": {"executed_lines": [151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 162], "summary": {"covered_lines": 11, "num_statements": 12, "percent_covered": 91.66666666666667, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [161], "excluded_lines": []}, "handle_switch_fingerprint": {"executed_lines": [172, 173, 174, 183, 184, 185, 186, 188, 189, 193, 194, 195, 200], "summary": {"covered_lines": 13, "num_statements": 23, "percent_covered": 56.52173913043478, "percent_covered_display": "57", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [175, 181, 190, 191, 201, 202, 204, 205, 206, 207], "excluded_lines": []}, "handle_add_new_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [216, 217, 218, 219, 220], "excluded_lines": []}, "handle_remove_fingerprint": {"executed_lines": [225, 226, 227, 231, 232, 233, 234, 236, 237, 241, 242, 245, 247, 254, 271], "summary": {"covered_lines": 15, "num_statements": 26, "percent_covered": 57.69230769230769, "percent_covered_display": "58", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [228, 229, 238, 239, 257, 260, 261, 268, 270, 272, 273], "excluded_lines": []}, "handle_remove_fingerprint._cleanup_and_exit": {"executed_lines": [248, 249, 250, 251, 252], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "handle_list_fingerprints": {"executed_lines": [282, 283, 284, 288, 289, 290, 291, 292], "summary": {"covered_lines": 8, "num_statements": 13, "percent_covered": 61.53846153846154, "percent_covered_display": "62", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [285, 286, 293, 294, 295], "excluded_lines": []}, "handle_display_npub": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [302, 303, 304, 305, 306, 308, 309, 310, 311, 312, 313], "excluded_lines": []}, "_display_live_stats": {"executed_lines": [324, 325, 326, 327, 328, 330, 331, 332, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346], "summary": {"covered_lines": 19, "num_statements": 32, "percent_covered": 59.375, "percent_covered_display": "59", "missing_lines": 13, "excluded_lines": 2}, "missing_lines": [348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360], "excluded_lines": [333, 334]}, "handle_display_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 3}, "missing_lines": [365, 366], "excluded_lines": [367, 368, 369]}, "print_matches": {"executed_lines": [377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 389, 391, 393, 395, 398, 399, 400, 401, 402, 404, 405], "summary": {"covered_lines": 22, "num_statements": 28, "percent_covered": 78.57142857142857, "percent_covered_display": "79", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [388, 390, 392, 394, 396, 403], "excluded_lines": []}, "handle_post_to_nostr": {"executed_lines": [414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 426, 427, 432], "summary": {"covered_lines": 14, "num_statements": 17, "percent_covered": 82.3529411764706, "percent_covered_display": "82", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [428, 429, 430], "excluded_lines": []}, "handle_retrieve_from_nostr": {"executed_lines": [437, 438, 439, 449, 450, 457, 458, 459, 465, 470], "summary": {"covered_lines": 10, "num_statements": 20, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [440, 446, 447, 453, 454, 455, 456, 466, 467, 468], "excluded_lines": []}, "handle_view_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487], "excluded_lines": []}, "_safe_close_client_pool": {"executed_lines": [492, 493, 494, 495, 496], "summary": {"covered_lines": 5, "num_statements": 7, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [497, 498], "excluded_lines": []}, "_reload_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [503, 504, 505, 506, 507, 508, 509, 510, 511], "excluded_lines": []}, "handle_add_relay": {"executed_lines": [516, 517, 520, 521, 524, 525, 526, 527, 530, 531, 532, 533, 534, 535, 542], "summary": {"covered_lines": 15, "num_statements": 26, "percent_covered": 57.69230769230769, "percent_covered_display": "58", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [518, 519, 522, 523, 528, 529, 536, 537, 538, 539, 540], "excluded_lines": []}, "handle_remove_relay": {"executed_lines": [547, 548, 551, 552, 553, 554, 557, 558, 559, 560, 563, 571, 572, 573, 574, 579], "summary": {"covered_lines": 16, "num_statements": 27, "percent_covered": 59.25925925925926, "percent_covered_display": "59", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [549, 550, 555, 556, 561, 562, 564, 570, 575, 576, 577], "excluded_lines": []}, "handle_reset_relays": {"executed_lines": [584, 585, 588, 590, 591, 592, 593, 598], "summary": {"covered_lines": 8, "num_statements": 13, "percent_covered": 61.53846153846154, "percent_covered_display": "62", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [586, 587, 594, 595, 596], "excluded_lines": []}, "handle_set_inactivity_timeout": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 30, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 30, "excluded_lines": 0}, "missing_lines": [603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632], "excluded_lines": []}, "handle_set_kdf_iterations": {"executed_lines": [637, 638, 640, 641, 644, 651, 652, 657, 658, 659, 660, 661, 662, 663, 666, 672, 673, 676, 677, 678], "summary": {"covered_lines": 20, "num_statements": 38, "percent_covered": 52.63157894736842, "percent_covered_display": "53", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [642, 643, 653, 654, 655, 656, 664, 665, 667, 668, 669, 670, 671, 674, 675, 679, 680, 681], "excluded_lines": []}, "handle_set_additional_backup_location": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 39, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 39, "excluded_lines": 0}, "missing_lines": [686, 687, 688, 689, 690, 691, 692, 693, 695, 696, 697, 698, 699, 701, 704, 705, 706, 707, 708, 709, 710, 711, 713, 714, 715, 716, 717, 718, 719, 720, 721, 723, 724, 725, 726, 727, 728, 729, 730], "excluded_lines": []}, "handle_set_profile_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [735, 736, 737, 738, 739, 740, 741, 743, 744, 745, 746, 747, 749], "excluded_lines": []}, "handle_toggle_secret_mode": {"executed_lines": [754, 755, 756, 757, 758, 759, 760, 768, 769, 770, 775, 776, 777, 778, 781, 782, 783, 784, 785, 791, 792, 793, 794, 795, 796, 797], "summary": {"covered_lines": 26, "num_statements": 46, "percent_covered": 56.52173913043478, "percent_covered_display": "57", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [761, 762, 763, 764, 766, 767, 771, 772, 773, 774, 779, 780, 786, 787, 788, 789, 790, 798, 799, 800], "excluded_lines": []}, "handle_toggle_quick_unlock": {"executed_lines": [805, 806, 807, 808, 809, 810, 811, 819, 820, 825, 826, 827, 828, 831, 832, 833, 834], "summary": {"covered_lines": 17, "num_statements": 32, "percent_covered": 53.125, "percent_covered_display": "53", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [812, 813, 814, 815, 817, 818, 821, 822, 823, 824, 829, 830, 835, 836, 837], "excluded_lines": []}, "handle_toggle_offline_mode": {"executed_lines": [842, 843, 844, 845, 846, 847, 848, 856, 857, 862, 863, 864, 865, 868, 869, 870, 871, 872], "summary": {"covered_lines": 18, "num_statements": 33, "percent_covered": 54.54545454545455, "percent_covered_display": "55", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [849, 850, 851, 852, 854, 855, 858, 859, 860, 861, 866, 867, 873, 874, 875], "excluded_lines": []}, "handle_profiles_menu": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [880, 881, 886, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 914], "excluded_lines": []}, "handle_nostr_menu": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 39, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 39, "excluded_lines": 0}, "missing_lines": [919, 920, 921, 922, 923, 924, 925, 926, 927, 929, 930, 935, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 968], "excluded_lines": []}, "handle_settings": {"executed_lines": [973, 974, 979, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1006, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1019, 1020, 1023, 1026, 1029, 1032, 1037, 1040, 1041, 1042, 1043, 1046, 1049, 1056, 1058, 1061, 1064, 1067, 1068], "summary": {"covered_lines": 50, "num_statements": 88, "percent_covered": 56.81818181818182, "percent_covered_display": "57", "missing_lines": 38, "excluded_lines": 0}, "missing_lines": [1005, 1007, 1015, 1016, 1017, 1018, 1021, 1022, 1024, 1025, 1027, 1028, 1030, 1031, 1033, 1034, 1035, 1036, 1038, 1039, 1044, 1045, 1047, 1048, 1050, 1051, 1052, 1053, 1054, 1055, 1057, 1059, 1060, 1062, 1063, 1065, 1066, 1070], "excluded_lines": []}, "display_menu": {"executed_lines": [1081, 1092, 1093, 1094, 1095, 1096, 1097, 1102, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1117, 1118, 1119, 1123, 1124, 1126, 1129, 1130, 1131, 1132, 1133, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1165, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1183, 1184, 1187, 1190, 1193, 1196, 1199, 1202, 1205, 1208, 1209, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1234], "summary": {"covered_lines": 89, "num_statements": 107, "percent_covered": 83.17757009345794, "percent_covered_display": "83", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [1147, 1148, 1185, 1186, 1188, 1189, 1191, 1192, 1194, 1195, 1197, 1198, 1200, 1201, 1203, 1204, 1206, 1207], "excluded_lines": []}, "main": {"executed_lines": [1247, 1248, 1249, 1250, 1251, 1253, 1254, 1255, 1256, 1260, 1265, 1270, 1276, 1278, 1279, 1280, 1286, 1287, 1289, 1290, 1292, 1293, 1295, 1296, 1298, 1300, 1301, 1302, 1310, 1311, 1312, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1327, 1328, 1329, 1335, 1338, 1339, 1340, 1350, 1352, 1355, 1356, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1368, 1369, 1370, 1371, 1372, 1373, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1403, 1404, 1405, 1406, 1407, 1416, 1418, 1430, 1431, 1433, 1434, 1470], "summary": {"covered_lines": 100, "num_statements": 159, "percent_covered": 62.893081761006286, "percent_covered_display": "63", "missing_lines": 59, "excluded_lines": 0}, "missing_lines": [1303, 1309, 1313, 1314, 1315, 1316, 1326, 1330, 1331, 1332, 1333, 1336, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1351, 1353, 1374, 1391, 1408, 1409, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469], "excluded_lines": []}, "main.signal_handler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428], "excluded_lines": []}, "": {"executed_lines": [2, 3, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 33, 40, 41, 42, 47, 49, 51, 58, 71, 84, 116, 117, 134, 149, 165, 166, 210, 223, 276, 298, 316, 363, 372, 408, 435, 473, 490, 501, 514, 545, 582, 601, 635, 684, 733, 752, 803, 840, 878, 917, 971, 1073, 1237, 1473], "summary": {"covered_lines": 66, "num_statements": 68, "percent_covered": 97.05882352941177, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [8, 1474], "excluded_lines": []}}, "classes": {"": {"executed_lines": [2, 3, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 33, 40, 41, 42, 47, 49, 51, 58, 60, 61, 62, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 84, 87, 88, 90, 91, 92, 93, 95, 96, 98, 101, 102, 104, 105, 106, 107, 108, 110, 112, 113, 116, 117, 134, 149, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 162, 165, 166, 172, 173, 174, 183, 184, 185, 186, 188, 189, 193, 194, 195, 200, 210, 223, 225, 226, 227, 231, 232, 233, 234, 236, 237, 241, 242, 245, 247, 248, 249, 250, 251, 252, 254, 271, 276, 282, 283, 284, 288, 289, 290, 291, 292, 298, 316, 324, 325, 326, 327, 328, 330, 331, 332, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 363, 372, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 389, 391, 393, 395, 398, 399, 400, 401, 402, 404, 405, 408, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 426, 427, 432, 435, 437, 438, 439, 449, 450, 457, 458, 459, 465, 470, 473, 490, 492, 493, 494, 495, 496, 501, 514, 516, 517, 520, 521, 524, 525, 526, 527, 530, 531, 532, 533, 534, 535, 542, 545, 547, 548, 551, 552, 553, 554, 557, 558, 559, 560, 563, 571, 572, 573, 574, 579, 582, 584, 585, 588, 590, 591, 592, 593, 598, 601, 635, 637, 638, 640, 641, 644, 651, 652, 657, 658, 659, 660, 661, 662, 663, 666, 672, 673, 676, 677, 678, 684, 733, 752, 754, 755, 756, 757, 758, 759, 760, 768, 769, 770, 775, 776, 777, 778, 781, 782, 783, 784, 785, 791, 792, 793, 794, 795, 796, 797, 803, 805, 806, 807, 808, 809, 810, 811, 819, 820, 825, 826, 827, 828, 831, 832, 833, 834, 840, 842, 843, 844, 845, 846, 847, 848, 856, 857, 862, 863, 864, 865, 868, 869, 870, 871, 872, 878, 917, 971, 973, 974, 979, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1006, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1019, 1020, 1023, 1026, 1029, 1032, 1037, 1040, 1041, 1042, 1043, 1046, 1049, 1056, 1058, 1061, 1064, 1067, 1068, 1073, 1081, 1092, 1093, 1094, 1095, 1096, 1097, 1102, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1117, 1118, 1119, 1123, 1124, 1126, 1129, 1130, 1131, 1132, 1133, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1165, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1183, 1184, 1187, 1190, 1193, 1196, 1199, 1202, 1205, 1208, 1209, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1234, 1237, 1247, 1248, 1249, 1250, 1251, 1253, 1254, 1255, 1256, 1260, 1265, 1270, 1276, 1278, 1279, 1280, 1286, 1287, 1289, 1290, 1292, 1293, 1295, 1296, 1298, 1300, 1301, 1302, 1310, 1311, 1312, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1327, 1328, 1329, 1335, 1338, 1339, 1340, 1350, 1352, 1355, 1356, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1368, 1369, 1370, 1371, 1372, 1373, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1403, 1404, 1405, 1406, 1407, 1416, 1418, 1430, 1431, 1433, 1434, 1470, 1473], "summary": {"covered_lines": 578, "num_statements": 1067, "percent_covered": 54.170571696344894, "percent_covered_display": "54", "missing_lines": 489, "excluded_lines": 5}, "missing_lines": [8, 63, 64, 124, 125, 126, 127, 128, 129, 131, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 161, 175, 181, 190, 191, 201, 202, 204, 205, 206, 207, 216, 217, 218, 219, 220, 228, 229, 238, 239, 257, 260, 261, 268, 270, 272, 273, 285, 286, 293, 294, 295, 302, 303, 304, 305, 306, 308, 309, 310, 311, 312, 313, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 365, 366, 388, 390, 392, 394, 396, 403, 428, 429, 430, 440, 446, 447, 453, 454, 455, 456, 466, 467, 468, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 497, 498, 503, 504, 505, 506, 507, 508, 509, 510, 511, 518, 519, 522, 523, 528, 529, 536, 537, 538, 539, 540, 549, 550, 555, 556, 561, 562, 564, 570, 575, 576, 577, 586, 587, 594, 595, 596, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 642, 643, 653, 654, 655, 656, 664, 665, 667, 668, 669, 670, 671, 674, 675, 679, 680, 681, 686, 687, 688, 689, 690, 691, 692, 693, 695, 696, 697, 698, 699, 701, 704, 705, 706, 707, 708, 709, 710, 711, 713, 714, 715, 716, 717, 718, 719, 720, 721, 723, 724, 725, 726, 727, 728, 729, 730, 735, 736, 737, 738, 739, 740, 741, 743, 744, 745, 746, 747, 749, 761, 762, 763, 764, 766, 767, 771, 772, 773, 774, 779, 780, 786, 787, 788, 789, 790, 798, 799, 800, 812, 813, 814, 815, 817, 818, 821, 822, 823, 824, 829, 830, 835, 836, 837, 849, 850, 851, 852, 854, 855, 858, 859, 860, 861, 866, 867, 873, 874, 875, 880, 881, 886, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 914, 919, 920, 921, 922, 923, 924, 925, 926, 927, 929, 930, 935, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 968, 1005, 1007, 1015, 1016, 1017, 1018, 1021, 1022, 1024, 1025, 1027, 1028, 1030, 1031, 1033, 1034, 1035, 1036, 1038, 1039, 1044, 1045, 1047, 1048, 1050, 1051, 1052, 1053, 1054, 1055, 1057, 1059, 1060, 1062, 1063, 1065, 1066, 1070, 1147, 1148, 1185, 1186, 1188, 1189, 1191, 1192, 1194, 1195, 1197, 1198, 1200, 1201, 1203, 1204, 1206, 1207, 1303, 1309, 1313, 1314, 1315, 1316, 1326, 1330, 1331, 1332, 1333, 1336, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1351, 1353, 1374, 1391, 1408, 1409, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1474], "excluded_lines": [333, 334, 367, 368, 369]}}}, "src/nostr/__init__.py": {"executed_lines": [3, 5, 6, 8, 16, 18, 29, 30, 31, 32, 33, 34], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"__getattr__": {"executed_lines": [30, 31, 32, 33, 34], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [3, 5, 6, 8, 16, 18, 29], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 5, 6, 8, 16, 18, 29, 30, 31, 32, 33, 34], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/backup_models.py": {"executed_lines": [1, 2, 5, 6, 7, 10, 11, 12, 14, 15, 16, 17, 20, 21, 22, 24, 25, 26, 27, 28], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [1, 2, 5, 6, 7, 10, 11, 12, 14, 15, 16, 17, 20, 21, 22, 24, 25, 26, 27, 28], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"ChunkMeta": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Manifest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 7, 10, 11, 12, 14, 15, 16, 17, 20, 21, 22, 24, 25, 26, 27, 28], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/client.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 22, 24, 25, 27, 34, 35, 36, 38, 42, 43, 45, 46, 49, 50, 52, 63, 64, 65, 66, 67, 69, 70, 73, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 88, 90, 91, 92, 97, 99, 100, 101, 102, 103, 104, 107, 108, 110, 113], "summary": {"covered_lines": 56, "num_statements": 58, "percent_covered": 96.55172413793103, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 2}, "missing_lines": [93, 94], "excluded_lines": [38, 39], "functions": {"NostrClient.__init__": {"executed_lines": [63, 64, 65, 66, 67, 69, 70, 73, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 88, 90, 91, 92, 97, 99, 100, 101, 102, 103, 104, 107, 108, 110], "summary": {"covered_lines": 32, "num_statements": 34, "percent_covered": 94.11764705882354, "percent_covered_display": "94", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [93, 94], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 22, 24, 25, 27, 34, 35, 36, 38, 42, 43, 45, 46, 49, 50, 52, 113], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [38, 39]}}, "classes": {"NostrClient": {"executed_lines": [63, 64, 65, 66, 67, 69, 70, 73, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 88, 90, 91, 92, 97, 99, 100, 101, 102, 103, 104, 107, 108, 110], "summary": {"covered_lines": 32, "num_statements": 34, "percent_covered": 94.11764705882354, "percent_covered_display": "94", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [93, 94], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 22, 24, 25, 27, 34, 35, 36, 38, 42, 43, 45, 46, 49, 50, 52, 113], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [38, 39]}}}, "src/nostr/coincurve_keys.py": {"executed_lines": [1, 3, 4, 7, 8, 10, 11, 12, 14, 15, 20, 21, 26, 28, 29, 31, 32, 34, 35, 36, 37, 39, 40, 42, 43, 45, 46], "summary": {"covered_lines": 26, "num_statements": 33, "percent_covered": 78.78787878787878, "percent_covered_display": "79", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [13, 17, 18, 22, 23, 24, 38], "excluded_lines": [], "functions": {"Keys.__init__": {"executed_lines": [11, 12, 14, 15, 20, 21, 26], "summary": {"covered_lines": 7, "num_statements": 13, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [13, 17, 18, 22, 23, 24], "excluded_lines": []}, "Keys.hex_to_bech32": {"executed_lines": [31, 32], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Keys.bech32_to_hex": {"executed_lines": [36, 37, 39, 40], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [38], "excluded_lines": []}, "Keys.private_key_hex": {"executed_lines": [43], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Keys.public_key_hex": {"executed_lines": [46], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 7, 8, 10, 28, 29, 34, 35, 42, 45], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"Keys": {"executed_lines": [11, 12, 14, 15, 20, 21, 26, 31, 32, 36, 37, 39, 40, 43, 46], "summary": {"covered_lines": 15, "num_statements": 22, "percent_covered": 68.18181818181819, "percent_covered_display": "68", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [13, 17, 18, 22, 23, 24, 38], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 7, 8, 10, 28, 29, 34, 35, 42, 45], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/connection.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 15, 22, 23, 25, 27, 29, 30, 32, 38, 40, 42, 43, 45, 46, 49, 50, 51, 52, 53, 59, 60, 62, 63, 65, 66, 67, 69, 71, 72, 73, 80, 81, 84, 85, 86, 87, 88, 89, 93, 103, 105, 107, 109, 148, 150, 152, 153, 155, 157, 158, 159, 160, 161, 162, 164, 168, 171, 172, 173, 174, 176, 182, 183, 184, 186, 187, 188, 189, 190, 191, 192, 196, 197, 198, 199, 201, 225, 227, 228, 231, 232], "summary": {"covered_lines": 91, "num_statements": 155, "percent_covered": 58.70967741935484, "percent_covered_display": "59", "missing_lines": 64, "excluded_lines": 0}, "missing_lines": [28, 34, 35, 36, 41, 47, 54, 55, 57, 90, 91, 94, 95, 96, 97, 98, 101, 106, 116, 117, 118, 119, 120, 121, 123, 124, 125, 129, 130, 131, 132, 133, 135, 140, 141, 143, 144, 145, 146, 151, 169, 181, 193, 194, 195, 202, 203, 204, 205, 206, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 229, 230], "excluded_lines": [], "functions": {"ConnectionHandler.connect": {"executed_lines": [27, 29, 30], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [28], "excluded_lines": []}, "ConnectionHandler.initialize_client_pool": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [34, 35, 36], "excluded_lines": []}, "ConnectionHandler._connect_async": {"executed_lines": [40, 42, 43], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [41], "excluded_lines": []}, "ConnectionHandler._initialize_client_pool": {"executed_lines": [46, 49, 50, 51, 52, 53, 59, 60, 62, 63, 65, 66, 67], "summary": {"covered_lines": 13, "num_statements": 17, "percent_covered": 76.47058823529412, "percent_covered_display": "76", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [47, 54, 55, 57], "excluded_lines": []}, "ConnectionHandler._ping_relay": {"executed_lines": [71, 72, 73, 80, 81, 84, 85, 86, 87, 88, 89], "summary": {"covered_lines": 11, "num_statements": 13, "percent_covered": 84.61538461538461, "percent_covered_display": "85", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [90, 91], "excluded_lines": []}, "ConnectionHandler._check_relay_health": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [94, 95, 96, 97, 98, 101], "excluded_lines": []}, "ConnectionHandler.check_relay_health": {"executed_lines": [105, 107], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [106], "excluded_lines": []}, "ConnectionHandler.publish_json_to_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [116, 117, 118, 119, 120, 121, 123, 124, 125, 129, 130, 131, 132, 133, 135, 140, 141, 143, 144, 145, 146], "excluded_lines": []}, "ConnectionHandler.publish_event": {"executed_lines": [150, 152, 153], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [151], "excluded_lines": []}, "ConnectionHandler.update_relays": {"executed_lines": [157, 158, 159, 160, 161, 162], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConnectionHandler.retrieve_json_from_nostr": {"executed_lines": [168, 171, 172, 173, 174, 176, 182, 183, 184, 186, 187, 188, 189, 190, 191, 192, 196, 197, 198, 199], "summary": {"covered_lines": 20, "num_statements": 25, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [169, 181, 193, 194, 195], "excluded_lines": []}, "ConnectionHandler._retrieve_json_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [202, 203, 204, 205, 206, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223], "excluded_lines": []}, "ConnectionHandler.close_client_pool": {"executed_lines": [227, 228, 231, 232], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [229, 230], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 15, 22, 23, 25, 32, 38, 45, 69, 93, 103, 109, 148, 155, 164, 201, 225], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"ConnectionHandler": {"executed_lines": [27, 29, 30, 40, 42, 43, 46, 49, 50, 51, 52, 53, 59, 60, 62, 63, 65, 66, 67, 71, 72, 73, 80, 81, 84, 85, 86, 87, 88, 89, 105, 107, 150, 152, 153, 157, 158, 159, 160, 161, 162, 168, 171, 172, 173, 174, 176, 182, 183, 184, 186, 187, 188, 189, 190, 191, 192, 196, 197, 198, 199, 227, 228, 231, 232], "summary": {"covered_lines": 65, "num_statements": 129, "percent_covered": 50.3875968992248, "percent_covered_display": "50", "missing_lines": 64, "excluded_lines": 0}, "missing_lines": [28, 34, 35, 36, 41, 47, 54, 55, 57, 90, 91, 94, 95, 96, 97, 98, 101, 106, 116, 117, 118, 119, 120, 121, 123, 124, 125, 129, 130, 131, 132, 133, 135, 140, 141, 143, 144, 145, 146, 151, 169, 181, 193, 194, 195, 202, 203, 204, 205, 206, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 229, 230], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 15, 22, 23, 25, 32, 38, 45, 69, 93, 103, 109, 148, 155, 164, 201, 225], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/key_manager.py": {"executed_lines": [3, 4, 5, 7, 8, 9, 12, 13, 15, 18, 19, 21, 36, 37, 41, 46, 47, 48, 49, 54, 57, 58, 64, 71, 72, 73, 74, 75, 80, 82, 83, 85, 89, 90, 91, 92, 97, 111, 122, 129, 131, 138, 140, 147, 148, 149, 150, 151, 152, 157], "summary": {"covered_lines": 49, "num_statements": 84, "percent_covered": 58.333333333333336, "percent_covered_display": "58", "missing_lines": 35, "excluded_lines": 0}, "missing_lines": [38, 42, 60, 61, 62, 76, 77, 78, 93, 94, 95, 99, 100, 103, 106, 107, 108, 109, 113, 114, 117, 118, 119, 120, 153, 154, 155, 159, 160, 161, 162, 163, 164, 165, 166], "excluded_lines": [], "functions": {"KeyManager.__init__": {"executed_lines": [36, 37, 41, 46, 47, 48, 49, 54, 57, 58], "summary": {"covered_lines": 10, "num_statements": 15, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [38, 42, 60, 61, 62], "excluded_lines": []}, "KeyManager.initialize_bip85": {"executed_lines": [71, 72, 73, 74, 75], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [76, 77, 78], "excluded_lines": []}, "KeyManager.generate_nostr_keys": {"executed_lines": [82, 83, 85, 89, 90, 91, 92], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [93, 94, 95], "excluded_lines": []}, "KeyManager.generate_v1_nostr_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [99, 100, 103, 106, 107, 108, 109], "excluded_lines": []}, "KeyManager.generate_legacy_nostr_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [113, 114, 117, 118, 119, 120], "excluded_lines": []}, "KeyManager.get_public_key_hex": {"executed_lines": [129], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "KeyManager.get_private_key_hex": {"executed_lines": [138], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "KeyManager.get_npub": {"executed_lines": [147, 148, 149, 150, 151, 152], "summary": {"covered_lines": 6, "num_statements": 9, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [153, 154, 155], "excluded_lines": []}, "KeyManager.get_nsec": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [159, 160, 161, 162, 163, 164, 165, 166], "excluded_lines": []}, "": {"executed_lines": [3, 4, 5, 7, 8, 9, 12, 13, 15, 18, 19, 21, 64, 80, 97, 111, 122, 131, 140, 157], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"KeyManager": {"executed_lines": [36, 37, 41, 46, 47, 48, 49, 54, 57, 58, 71, 72, 73, 74, 75, 82, 83, 85, 89, 90, 91, 92, 129, 138, 147, 148, 149, 150, 151, 152], "summary": {"covered_lines": 30, "num_statements": 65, "percent_covered": 46.15384615384615, "percent_covered_display": "46", "missing_lines": 35, "excluded_lines": 0}, "missing_lines": [38, 42, 60, 61, 62, 76, 77, 78, 93, 94, 95, 99, 100, 103, 106, 107, 108, 109, 113, 114, 117, 118, 119, 120, 153, 154, 155, 159, 160, 161, 162, 163, 164, 165, 166], "excluded_lines": []}, "": {"executed_lines": [3, 4, 5, 7, 8, 9, 12, 13, 15, 18, 19, 21, 64, 80, 97, 111, 122, 131, 140, 157], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/snapshot.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 25, 26, 29, 33, 34, 35, 36, 37, 45, 46, 49, 57, 58, 59, 62, 63, 65, 68, 69, 71, 72, 73, 75, 76, 77, 78, 79, 81, 82, 83, 86, 87, 90, 91, 92, 93, 99, 104, 105, 107, 108, 110, 120, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 137, 140, 141, 142, 143, 144, 158, 159, 160, 162, 167, 168, 169, 170, 172, 173, 174, 175, 176, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 204, 206, 207, 208, 212, 214, 215, 216, 217, 218, 219, 221, 225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 245, 265, 266, 267, 268, 269, 277, 279, 281, 283, 284, 285, 286, 287, 292, 293, 294, 295, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 312, 314, 316, 317, 318, 319, 320, 321, 328, 329, 330, 333, 335, 336, 337, 338, 339, 342, 343, 344, 345, 346, 348, 349, 351, 352, 353, 354, 355, 358, 359, 360, 361, 364, 366, 367, 368, 369, 370, 381, 389, 390, 391, 392, 394, 395, 397, 398, 399, 405, 406, 407, 410, 411, 412, 413, 414, 415, 416, 420, 421, 422, 423, 424, 427, 430, 431, 433, 434, 435, 437, 438, 439, 441, 442, 443], "summary": {"covered_lines": 232, "num_statements": 264, "percent_covered": 87.87878787878788, "percent_covered_display": "88", "missing_lines": 32, "excluded_lines": 11}, "missing_lines": [70, 84, 85, 96, 97, 155, 156, 205, 209, 210, 211, 213, 246, 252, 253, 262, 263, 282, 290, 291, 308, 309, 310, 315, 331, 332, 334, 340, 341, 350, 365, 396], "excluded_lines": [236, 237, 238, 243, 254, 255, 256, 261, 270, 271, 272], "functions": {"prepare_snapshot": {"executed_lines": [33, 34, 35, 36, 37, 45, 46], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "new_manifest_id": {"executed_lines": [57, 58, 59], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SnapshotHandler.publish_snapshot": {"executed_lines": [68, 69, 71, 72, 73, 75, 76, 77, 78, 79, 81, 82, 83, 86, 87, 90, 91, 92, 93, 99, 104, 105, 107, 108, 110, 120, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135], "summary": {"covered_lines": 36, "num_statements": 41, "percent_covered": 87.8048780487805, "percent_covered_display": "88", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [70, 84, 85, 96, 97], "excluded_lines": []}, "SnapshotHandler._fetch_chunks_with_retry": {"executed_lines": [140, 141, 142, 143, 144, 158, 159, 160, 162, 167, 168, 169, 170, 172, 173, 174, 175, 176, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 204, 206, 207, 208, 212, 214, 215, 216, 217, 218, 219], "summary": {"covered_lines": 50, "num_statements": 57, "percent_covered": 87.71929824561404, "percent_covered_display": "88", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [155, 156, 205, 209, 210, 211, 213], "excluded_lines": []}, "SnapshotHandler._fetch_manifest_with_keys": {"executed_lines": [225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 245, 265, 266, 267, 268, 269, 277], "summary": {"covered_lines": 17, "num_statements": 22, "percent_covered": 77.27272727272727, "percent_covered_display": "77", "missing_lines": 5, "excluded_lines": 11}, "missing_lines": [246, 252, 253, 262, 263], "excluded_lines": [236, 237, 238, 243, 254, 255, 256, 261, 270, 271, 272]}, "SnapshotHandler.fetch_latest_snapshot": {"executed_lines": [281, 283, 284, 285, 286, 287, 292, 293, 294, 295, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307], "summary": {"covered_lines": 20, "num_statements": 26, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [282, 290, 291, 308, 309, 310], "excluded_lines": []}, "SnapshotHandler.ensure_manifest_is_current": {"executed_lines": [314, 316, 317, 318, 319, 320, 321, 328, 329, 330, 333, 335, 336, 337, 338, 339, 342, 343, 344, 345, 346], "summary": {"covered_lines": 21, "num_statements": 27, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [315, 331, 332, 334, 340, 341], "excluded_lines": []}, "SnapshotHandler.publish_delta": {"executed_lines": [349, 351, 352, 353, 354, 355, 358, 359, 360, 361, 364, 366, 367, 368, 369, 370, 381, 389, 390, 391, 392], "summary": {"covered_lines": 21, "num_statements": 23, "percent_covered": 91.30434782608695, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [350, 365], "excluded_lines": []}, "SnapshotHandler.fetch_deltas_since": {"executed_lines": [395, 397, 398, 399, 405, 406, 407, 410, 411, 412, 413, 414, 415, 416, 420, 421, 422, 423, 424, 427, 430, 431], "summary": {"covered_lines": 22, "num_statements": 23, "percent_covered": 95.65217391304348, "percent_covered_display": "96", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [396], "excluded_lines": []}, "SnapshotHandler.get_current_manifest": {"executed_lines": [434, 435], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SnapshotHandler.get_current_manifest_id": {"executed_lines": [438, 439], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SnapshotHandler.get_delta_events": {"executed_lines": [442, 443], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 25, 26, 29, 49, 62, 63, 65, 137, 221, 279, 312, 348, 394, 433, 437, 441], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"SnapshotHandler": {"executed_lines": [68, 69, 71, 72, 73, 75, 76, 77, 78, 79, 81, 82, 83, 86, 87, 90, 91, 92, 93, 99, 104, 105, 107, 108, 110, 120, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 140, 141, 142, 143, 144, 158, 159, 160, 162, 167, 168, 169, 170, 172, 173, 174, 175, 176, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 204, 206, 207, 208, 212, 214, 215, 216, 217, 218, 219, 225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 245, 265, 266, 267, 268, 269, 277, 281, 283, 284, 285, 286, 287, 292, 293, 294, 295, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 314, 316, 317, 318, 319, 320, 321, 328, 329, 330, 333, 335, 336, 337, 338, 339, 342, 343, 344, 345, 346, 349, 351, 352, 353, 354, 355, 358, 359, 360, 361, 364, 366, 367, 368, 369, 370, 381, 389, 390, 391, 392, 395, 397, 398, 399, 405, 406, 407, 410, 411, 412, 413, 414, 415, 416, 420, 421, 422, 423, 424, 427, 430, 431, 434, 435, 438, 439, 442, 443], "summary": {"covered_lines": 193, "num_statements": 225, "percent_covered": 85.77777777777777, "percent_covered_display": "86", "missing_lines": 32, "excluded_lines": 11}, "missing_lines": [70, 84, 85, 96, 97, 155, 156, 205, 209, 210, 211, 213, 246, 252, 253, 262, 263, 282, 290, 291, 308, 309, 310, 315, 331, 332, 334, 340, 341, 350, 365, 396], "excluded_lines": [236, 237, 238, 243, 254, 255, 256, 261, 270, 271, 272]}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 25, 26, 29, 33, 34, 35, 36, 37, 45, 46, 49, 57, 58, 59, 62, 63, 65, 137, 221, 279, 312, 348, 394, 433, 437, 441], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/__init__.py": {"executed_lines": [1], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [1], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/api.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 20, 22, 23, 24, 25, 27, 28, 29, 31, 32, 33, 35, 36, 38, 41, 42, 43, 44, 47, 48, 50, 51, 52, 53, 56, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 70, 78, 79, 82, 83, 84, 85, 86, 87, 88, 89, 94, 95, 101, 104, 105, 106, 107, 110, 116, 117, 118, 119, 120, 123, 124, 127, 128, 129, 130, 143, 144, 150, 151, 152, 153, 154, 156, 159, 160, 171, 172, 174, 176, 177, 187, 189, 197, 199, 200, 202, 214, 216, 217, 225, 279, 280, 291, 292, 293, 294, 305, 306, 307, 310, 311, 315, 316, 317, 318, 321, 322, 326, 327, 328, 329, 332, 333, 336, 337, 338, 340, 342, 345, 346, 353, 354, 355, 356, 367, 369, 370, 372, 375, 376, 379, 380, 384, 385, 386, 388, 390, 392, 393, 394, 395, 396, 397, 400, 401, 404, 405, 406, 409, 410, 414, 415, 416, 417, 420, 421, 425, 426, 427, 428, 431, 432, 436, 437, 438, 440, 442, 443, 446, 447, 453, 454, 455, 456, 457, 460, 461, 467, 468, 469, 470, 473, 474, 475, 476, 478, 480, 483, 486, 487, 491, 492, 493, 496, 497, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 513, 514, 515, 516, 517, 520, 521, 523, 524, 525, 526, 529, 530, 534, 535, 536, 538, 540, 541, 543, 545, 546, 547, 548, 551, 552, 556, 557, 558, 559, 561, 563, 565, 566, 567, 568, 571, 572, 576, 577, 578, 580, 581, 582, 583, 586, 587, 591, 592, 593, 594, 597, 598, 602, 603, 604, 605, 608, 609, 615, 616, 617, 618, 619, 621, 622, 625, 626, 630, 631, 633, 635, 636, 637, 639, 641, 642, 643, 644, 645, 646, 648, 650, 651, 653, 656, 657, 658, 663, 664, 665, 668, 669, 676, 677, 678, 680, 682, 684, 686, 688, 689, 690, 691, 694, 695, 699, 700, 701, 703, 706, 707, 711, 712, 713, 715, 725, 727, 728, 729, 732, 733, 737, 738, 739, 740, 743, 744, 747, 748, 750], "summary": {"covered_lines": 349, "num_statements": 378, "percent_covered": 92.32804232804233, "percent_covered_display": "92", "missing_lines": 29, "excluded_lines": 0}, "missing_lines": [49, 81, 155, 227, 228, 238, 240, 241, 249, 251, 252, 259, 261, 262, 267, 274, 276, 341, 373, 391, 441, 539, 544, 562, 564, 620, 640, 654, 687], "excluded_lines": [], "functions": {"_get_pm": {"executed_lines": [42, 43, 44], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_check_token": {"executed_lines": [48, 50, 51, 52, 53], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [49], "excluded_lines": []}, "_reload_relays": {"executed_lines": [58, 59, 60, 61, 62, 63, 64, 65, 66, 67], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "start_server": {"executed_lines": [78, 79, 82, 83, 84, 85, 86, 87, 88, 89, 94, 95, 101], "summary": {"covered_lines": 13, "num_statements": 14, "percent_covered": 92.85714285714286, "percent_covered_display": "93", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [81], "excluded_lines": []}, "_require_password": {"executed_lines": [105, 106, 107], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_validate_encryption_path": {"executed_lines": [116, 117, 118, 119, 120], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "search_entry": {"executed_lines": [127, 128, 129, 130], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_entry": {"executed_lines": [150, 151, 152, 153, 154, 156], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [155], "excluded_lines": []}, "create_entry": {"executed_lines": [171, 172, 174, 176, 177, 187, 189, 197, 199, 200, 202, 214, 216, 217, 225], "summary": {"covered_lines": 15, "num_statements": 29, "percent_covered": 51.724137931034484, "percent_covered_display": "52", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [227, 228, 238, 240, 241, 249, 251, 252, 259, 261, 262, 267, 274, 276], "excluded_lines": []}, "update_entry": {"executed_lines": [291, 292, 293, 294, 305, 306, 307], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "archive_entry": {"executed_lines": [315, 316, 317, 318], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "unarchive_entry": {"executed_lines": [326, 327, 328, 329], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_config": {"executed_lines": [336, 337, 338, 340, 342], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [341], "excluded_lines": []}, "update_config": {"executed_lines": [353, 354, 355, 356, 367, 369, 370, 372, 375, 376], "summary": {"covered_lines": 10, "num_statements": 11, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [373], "excluded_lines": []}, "set_secret_mode": {"executed_lines": [384, 385, 386, 388, 390, 392, 393, 394, 395, 396, 397], "summary": {"covered_lines": 11, "num_statements": 12, "percent_covered": 91.66666666666667, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [391], "excluded_lines": []}, "list_fingerprints": {"executed_lines": [404, 405, 406], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "add_fingerprint": {"executed_lines": [414, 415, 416, 417], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "remove_fingerprint": {"executed_lines": [425, 426, 427, 428], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "select_fingerprint": {"executed_lines": [436, 437, 438, 440, 442, 443], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [441], "excluded_lines": []}, "export_totp": {"executed_lines": [453, 454, 455, 456, 457], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_totp_codes": {"executed_lines": [467, 468, 469, 470, 473, 474, 475, 476, 478, 480, 483], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_profile_stats": {"executed_lines": [491, 492, 493], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_notifications": {"executed_lines": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_nostr_pubkey": {"executed_lines": [515, 516, 517], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "list_relays": {"executed_lines": [523, 524, 525, 526], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "add_relay": {"executed_lines": [534, 535, 536, 538, 540, 541, 543, 545, 546, 547, 548], "summary": {"covered_lines": 11, "num_statements": 13, "percent_covered": 84.61538461538461, "percent_covered_display": "85", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [539, 544], "excluded_lines": []}, "remove_relay": {"executed_lines": [556, 557, 558, 559, 561, 563, 565, 566, 567, 568], "summary": {"covered_lines": 10, "num_statements": 12, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [562, 564], "excluded_lines": []}, "reset_relays": {"executed_lines": [576, 577, 578, 580, 581, 582, 583], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "verify_checksum": {"executed_lines": [591, 592, 593, 594], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "update_checksum": {"executed_lines": [602, 603, 604, 605], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "export_vault": {"executed_lines": [615, 616, 617, 618, 619, 621, 622], "summary": {"covered_lines": 7, "num_statements": 8, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [620], "excluded_lines": []}, "import_vault": {"executed_lines": [630, 631, 633, 635, 636, 637, 639, 641, 642, 643, 644, 645, 646, 648, 650, 651, 653, 656, 657, 658, 663, 664, 665], "summary": {"covered_lines": 23, "num_statements": 25, "percent_covered": 92.0, "percent_covered_display": "92", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [640, 654], "excluded_lines": []}, "backup_parent_seed": {"executed_lines": [676, 677, 678, 680, 682, 684, 686, 688, 689, 690, 691], "summary": {"covered_lines": 11, "num_statements": 12, "percent_covered": 91.66666666666667, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [687], "excluded_lines": []}, "change_password": {"executed_lines": [699, 700, 701, 703], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "generate_password": {"executed_lines": [711, 712, 713, 715, 725, 727, 728, 729], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "lock_vault": {"executed_lines": [737, 738, 739, 740], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "shutdown_server": {"executed_lines": [747, 748, 750], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 20, 22, 23, 24, 25, 27, 28, 29, 31, 32, 33, 35, 36, 38, 41, 47, 56, 70, 104, 110, 123, 124, 143, 144, 159, 160, 279, 280, 310, 311, 321, 322, 332, 333, 345, 346, 379, 380, 400, 401, 409, 410, 420, 421, 431, 432, 446, 447, 460, 461, 486, 487, 496, 497, 513, 514, 520, 521, 529, 530, 551, 552, 571, 572, 586, 587, 597, 598, 608, 609, 625, 626, 668, 669, 694, 695, 706, 707, 732, 733, 743, 744], "summary": {"covered_lines": 95, "num_statements": 95, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 20, 22, 23, 24, 25, 27, 28, 29, 31, 32, 33, 35, 36, 38, 41, 42, 43, 44, 47, 48, 50, 51, 52, 53, 56, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 70, 78, 79, 82, 83, 84, 85, 86, 87, 88, 89, 94, 95, 101, 104, 105, 106, 107, 110, 116, 117, 118, 119, 120, 123, 124, 127, 128, 129, 130, 143, 144, 150, 151, 152, 153, 154, 156, 159, 160, 171, 172, 174, 176, 177, 187, 189, 197, 199, 200, 202, 214, 216, 217, 225, 279, 280, 291, 292, 293, 294, 305, 306, 307, 310, 311, 315, 316, 317, 318, 321, 322, 326, 327, 328, 329, 332, 333, 336, 337, 338, 340, 342, 345, 346, 353, 354, 355, 356, 367, 369, 370, 372, 375, 376, 379, 380, 384, 385, 386, 388, 390, 392, 393, 394, 395, 396, 397, 400, 401, 404, 405, 406, 409, 410, 414, 415, 416, 417, 420, 421, 425, 426, 427, 428, 431, 432, 436, 437, 438, 440, 442, 443, 446, 447, 453, 454, 455, 456, 457, 460, 461, 467, 468, 469, 470, 473, 474, 475, 476, 478, 480, 483, 486, 487, 491, 492, 493, 496, 497, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 513, 514, 515, 516, 517, 520, 521, 523, 524, 525, 526, 529, 530, 534, 535, 536, 538, 540, 541, 543, 545, 546, 547, 548, 551, 552, 556, 557, 558, 559, 561, 563, 565, 566, 567, 568, 571, 572, 576, 577, 578, 580, 581, 582, 583, 586, 587, 591, 592, 593, 594, 597, 598, 602, 603, 604, 605, 608, 609, 615, 616, 617, 618, 619, 621, 622, 625, 626, 630, 631, 633, 635, 636, 637, 639, 641, 642, 643, 644, 645, 646, 648, 650, 651, 653, 656, 657, 658, 663, 664, 665, 668, 669, 676, 677, 678, 680, 682, 684, 686, 688, 689, 690, 691, 694, 695, 699, 700, 701, 703, 706, 707, 711, 712, 713, 715, 725, 727, 728, 729, 732, 733, 737, 738, 739, 740, 743, 744, 747, 748, 750], "summary": {"covered_lines": 349, "num_statements": 378, "percent_covered": 92.32804232804233, "percent_covered_display": "92", "missing_lines": 29, "excluded_lines": 0}, "missing_lines": [49, 81, 155, 227, 228, 238, 240, 241, 249, 251, 252, 259, 261, 262, 267, 274, 276, 341, 373, 391, 441, 539, 544, 562, 564, 620, 640, 654, 687], "excluded_lines": []}}}, "src/seedpass/cli/__init__.py": {"executed_lines": [1, 3, 4, 5, 6, 7, 9, 11, 12, 14, 20, 27, 33, 40, 42, 43, 44, 45, 46, 47, 48, 51, 60, 62, 63, 64, 68, 69, 79, 84, 85, 86, 89, 90, 92, 93, 94, 97, 98, 111, 112, 113, 114, 115, 131, 132, 137, 139, 145, 150, 151, 162, 171, 178, 180, 183], "summary": {"covered_lines": 55, "num_statements": 78, "percent_covered": 70.51282051282051, "percent_covered_display": "71", "missing_lines": 23, "excluded_lines": 2}, "missing_lines": [53, 54, 55, 56, 57, 65, 116, 117, 118, 119, 120, 121, 122, 123, 125, 129, 142, 143, 163, 164, 169, 172, 176], "excluded_lines": [183, 184], "functions": {"run": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [53, 54, 55, 56, 57], "excluded_lines": []}, "_gui_backend_available": {"executed_lines": [62, 63, 64], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [65], "excluded_lines": []}, "main": {"executed_lines": [79, 84, 85, 86], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "root_lock": {"executed_lines": [92, 93, 94], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "gui": {"executed_lines": [111, 112, 113, 114, 115, 131, 132, 137, 139, 145, 150, 151, 162, 171, 178, 180], "summary": {"covered_lines": 16, "num_statements": 33, "percent_covered": 48.484848484848484, "percent_covered_display": "48", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [116, 117, 118, 119, 120, 121, 122, 123, 125, 129, 142, 143, 163, 164, 169, 172, 176], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 7, 9, 11, 12, 14, 20, 27, 33, 40, 42, 43, 44, 45, 46, 47, 48, 51, 60, 68, 69, 89, 90, 97, 98, 183], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [183, 184]}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 6, 7, 9, 11, 12, 14, 20, 27, 33, 40, 42, 43, 44, 45, 46, 47, 48, 51, 60, 62, 63, 64, 68, 69, 79, 84, 85, 86, 89, 90, 92, 93, 94, 97, 98, 111, 112, 113, 114, 115, 131, 132, 137, 139, 145, 150, 151, 162, 171, 178, 180, 183], "summary": {"covered_lines": 55, "num_statements": 78, "percent_covered": 70.51282051282051, "percent_covered_display": "71", "missing_lines": 23, "excluded_lines": 2}, "missing_lines": [53, 54, 55, 56, 57, 65, 116, 117, 118, 119, 120, 121, 122, 123, 125, 129, 142, 143, 163, 164, 169, 172, 176], "excluded_lines": [183, 184]}}}, "src/seedpass/cli/api.py": {"executed_lines": [1, 3, 4, 6, 8, 11, 12, 14, 15, 18, 21, 22], "summary": {"covered_lines": 12, "num_statements": 15, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 3, "excluded_lines": 2}, "missing_lines": [28, 30, 31], "excluded_lines": [36, 37], "functions": {"api_start": {"executed_lines": [14, 15, 18], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "api_stop": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 2}, "missing_lines": [28, 30, 31], "excluded_lines": [36, 37]}, "": {"executed_lines": [1, 3, 4, 6, 8, 11, 12, 21, 22], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 6, 8, 11, 12, 14, 15, 18, 21, 22], "summary": {"covered_lines": 12, "num_statements": 15, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 3, "excluded_lines": 2}, "missing_lines": [28, 30, 31], "excluded_lines": [36, 37]}}}, "src/seedpass/cli/common.py": {"executed_lines": [1, 3, 5, 6, 7, 23, 25, 26, 27, 29, 30, 32, 34, 37, 42, 43, 46, 47, 48, 51, 52, 53, 56, 57, 58, 61, 62, 63], "summary": {"covered_lines": 28, "num_statements": 30, "percent_covered": 93.33333333333333, "percent_covered_display": "93", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [31, 33], "excluded_lines": [], "functions": {"_get_pm": {"executed_lines": [25, 26, 27, 29, 30, 32, 34], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [31, 33], "excluded_lines": []}, "_get_services": {"executed_lines": [42, 43], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_get_entry_service": {"executed_lines": [47, 48], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_get_config_service": {"executed_lines": [52, 53], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_get_util_service": {"executed_lines": [57, 58], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_get_nostr_service": {"executed_lines": [62, 63], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 23, 37, 46, 51, 56, 61], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 6, 7, 23, 25, 26, 27, 29, 30, 32, 34, 37, 42, 43, 46, 47, 48, 51, 52, 53, 56, 57, 58, 61, 62, 63], "summary": {"covered_lines": 28, "num_statements": 30, "percent_covered": 93.33333333333333, "percent_covered_display": "93", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [31, 33], "excluded_lines": []}}}, "src/seedpass/cli/config.py": {"executed_lines": [1, 3, 5, 7, 10, 11, 13, 14, 15, 16, 18, 21, 22, 24, 26, 27, 32, 33, 34, 35, 40, 43, 44, 50, 51, 52, 53, 58, 59, 66, 67, 68, 71, 74, 75, 76, 77, 84, 85, 90, 91, 94, 95, 97, 98, 99, 104, 105, 112, 114, 115, 117, 118, 123, 124], "summary": {"covered_lines": 55, "num_statements": 62, "percent_covered": 88.70967741935483, "percent_covered_display": "89", "missing_lines": 7, "excluded_lines": 15}, "missing_lines": [69, 78, 79, 80, 81, 82, 113], "excluded_lines": [36, 37, 38, 54, 55, 56, 86, 87, 88, 100, 101, 102, 119, 120, 121], "functions": {"config_get": {"executed_lines": [13, 14, 15, 16, 18], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "config_set": {"executed_lines": [24, 26, 27, 32, 33, 34, 35, 40], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [36, 37, 38]}, "config_toggle_secret_mode": {"executed_lines": [50, 51, 52, 53, 58, 59, 66, 67, 68, 71, 74, 75, 76, 77, 84, 85, 90, 91], "summary": {"covered_lines": 18, "num_statements": 24, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 6, "excluded_lines": 6}, "missing_lines": [69, 78, 79, 80, 81, 82], "excluded_lines": [54, 55, 56, 86, 87, 88]}, "config_toggle_offline": {"executed_lines": [97, 98, 99, 104, 105, 112, 114, 115, 117, 118, 123, 124], "summary": {"covered_lines": 12, "num_statements": 13, "percent_covered": 92.3076923076923, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 6}, "missing_lines": [113], "excluded_lines": [100, 101, 102, 119, 120, 121]}, "": {"executed_lines": [1, 3, 5, 7, 10, 11, 21, 22, 43, 44, 94, 95], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 7, 10, 11, 13, 14, 15, 16, 18, 21, 22, 24, 26, 27, 32, 33, 34, 35, 40, 43, 44, 50, 51, 52, 53, 58, 59, 66, 67, 68, 71, 74, 75, 76, 77, 84, 85, 90, 91, 94, 95, 97, 98, 99, 104, 105, 112, 114, 115, 117, 118, 123, 124], "summary": {"covered_lines": 55, "num_statements": 62, "percent_covered": 88.70967741935483, "percent_covered_display": "89", "missing_lines": 7, "excluded_lines": 15}, "missing_lines": [69, 78, 79, 80, 81, 82, 113], "excluded_lines": [36, 37, 38, 54, 55, 56, 86, 87, 88, 100, 101, 102, 119, 120, 121]}}}, "src/seedpass/cli/entry.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 12, 13, 15, 18, 19, 33, 34, 39, 40, 41, 42, 43, 44, 45, 47, 50, 51, 63, 64, 65, 66, 69, 70, 71, 72, 73, 75, 78, 79, 81, 82, 83, 84, 87, 96, 97, 98, 99, 100, 101, 102, 109, 110, 115, 118, 119, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 166, 167, 170, 171, 183, 184, 192, 195, 196, 203, 204, 209, 212, 213, 222, 223, 230, 233, 234, 241, 242, 247, 250, 251, 259, 260, 266, 269, 270, 278, 279, 280, 283, 284, 291, 292, 297, 300, 301, 316, 317, 318, 329, 330, 331, 332, 335, 336, 338, 339, 340, 343, 344, 346, 347, 348, 351, 352, 354, 355, 358, 359, 363, 364, 365, 366], "summary": {"covered_lines": 138, "num_statements": 156, "percent_covered": 88.46153846153847, "percent_covered_display": "88", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [46, 67, 68, 74, 85, 86, 88, 89, 90, 91, 92, 93, 94, 103, 104, 105, 107, 108], "excluded_lines": [], "functions": {"entry_list": {"executed_lines": [33, 34, 39, 40, 41, 42, 43, 44, 45, 47], "summary": {"covered_lines": 10, "num_statements": 11, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [46], "excluded_lines": []}, "entry_search": {"executed_lines": [63, 64, 65, 66, 69, 70, 71, 72, 73, 75], "summary": {"covered_lines": 10, "num_statements": 13, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [67, 68, 74], "excluded_lines": []}, "entry_get": {"executed_lines": [81, 82, 83, 84, 87, 96, 97, 98, 99, 100, 101, 102, 109, 110, 115], "summary": {"covered_lines": 15, "num_statements": 29, "percent_covered": 51.724137931034484, "percent_covered_display": "52", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [85, 86, 88, 89, 90, 91, 92, 93, 94, 103, 104, 105, 107, 108], "excluded_lines": []}, "entry_add": {"executed_lines": [147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 166, 167], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_add_totp": {"executed_lines": [183, 184, 192], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_add_ssh": {"executed_lines": [203, 204, 209], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_add_pgp": {"executed_lines": [222, 223, 230], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_add_nostr": {"executed_lines": [241, 242, 247], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_add_seed": {"executed_lines": [259, 260, 266], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_add_key_value": {"executed_lines": [278, 279, 280], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_add_managed_account": {"executed_lines": [291, 292, 297], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_modify": {"executed_lines": [316, 317, 318, 329, 330, 331, 332], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_archive": {"executed_lines": [338, 339, 340], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_unarchive": {"executed_lines": [346, 347, 348], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_totp_codes": {"executed_lines": [354, 355], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_export_totp": {"executed_lines": [363, 364, 365, 366], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 12, 13, 15, 18, 19, 50, 51, 78, 79, 118, 119, 170, 171, 195, 196, 212, 213, 233, 234, 250, 251, 269, 270, 283, 284, 300, 301, 335, 336, 343, 344, 351, 352, 358, 359], "summary": {"covered_lines": 43, "num_statements": 43, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 12, 13, 15, 18, 19, 33, 34, 39, 40, 41, 42, 43, 44, 45, 47, 50, 51, 63, 64, 65, 66, 69, 70, 71, 72, 73, 75, 78, 79, 81, 82, 83, 84, 87, 96, 97, 98, 99, 100, 101, 102, 109, 110, 115, 118, 119, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 166, 167, 170, 171, 183, 184, 192, 195, 196, 203, 204, 209, 212, 213, 222, 223, 230, 233, 234, 241, 242, 247, 250, 251, 259, 260, 266, 269, 270, 278, 279, 280, 283, 284, 291, 292, 297, 300, 301, 316, 317, 318, 329, 330, 331, 332, 335, 336, 338, 339, 340, 343, 344, 346, 347, 348, 351, 352, 354, 355, 358, 359, 363, 364, 365, 366], "summary": {"covered_lines": 138, "num_statements": 156, "percent_covered": 88.46153846153847, "percent_covered_display": "88", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [46, 67, 68, 74, 85, 86, 88, 89, 90, 91, 92, 93, 94, 103, 104, 105, 107, 108], "excluded_lines": []}}}, "src/seedpass/cli/fingerprint.py": {"executed_lines": [1, 3, 5, 7, 10, 11, 13, 14, 15, 18, 19, 21, 22, 25, 26, 28, 29, 32, 33, 35, 36, 37], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"fingerprint_list": {"executed_lines": [13, 14, 15], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "fingerprint_add": {"executed_lines": [21, 22], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "fingerprint_remove": {"executed_lines": [28, 29], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "fingerprint_switch": {"executed_lines": [35, 36, 37], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 7, 10, 11, 18, 19, 25, 26, 32, 33], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 7, 10, 11, 13, 14, 15, 18, 19, 21, 22, 25, 26, 28, 29, 32, 33, 35, 36, 37], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/cli/nostr.py": {"executed_lines": [1, 3, 5, 7, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 28, 29, 31, 32, 33, 36, 37, 39, 40, 41, 42, 45, 46, 48, 49, 50, 54, 57, 58, 60, 61, 62, 66], "summary": {"covered_lines": 38, "num_statements": 39, "percent_covered": 97.43589743589743, "percent_covered_display": "97", "missing_lines": 1, "excluded_lines": 6}, "missing_lines": [25], "excluded_lines": [51, 52, 53, 63, 64, 65], "functions": {"nostr_sync": {"executed_lines": [15, 16, 17, 18, 19, 20, 21, 22, 23], "summary": {"covered_lines": 9, "num_statements": 10, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [25], "excluded_lines": []}, "nostr_get_pubkey": {"executed_lines": [31, 32, 33], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "nostr_list_relays": {"executed_lines": [39, 40, 41, 42], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "nostr_add_relay": {"executed_lines": [48, 49, 50, 54], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [51, 52, 53]}, "nostr_remove_relay": {"executed_lines": [60, 61, 62, 66], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [63, 64, 65]}, "": {"executed_lines": [1, 3, 5, 7, 12, 13, 28, 29, 36, 37, 45, 46, 57, 58], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 7, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 28, 29, 31, 32, 33, 36, 37, 39, 40, 41, 42, 45, 46, 48, 49, 50, 54, 57, 58, 60, 61, 62, 66], "summary": {"covered_lines": 38, "num_statements": 39, "percent_covered": 97.43589743589743, "percent_covered_display": "97", "missing_lines": 1, "excluded_lines": 6}, "missing_lines": [25], "excluded_lines": [51, 52, 53, 63, 64, 65]}}}, "src/seedpass/cli/util.py": {"executed_lines": [1, 3, 5, 7, 9, 12, 13, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 57, 58, 61, 62, 64, 65, 68, 69, 71, 72], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"generate_password": {"executed_lines": [38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 57, 58], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "verify_checksum": {"executed_lines": [64, 65], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "update_checksum": {"executed_lines": [71, 72], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 7, 9, 12, 13, 61, 62, 68, 69], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 7, 9, 12, 13, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 57, 58, 61, 62, 64, 65, 68, 69, 71, 72], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/cli/vault.py": {"executed_lines": [1, 3, 4, 5, 7, 9, 16, 19, 20, 24, 25, 26, 27, 30, 31, 35, 36, 37, 38, 41, 42, 44, 45, 46, 47, 48, 54, 57, 58, 60, 61, 62, 63, 67, 70, 71, 73, 74, 75, 78, 79, 81, 82, 83, 86, 87, 94, 95, 96], "summary": {"covered_lines": 49, "num_statements": 49, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [51, 52, 53, 64, 65, 66], "functions": {"vault_export": {"executed_lines": [24, 25, 26, 27], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "vault_import": {"executed_lines": [35, 36, 37, 38], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "vault_change_password": {"executed_lines": [44, 45, 46, 47, 48, 54], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [51, 52, 53]}, "vault_unlock": {"executed_lines": [60, 61, 62, 63, 67], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [64, 65, 66]}, "vault_lock": {"executed_lines": [73, 74, 75], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "vault_stats": {"executed_lines": [81, 82, 83], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "vault_reveal_parent_seed": {"executed_lines": [94, 95, 96], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 16, 19, 20, 30, 31, 41, 42, 57, 58, 70, 71, 78, 79, 86, 87], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 7, 9, 16, 19, 20, 24, 25, 26, 27, 30, 31, 35, 36, 37, 38, 41, 42, 44, 45, 46, 47, 48, 54, 57, 58, 60, 61, 62, 63, 67, 70, 71, 73, 74, 75, 78, 79, 81, 82, 83, 86, 87, 94, 95, 96], "summary": {"covered_lines": 49, "num_statements": 49, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [51, 52, 53, 64, 65, 66]}}}, "src/seedpass/core/__init__.py": {"executed_lines": [3, 5, 7, 17, 18, 20, 22, 24, 26, 28, 30], "summary": {"covered_lines": 10, "num_statements": 16, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [19, 21, 23, 25, 27, 29], "excluded_lines": [], "functions": {"__getattr__": {"executed_lines": [18, 20, 22, 24, 26, 28, 30], "summary": {"covered_lines": 7, "num_statements": 13, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [19, 21, 23, 25, 27, 29], "excluded_lines": []}, "": {"executed_lines": [3, 5, 7, 17], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 5, 7, 17, 18, 20, 22, 24, 26, 28, 30], "summary": {"covered_lines": 10, "num_statements": 16, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [19, 21, 23, 25, 27, 29], "excluded_lines": []}}}, "src/seedpass/core/api.py": {"executed_lines": [1, 3, 10, 11, 12, 13, 14, 16, 18, 19, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 41, 42, 44, 45, 48, 49, 51, 54, 55, 57, 60, 61, 63, 64, 67, 68, 70, 71, 74, 75, 77, 80, 81, 83, 84, 85, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 108, 109, 112, 113, 116, 117, 119, 120, 121, 123, 126, 127, 128, 130, 133, 134, 135, 137, 140, 141, 142, 145, 147, 150, 151, 154, 155, 156, 158, 161, 162, 164, 167, 168, 169, 171, 174, 175, 177, 180, 181, 185, 188, 189, 192, 193, 195, 196, 197, 199, 202, 203, 205, 208, 209, 210, 214, 217, 218, 220, 223, 224, 227, 228, 230, 231, 232, 234, 237, 238, 239, 240, 241, 242, 243, 245, 248, 249, 251, 254, 255, 258, 259, 261, 262, 263, 265, 271, 272, 278, 291, 292, 294, 295, 296, 298, 299, 300, 301, 302, 303, 304, 306, 307, 308, 311, 313, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 355, 356, 358, 368, 369, 370, 379, 380, 382, 389, 390, 396, 397, 399, 408, 409, 417, 418, 420, 427, 428, 434, 435, 437, 445, 446, 453, 454, 456, 459, 460, 463, 464, 466, 473, 474, 480, 481, 483, 496, 497, 508, 510, 511, 512, 513, 515, 516, 517, 518, 520, 521, 522, 525, 527, 528, 529, 532, 533, 535, 536, 537, 539, 540, 541, 543, 544, 545, 581, 582, 583, 584, 585, 586, 587, 592, 593, 595, 597, 598, 599, 601, 602, 603, 605, 606, 607, 608, 609, 610, 611, 613, 614, 615, 617, 618, 619, 620, 621, 624, 625, 627, 628, 629, 631, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 660, 662, 665, 666, 670, 671, 673, 674, 676, 677, 678, 680, 681, 682, 685, 686, 688, 689, 690, 692, 693, 694, 696, 697, 698, 700, 701, 702, 703, 707, 708, 709, 710], "summary": {"covered_lines": 322, "num_statements": 325, "percent_covered": 99.07692307692308, "percent_covered_display": "99", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [659, 661, 663], "excluded_lines": [], "functions": {"VaultService.__init__": {"executed_lines": [120, 121], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.export_vault": {"executed_lines": [126, 127, 128], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.import_vault": {"executed_lines": [133, 134, 135], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.export_profile": {"executed_lines": [140, 141, 142, 145], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.import_profile": {"executed_lines": [150, 151, 154, 155, 156], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.change_password": {"executed_lines": [161, 162], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.unlock": {"executed_lines": [167, 168, 169], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.lock": {"executed_lines": [174, 175], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.backup_parent_seed": {"executed_lines": [180, 181], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.stats": {"executed_lines": [188, 189], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileService.__init__": {"executed_lines": [196, 197], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileService.list_profiles": {"executed_lines": [202, 203], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileService.add_profile": {"executed_lines": [208, 209, 210], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileService.remove_profile": {"executed_lines": [217, 218], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileService.switch_profile": {"executed_lines": [223, 224], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SyncService.__init__": {"executed_lines": [231, 232], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SyncService.sync": {"executed_lines": [237, 238, 239, 240, 241, 242, 243], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SyncService.start_background_sync": {"executed_lines": [248, 249], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SyncService.start_background_vault_sync": {"executed_lines": [254, 255], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.__init__": {"executed_lines": [262, 263], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.list_entries": {"executed_lines": [271, 272], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.search_entries": {"executed_lines": [291, 292], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.retrieve_entry": {"executed_lines": [295, 296], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.generate_password": {"executed_lines": [299, 300, 301, 302, 303, 304], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.get_totp_code": {"executed_lines": [307, 308, 311], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.add_entry": {"executed_lines": [329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 355, 356], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.add_totp": {"executed_lines": [368, 369, 370, 379, 380], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.add_ssh_key": {"executed_lines": [389, 390, 396, 397], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.add_pgp_key": {"executed_lines": [408, 409, 417, 418], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.add_nostr_key": {"executed_lines": [427, 428, 434, 435], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.add_seed": {"executed_lines": [445, 446, 453, 454], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.add_key_value": {"executed_lines": [459, 460, 463, 464], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.add_managed_account": {"executed_lines": [473, 474, 480, 481], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.modify_entry": {"executed_lines": [496, 497, 508], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.archive_entry": {"executed_lines": [511, 512, 513], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.restore_entry": {"executed_lines": [516, 517, 518], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.export_totp_entries": {"executed_lines": [521, 522, 525], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.display_totp_codes": {"executed_lines": [528, 529], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService.__init__": {"executed_lines": [536, 537], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService.get": {"executed_lines": [540, 541], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService.set": {"executed_lines": [544, 545, 581, 582, 583, 584, 585, 586, 587, 592, 593, 595], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService.get_secret_mode_enabled": {"executed_lines": [598, 599], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService.get_clipboard_clear_delay": {"executed_lines": [602, 603], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService.set_secret_mode": {"executed_lines": [606, 607, 608, 609, 610, 611], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService.get_offline_mode": {"executed_lines": [614, 615], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService.set_offline_mode": {"executed_lines": [618, 619, 620, 621], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "UtilityService.__init__": {"executed_lines": [628, 629], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "UtilityService.generate_password": {"executed_lines": [644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 660, 662, 665, 666, 670, 671, 673, 674], "summary": {"covered_lines": 23, "num_statements": 26, "percent_covered": 88.46153846153847, "percent_covered_display": "88", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [659, 661, 663], "excluded_lines": []}, "UtilityService.verify_checksum": {"executed_lines": [677, 678], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "UtilityService.update_checksum": {"executed_lines": [681, 682], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NostrService.__init__": {"executed_lines": [689, 690], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NostrService.get_pubkey": {"executed_lines": [693, 694], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NostrService.list_relays": {"executed_lines": [697, 698], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NostrService.add_relay": {"executed_lines": [701, 702, 703], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NostrService.remove_relay": {"executed_lines": [708, 709, 710], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 10, 11, 12, 13, 14, 16, 18, 19, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 41, 42, 44, 45, 48, 49, 51, 54, 55, 57, 60, 61, 63, 64, 67, 68, 70, 71, 74, 75, 77, 80, 81, 83, 84, 85, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 108, 109, 112, 113, 116, 117, 119, 123, 130, 137, 147, 158, 164, 171, 177, 185, 192, 193, 195, 199, 205, 214, 220, 227, 228, 230, 234, 245, 251, 258, 259, 261, 265, 278, 294, 298, 306, 313, 358, 382, 399, 420, 437, 456, 466, 483, 510, 515, 520, 527, 532, 533, 535, 539, 543, 597, 601, 605, 613, 617, 624, 625, 627, 631, 676, 680, 685, 686, 688, 692, 696, 700, 707], "summary": {"covered_lines": 116, "num_statements": 116, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"VaultExportRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultExportResponse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultImportRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ChangePasswordRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "UnlockRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "UnlockResponse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BackupParentSeedRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileSwitchRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileRemoveRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SyncResponse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordPolicyOptions": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AddPasswordEntryRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "GeneratePasswordRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "GeneratePasswordResponse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService": {"executed_lines": [120, 121, 126, 127, 128, 133, 134, 135, 140, 141, 142, 145, 150, 151, 154, 155, 156, 161, 162, 167, 168, 169, 174, 175, 180, 181, 188, 189], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileService": {"executed_lines": [196, 197, 202, 203, 208, 209, 210, 217, 218, 223, 224], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SyncService": {"executed_lines": [231, 232, 237, 238, 239, 240, 241, 242, 243, 248, 249, 254, 255], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService": {"executed_lines": [262, 263, 271, 272, 291, 292, 295, 296, 299, 300, 301, 302, 303, 304, 307, 308, 311, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 355, 356, 368, 369, 370, 379, 380, 389, 390, 396, 397, 408, 409, 417, 418, 427, 428, 434, 435, 445, 446, 453, 454, 459, 460, 463, 464, 473, 474, 480, 481, 496, 497, 508, 511, 512, 513, 516, 517, 518, 521, 522, 525, 528, 529], "summary": {"covered_lines": 81, "num_statements": 81, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService": {"executed_lines": [536, 537, 540, 541, 544, 545, 581, 582, 583, 584, 585, 586, 587, 592, 593, 595, 598, 599, 602, 603, 606, 607, 608, 609, 610, 611, 614, 615, 618, 619, 620, 621], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "UtilityService": {"executed_lines": [628, 629, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 660, 662, 665, 666, 670, 671, 673, 674, 677, 678, 681, 682], "summary": {"covered_lines": 29, "num_statements": 32, "percent_covered": 90.625, "percent_covered_display": "91", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [659, 661, 663], "excluded_lines": []}, "NostrService": {"executed_lines": [689, 690, 693, 694, 697, 698, 701, 702, 703, 708, 709, 710], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 10, 11, 12, 13, 14, 16, 18, 19, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 41, 42, 44, 45, 48, 49, 51, 54, 55, 57, 60, 61, 63, 64, 67, 68, 70, 71, 74, 75, 77, 80, 81, 83, 84, 85, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 108, 109, 112, 113, 116, 117, 119, 123, 130, 137, 147, 158, 164, 171, 177, 185, 192, 193, 195, 199, 205, 214, 220, 227, 228, 230, 234, 245, 251, 258, 259, 261, 265, 278, 294, 298, 306, 313, 358, 382, 399, 420, 437, 456, 466, 483, 510, 515, 520, 527, 532, 533, 535, 539, 543, 597, 601, 605, 613, 617, 624, 625, 627, 631, 676, 680, 685, 686, 688, 692, 696, 700, 707], "summary": {"covered_lines": 116, "num_statements": 116, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/backup.py": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 23, 24, 27, 30, 31, 39, 41, 51, 52, 53, 54, 55, 56, 57, 61, 62, 63, 64, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 89, 90, 95, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 114, 115, 116, 122, 127, 128, 129, 130, 131, 132, 148, 150, 151, 152, 156, 157, 158, 159, 170, 193, 194, 195, 197, 198, 199, 200, 202, 203, 206, 207, 208, 209, 210], "summary": {"covered_lines": 82, "num_statements": 116, "percent_covered": 70.6896551724138, "percent_covered_display": "71", "missing_lines": 34, "excluded_lines": 2}, "missing_lines": [65, 66, 72, 91, 92, 93, 123, 124, 125, 137, 138, 141, 153, 154, 155, 160, 161, 164, 171, 172, 178, 179, 180, 181, 183, 184, 185, 188, 189, 190, 191, 215, 216, 219], "excluded_lines": [108, 109], "functions": {"BackupManager.__init__": {"executed_lines": [51, 52, 53, 54, 55, 56, 57], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BackupManager.create_backup": {"executed_lines": [62, 63, 64, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 89, 90], "summary": {"covered_lines": 17, "num_statements": 23, "percent_covered": 73.91304347826087, "percent_covered_display": "74", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [65, 66, 72, 91, 92, 93], "excluded_lines": []}, "BackupManager._create_additional_backup": {"executed_lines": [97, 98, 99, 101, 102, 103, 104, 105, 106, 107], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [108, 109]}, "BackupManager.restore_latest_backup": {"executed_lines": [115, 116, 122, 127, 128, 129, 130, 131, 132], "summary": {"covered_lines": 9, "num_statements": 15, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [123, 124, 125, 137, 138, 141], "excluded_lines": []}, "BackupManager.restore_from_backup": {"executed_lines": [150, 151, 152, 156, 157, 158, 159], "summary": {"covered_lines": 7, "num_statements": 13, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [153, 154, 155, 160, 161, 164], "excluded_lines": []}, "BackupManager.list_backups": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [171, 172, 178, 179, 180, 181, 183, 184, 185, 188, 189, 190, 191], "excluded_lines": []}, "BackupManager.restore_backup_by_timestamp": {"executed_lines": [194, 195, 197, 198, 199, 200, 202, 203, 206, 207, 208, 209, 210], "summary": {"covered_lines": 13, "num_statements": 16, "percent_covered": 81.25, "percent_covered_display": "81", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [215, 216, 219], "excluded_lines": []}, "": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 23, 24, 27, 30, 31, 39, 41, 61, 95, 114, 148, 170, 193], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"BackupManager": {"executed_lines": [51, 52, 53, 54, 55, 56, 57, 62, 63, 64, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 89, 90, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 115, 116, 122, 127, 128, 129, 130, 131, 132, 150, 151, 152, 156, 157, 158, 159, 194, 195, 197, 198, 199, 200, 202, 203, 206, 207, 208, 209, 210], "summary": {"covered_lines": 63, "num_statements": 97, "percent_covered": 64.94845360824742, "percent_covered_display": "65", "missing_lines": 34, "excluded_lines": 2}, "missing_lines": [65, 66, 72, 91, 92, 93, 123, 124, 125, 137, 138, 141, 153, 154, 155, 160, 161, 164, 171, 172, 178, 179, 180, 181, 183, 184, 185, 188, 189, 190, 191, 215, 216, 219], "excluded_lines": [108, 109]}, "": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 23, 24, 27, 30, 31, 39, 41, 61, 95, 114, 148, 170, 193], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/config_manager.py": {"executed_lines": [1, 3, 5, 6, 7, 9, 11, 13, 14, 16, 18, 21, 24, 25, 27, 29, 30, 31, 32, 34, 43, 44, 45, 71, 72, 73, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 103, 104, 105, 106, 107, 115, 120, 122, 123, 124, 129, 131, 132, 133, 134, 135, 137, 139, 140, 141, 142, 144, 146, 147, 148, 150, 152, 154, 155, 156, 159, 161, 162, 163, 165, 167, 169, 170, 171, 173, 178, 180, 182, 183, 184, 186, 188, 189, 191, 199, 201, 202, 204, 212, 217, 219, 220, 221, 223, 225, 226, 227, 229, 231, 232, 233, 235, 237, 238, 239, 241, 243, 244, 246, 248, 249, 251, 253, 255, 256, 257, 259, 261, 262, 264, 266, 268, 269, 270, 272, 274, 275, 278, 280, 282, 283, 294, 299, 304, 309, 314, 316, 317, 318, 320, 322, 323, 324, 326, 328, 329, 330, 332, 334, 335, 336, 338, 340, 341, 342, 344, 346, 347, 349, 351, 353, 354, 355, 357, 359, 360, 362, 364, 366, 367, 368, 370, 372, 373, 375, 380, 381, 382], "summary": {"covered_lines": 191, "num_statements": 241, "percent_covered": 79.25311203319502, "percent_covered_display": "79", "missing_lines": 50, "excluded_lines": 2}, "missing_lines": [74, 108, 109, 110, 111, 112, 114, 116, 117, 118, 125, 126, 127, 149, 157, 168, 175, 176, 181, 193, 194, 195, 196, 197, 206, 207, 208, 209, 210, 214, 215, 254, 267, 295, 296, 297, 300, 301, 302, 305, 306, 307, 310, 311, 312, 352, 365, 376, 377, 378], "excluded_lines": [18, 19], "functions": {"ConfigManager.__init__": {"executed_lines": [30, 31, 32], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.load_config": {"executed_lines": [43, 44, 45, 71, 72, 73, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 103, 104, 105, 106, 107, 115], "summary": {"covered_lines": 37, "num_statements": 47, "percent_covered": 78.72340425531915, "percent_covered_display": "79", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [74, 108, 109, 110, 111, 112, 114, 116, 117, 118], "excluded_lines": []}, "ConfigManager.save_config": {"executed_lines": [122, 123, 124], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [125, 126, 127], "excluded_lines": []}, "ConfigManager.set_relays": {"executed_lines": [131, 132, 133, 134, 135], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_pin": {"executed_lines": [139, 140, 141, 142], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.verify_pin": {"executed_lines": [146, 147, 148, 150], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [149], "excluded_lines": []}, "ConfigManager.change_pin": {"executed_lines": [154, 155, 156], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [157], "excluded_lines": []}, "ConfigManager.set_password_hash": {"executed_lines": [161, 162, 163], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_inactivity_timeout": {"executed_lines": [167, 169, 170, 171], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [168], "excluded_lines": []}, "ConfigManager.get_inactivity_timeout": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [175, 176], "excluded_lines": []}, "ConfigManager.set_kdf_iterations": {"executed_lines": [180, 182, 183, 184], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [181], "excluded_lines": []}, "ConfigManager.get_kdf_iterations": {"executed_lines": [188, 189], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_kdf_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [193, 194, 195, 196, 197], "excluded_lines": []}, "ConfigManager.get_kdf_mode": {"executed_lines": [201, 202], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_argon2_time_cost": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [206, 207, 208, 209, 210], "excluded_lines": []}, "ConfigManager.get_argon2_time_cost": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [214, 215], "excluded_lines": []}, "ConfigManager.set_additional_backup_path": {"executed_lines": [219, 220, 221], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.get_additional_backup_path": {"executed_lines": [225, 226, 227], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_secret_mode_enabled": {"executed_lines": [231, 232, 233], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_offline_mode": {"executed_lines": [237, 238, 239], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.get_secret_mode_enabled": {"executed_lines": [243, 244], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.get_offline_mode": {"executed_lines": [248, 249], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_clipboard_clear_delay": {"executed_lines": [253, 255, 256, 257], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [254], "excluded_lines": []}, "ConfigManager.get_clipboard_clear_delay": {"executed_lines": [261, 262], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_backup_interval": {"executed_lines": [266, 268, 269, 270], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [267], "excluded_lines": []}, "ConfigManager.get_backup_interval": {"executed_lines": [274, 275], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.get_password_policy": {"executed_lines": [280, 282, 283], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_min_uppercase": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [295, 296, 297], "excluded_lines": []}, "ConfigManager.set_min_lowercase": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [300, 301, 302], "excluded_lines": []}, "ConfigManager.set_min_digits": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [305, 306, 307], "excluded_lines": []}, "ConfigManager.set_min_special": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [310, 311, 312], "excluded_lines": []}, "ConfigManager.set_include_special_chars": {"executed_lines": [316, 317, 318], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_allowed_special_chars": {"executed_lines": [322, 323, 324], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_special_mode": {"executed_lines": [328, 329, 330], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_exclude_ambiguous": {"executed_lines": [334, 335, 336], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_quick_unlock": {"executed_lines": [340, 341, 342], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.get_quick_unlock": {"executed_lines": [346, 347], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_nostr_max_retries": {"executed_lines": [351, 353, 354, 355], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [352], "excluded_lines": []}, "ConfigManager.get_nostr_max_retries": {"executed_lines": [359, 360], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_nostr_retry_delay": {"executed_lines": [364, 366, 367, 368], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [365], "excluded_lines": []}, "ConfigManager.get_nostr_retry_delay": {"executed_lines": [372, 373], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_verbose_timing": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [376, 377, 378], "excluded_lines": []}, "ConfigManager.get_verbose_timing": {"executed_lines": [381, 382], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 9, 11, 13, 14, 16, 18, 21, 24, 25, 27, 29, 34, 120, 129, 137, 144, 152, 159, 165, 173, 178, 186, 191, 199, 204, 212, 217, 223, 229, 235, 241, 246, 251, 259, 264, 272, 278, 294, 299, 304, 309, 314, 320, 326, 332, 338, 344, 349, 357, 362, 370, 375, 380], "summary": {"covered_lines": 55, "num_statements": 55, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [18, 19]}}, "classes": {"ConfigManager": {"executed_lines": [30, 31, 32, 43, 44, 45, 71, 72, 73, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 103, 104, 105, 106, 107, 115, 122, 123, 124, 131, 132, 133, 134, 135, 139, 140, 141, 142, 146, 147, 148, 150, 154, 155, 156, 161, 162, 163, 167, 169, 170, 171, 180, 182, 183, 184, 188, 189, 201, 202, 219, 220, 221, 225, 226, 227, 231, 232, 233, 237, 238, 239, 243, 244, 248, 249, 253, 255, 256, 257, 261, 262, 266, 268, 269, 270, 274, 275, 280, 282, 283, 316, 317, 318, 322, 323, 324, 328, 329, 330, 334, 335, 336, 340, 341, 342, 346, 347, 351, 353, 354, 355, 359, 360, 364, 366, 367, 368, 372, 373, 381, 382], "summary": {"covered_lines": 136, "num_statements": 186, "percent_covered": 73.11827956989248, "percent_covered_display": "73", "missing_lines": 50, "excluded_lines": 0}, "missing_lines": [74, 108, 109, 110, 111, 112, 114, 116, 117, 118, 125, 126, 127, 149, 157, 168, 175, 176, 181, 193, 194, 195, 196, 197, 206, 207, 208, 209, 210, 214, 215, 254, 267, 295, 296, 297, 300, 301, 302, 305, 306, 307, 310, 311, 312, 352, 365, 376, 377, 378], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 9, 11, 13, 14, 16, 18, 21, 24, 25, 27, 29, 34, 120, 129, 137, 144, 152, 159, 165, 173, 178, 186, 191, 199, 204, 212, 217, 223, 229, 235, 241, 246, 251, 259, 264, 272, 278, 294, 299, 304, 309, 314, 320, 326, 332, 338, 344, 349, 357, 362, 370, 375, 380], "summary": {"covered_lines": 55, "num_statements": 55, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [18, 19]}}}, "src/seedpass/core/encryption.py": {"executed_lines": [3, 4, 6, 7, 9, 10, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 35, 38, 40, 41, 42, 45, 46, 48, 49, 52, 53, 56, 57, 62, 71, 72, 74, 75, 79, 80, 82, 83, 85, 94, 95, 97, 99, 105, 106, 107, 108, 110, 111, 112, 117, 131, 133, 135, 136, 137, 138, 139, 144, 145, 146, 147, 152, 153, 154, 155, 156, 157, 158, 161, 162, 163, 166, 167, 168, 171, 181, 182, 183, 184, 185, 188, 192, 193, 198, 199, 200, 206, 211, 212, 213, 214, 215, 218, 219, 220, 221, 222, 223, 225, 228, 234, 237, 238, 239, 247, 266, 267, 268, 269, 271, 275, 276, 277, 279, 281, 282, 283, 285, 286, 289, 291, 292, 293, 295, 297, 298, 299, 300, 303, 311, 312, 313, 316, 317, 318, 319, 320, 321, 322, 325, 330, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 347, 348, 349, 350, 351, 352, 353, 355, 356, 357, 358, 359, 360, 361, 363, 370, 371, 372, 373, 376, 377, 379, 386, 387, 388, 389, 390, 391, 392, 397, 398, 399, 401, 402, 405, 407, 408, 411, 412, 417, 418, 419, 420, 421, 423, 424, 425, 426, 430, 436, 441, 442, 443, 444, 445, 446, 447, 448, 450, 470, 471, 473, 474, 475, 477, 478, 479, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 496, 497, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 512, 515, 516, 517, 518, 521, 527, 528, 560, 562, 563, 564, 565, 568, 569, 570, 571, 572, 575, 576, 579, 580, 581, 582, 589, 590, 591, 592, 593, 594, 595, 603, 609, 610, 611, 612, 613, 614, 619], "summary": {"covered_lines": 285, "num_statements": 343, "percent_covered": 83.09037900874635, "percent_covered_display": "83", "missing_lines": 58, "excluded_lines": 23}, "missing_lines": [76, 86, 87, 91, 109, 113, 114, 115, 140, 141, 172, 173, 176, 240, 241, 301, 315, 375, 395, 414, 427, 428, 429, 437, 438, 439, 481, 529, 530, 531, 535, 541, 542, 543, 566, 583, 584, 596, 597, 601, 615, 616, 617, 620, 621, 622, 623, 625, 626, 627, 628, 630, 631, 632, 633, 634, 635, 636], "excluded_lines": [11, 12, 13, 15, 201, 202, 229, 230, 238, 239, 321, 322, 430, 431, 432, 433, 544, 545, 546, 550, 556, 557, 558], "functions": {"_derive_legacy_key_from_password": {"executed_lines": [40, 41, 42], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "LegacyFormatRequiresMigrationError.__init__": {"executed_lines": [49, 52, 53], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager.__init__": {"executed_lines": [71, 72, 74, 75, 79, 80, 82, 83, 85, 94, 95, 97], "summary": {"covered_lines": 12, "num_statements": 16, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [76, 86, 87, 91], "excluded_lines": []}, "EncryptionManager.encrypt_data": {"executed_lines": [105, 106, 107, 108, 110, 111, 112], "summary": {"covered_lines": 7, "num_statements": 11, "percent_covered": 63.63636363636363, "percent_covered_display": "64", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [109, 113, 114, 115], "excluded_lines": []}, "EncryptionManager.decrypt_data": {"executed_lines": [131, 133, 135, 136, 137, 138, 139, 144, 145, 146, 147, 152, 153, 154, 155, 156, 157, 158, 161, 162, 163, 166, 167, 168, 171, 181, 182, 183, 184, 185, 188, 192, 193, 198, 199, 200], "summary": {"covered_lines": 36, "num_statements": 41, "percent_covered": 87.8048780487805, "percent_covered_display": "88", "missing_lines": 5, "excluded_lines": 2}, "missing_lines": [140, 141, 172, 173, 176], "excluded_lines": [201, 202]}, "EncryptionManager.decrypt_legacy": {"executed_lines": [211, 212, 213, 214, 215, 218, 219, 220, 221, 222, 223, 225, 228, 234, 237, 238, 239], "summary": {"covered_lines": 15, "num_statements": 17, "percent_covered": 88.23529411764706, "percent_covered_display": "88", "missing_lines": 2, "excluded_lines": 4}, "missing_lines": [240, 241], "excluded_lines": [229, 230, 238, 239]}, "EncryptionManager.resolve_relative_path": {"executed_lines": [266, 267, 268, 269], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager.encrypt_parent_seed": {"executed_lines": [275, 276, 277], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager.decrypt_parent_seed": {"executed_lines": [281, 282, 283, 285, 286, 289, 291, 292, 293, 295], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager._serialize": {"executed_lines": [298, 299, 300], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [301], "excluded_lines": []}, "EncryptionManager._deserialize": {"executed_lines": [311, 312, 313, 316, 317, 318, 319, 320, 321, 322, 325], "summary": {"covered_lines": 9, "num_statements": 10, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 1, "excluded_lines": 2}, "missing_lines": [315], "excluded_lines": [321, 322]}, "EncryptionManager.encrypt_and_save_file": {"executed_lines": [333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager.decrypt_file": {"executed_lines": [348, 349, 350, 351, 352, 353], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager.get_file_kdf": {"executed_lines": [356, 357, 358, 359, 360, 361], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager.save_json_data": {"executed_lines": [370, 371, 372, 373, 376, 377], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [375], "excluded_lines": []}, "EncryptionManager.load_json_data": {"executed_lines": [386, 387, 388, 389, 390, 391, 392, 397, 398, 399, 401, 402, 405, 407, 408, 411, 412, 417, 418, 419, 420, 421, 423, 424, 425, 426, 430, 436], "summary": {"covered_lines": 27, "num_statements": 35, "percent_covered": 77.14285714285714, "percent_covered_display": "77", "missing_lines": 8, "excluded_lines": 4}, "missing_lines": [395, 414, 427, 428, 429, 437, 438, 439], "excluded_lines": [430, 431, 432, 433]}, "EncryptionManager.get_encrypted_index": {"executed_lines": [442, 443, 444, 445, 446, 447, 448], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager.decrypt_and_save_index_from_nostr": {"executed_lines": [470, 471, 473, 474, 475, 477, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 512, 515, 516, 517, 518, 521, 527, 528], "summary": {"covered_lines": 25, "num_statements": 32, "percent_covered": 78.125, "percent_covered_display": "78", "missing_lines": 7, "excluded_lines": 7}, "missing_lines": [529, 530, 531, 535, 541, 542, 543], "excluded_lines": [544, 545, 546, 550, 556, 557, 558]}, "EncryptionManager.decrypt_and_save_index_from_nostr._process": {"executed_lines": [478, 479, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 496, 497], "summary": {"covered_lines": 16, "num_statements": 17, "percent_covered": 94.11764705882354, "percent_covered_display": "94", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [481], "excluded_lines": []}, "EncryptionManager.update_checksum": {"executed_lines": [562, 563, 564, 565, 568, 569, 570, 571, 572, 575, 576, 579, 580, 581, 582, 589, 590, 591, 592, 593, 594, 595], "summary": {"covered_lines": 22, "num_statements": 28, "percent_covered": 78.57142857142857, "percent_covered_display": "79", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [566, 583, 584, 596, 597, 601], "excluded_lines": []}, "EncryptionManager.validate_seed": {"executed_lines": [609, 610, 611, 612, 613, 614], "summary": {"covered_lines": 6, "num_statements": 9, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [615, 616, 617], "excluded_lines": []}, "EncryptionManager.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [620, 621, 622, 623, 625, 626, 627, 628, 630, 631, 632, 633, 634, 635, 636], "excluded_lines": []}, "": {"executed_lines": [3, 4, 6, 7, 9, 10, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 35, 38, 45, 46, 48, 56, 57, 62, 99, 117, 206, 247, 271, 279, 297, 303, 330, 347, 355, 363, 379, 441, 450, 560, 603, 619], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 4}, "missing_lines": [], "excluded_lines": [11, 12, 13, 15]}}, "classes": {"LegacyFormatRequiresMigrationError": {"executed_lines": [49, 52, 53], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager": {"executed_lines": [71, 72, 74, 75, 79, 80, 82, 83, 85, 94, 95, 97, 105, 106, 107, 108, 110, 111, 112, 131, 133, 135, 136, 137, 138, 139, 144, 145, 146, 147, 152, 153, 154, 155, 156, 157, 158, 161, 162, 163, 166, 167, 168, 171, 181, 182, 183, 184, 185, 188, 192, 193, 198, 199, 200, 211, 212, 213, 214, 215, 218, 219, 220, 221, 222, 223, 225, 228, 234, 237, 238, 239, 266, 267, 268, 269, 275, 276, 277, 281, 282, 283, 285, 286, 289, 291, 292, 293, 295, 298, 299, 300, 311, 312, 313, 316, 317, 318, 319, 320, 321, 322, 325, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 348, 349, 350, 351, 352, 353, 356, 357, 358, 359, 360, 361, 370, 371, 372, 373, 376, 377, 386, 387, 388, 389, 390, 391, 392, 397, 398, 399, 401, 402, 405, 407, 408, 411, 412, 417, 418, 419, 420, 421, 423, 424, 425, 426, 430, 436, 442, 443, 444, 445, 446, 447, 448, 470, 471, 473, 474, 475, 477, 478, 479, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 496, 497, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 512, 515, 516, 517, 518, 521, 527, 528, 562, 563, 564, 565, 568, 569, 570, 571, 572, 575, 576, 579, 580, 581, 582, 589, 590, 591, 592, 593, 594, 595, 609, 610, 611, 612, 613, 614], "summary": {"covered_lines": 233, "num_statements": 291, "percent_covered": 80.06872852233677, "percent_covered_display": "80", "missing_lines": 58, "excluded_lines": 19}, "missing_lines": [76, 86, 87, 91, 109, 113, 114, 115, 140, 141, 172, 173, 176, 240, 241, 301, 315, 375, 395, 414, 427, 428, 429, 437, 438, 439, 481, 529, 530, 531, 535, 541, 542, 543, 566, 583, 584, 596, 597, 601, 615, 616, 617, 620, 621, 622, 623, 625, 626, 627, 628, 630, 631, 632, 633, 634, 635, 636], "excluded_lines": [201, 202, 229, 230, 238, 239, 321, 322, 430, 431, 432, 433, 544, 545, 546, 550, 556, 557, 558]}, "": {"executed_lines": [3, 4, 6, 7, 9, 10, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 35, 38, 40, 41, 42, 45, 46, 48, 56, 57, 62, 99, 117, 206, 247, 271, 279, 297, 303, 330, 347, 355, 363, 379, 441, 450, 560, 603, 619], "summary": {"covered_lines": 49, "num_statements": 49, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 4}, "missing_lines": [], "excluded_lines": [11, 12, 13, 15]}}}, "src/seedpass/core/entry_management.py": {"executed_lines": [3, 18, 19, 21, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 48, 49, 50, 53, 56, 57, 64, 65, 66, 69, 70, 72, 74, 76, 78, 80, 81, 82, 84, 85, 86, 88, 89, 90, 91, 93, 94, 96, 101, 103, 104, 107, 108, 109, 110, 111, 116, 119, 120, 121, 123, 124, 125, 126, 127, 132, 138, 139, 140, 141, 142, 145, 146, 152, 183, 184, 185, 187, 188, 202, 203, 204, 205, 207, 209, 211, 213, 215, 216, 217, 219, 220, 222, 224, 228, 229, 230, 232, 233, 235, 242, 244, 245, 246, 254, 256, 271, 272, 273, 275, 276, 278, 279, 280, 281, 283, 297, 298, 299, 300, 301, 315, 317, 318, 319, 321, 322, 327, 343, 344, 346, 348, 349, 350, 352, 353, 354, 364, 365, 366, 367, 369, 372, 373, 374, 375, 378, 380, 381, 383, 396, 397, 399, 400, 401, 403, 404, 406, 407, 408, 410, 411, 412, 424, 425, 426, 427, 429, 432, 433, 434, 435, 438, 439, 440, 442, 443, 445, 446, 447, 448, 450, 461, 462, 464, 465, 466, 468, 469, 470, 471, 472, 473, 474, 475, 477, 478, 479, 489, 490, 491, 492, 494, 507, 509, 510, 511, 524, 525, 526, 527, 529, 532, 533, 534, 535, 540, 541, 542, 544, 545, 547, 548, 549, 550, 551, 552, 554, 566, 567, 569, 570, 571, 573, 574, 575, 576, 577, 579, 580, 581, 592, 593, 594, 595, 597, 600, 601, 602, 603, 608, 609, 610, 612, 613, 615, 616, 617, 619, 634, 635, 637, 638, 639, 641, 642, 644, 646, 647, 648, 649, 651, 652, 654, 655, 656, 669, 670, 671, 672, 674, 677, 678, 679, 680, 686, 687, 688, 690, 691, 693, 694, 695, 697, 703, 704, 705, 706, 710, 715, 717, 724, 725, 726, 727, 731, 732, 734, 735, 736, 738, 740, 741, 742, 743, 748, 749, 751, 755, 756, 757, 758, 759, 760, 762, 763, 764, 765, 766, 768, 769, 772, 773, 782, 784, 790, 791, 799, 806, 807, 808, 810, 811, 812, 817, 818, 821, 822, 837, 876, 877, 878, 880, 892, 894, 916, 990, 991, 994, 995, 999, 1000, 1003, 1004, 1005, 1006, 1007, 1008, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1019, 1020, 1021, 1022, 1026, 1027, 1028, 1029, 1030, 1031, 1033, 1036, 1037, 1038, 1040, 1044, 1045, 1046, 1048, 1052, 1053, 1054, 1056, 1057, 1059, 1061, 1063, 1065, 1067, 1069, 1071, 1073, 1078, 1080, 1081, 1085, 1086, 1087, 1089, 1090, 1094, 1095, 1096, 1099, 1101, 1103, 1105, 1107, 1109, 1130, 1131, 1132, 1134, 1135, 1136, 1137, 1138, 1140, 1141, 1142, 1143, 1144, 1147, 1148, 1150, 1153, 1155, 1156, 1158, 1159, 1160, 1164, 1165, 1168, 1169, 1171, 1172, 1173, 1174, 1175, 1176, 1186, 1196, 1197, 1198, 1199, 1202, 1203, 1204, 1205, 1206, 1209, 1215, 1216, 1222, 1227, 1228, 1235, 1236, 1242, 1244, 1252, 1261, 1262, 1264, 1267, 1268, 1272, 1273, 1277, 1278, 1280, 1281, 1284, 1285, 1286, 1288, 1289, 1290, 1291, 1293, 1294, 1305, 1307, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1344, 1348, 1349, 1350, 1351, 1354, 1356, 1358, 1359, 1365, 1407, 1440, 1447, 1448, 1449, 1451, 1452, 1454, 1455, 1456, 1457, 1459, 1462, 1463, 1464, 1466, 1467, 1469, 1470], "summary": {"covered_lines": 535, "num_statements": 667, "percent_covered": 80.20989505247377, "percent_covered_display": "80", "missing_lines": 132, "excluded_lines": 3}, "missing_lines": [92, 95, 100, 102, 105, 106, 112, 113, 114, 128, 129, 130, 144, 147, 148, 149, 150, 206, 208, 210, 212, 214, 218, 237, 238, 239, 240, 277, 282, 323, 324, 325, 376, 436, 538, 606, 684, 709, 711, 712, 713, 714, 730, 733, 746, 761, 767, 771, 792, 793, 794, 797, 824, 825, 826, 828, 829, 832, 835, 881, 884, 890, 1001, 1002, 1034, 1039, 1049, 1050, 1058, 1060, 1062, 1064, 1066, 1068, 1070, 1072, 1074, 1075, 1076, 1151, 1246, 1247, 1248, 1249, 1250, 1265, 1328, 1331, 1338, 1339, 1340, 1361, 1362, 1363, 1371, 1372, 1373, 1374, 1375, 1380, 1382, 1385, 1387, 1388, 1394, 1395, 1397, 1398, 1401, 1415, 1416, 1421, 1422, 1423, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1435, 1436, 1437, 1438, 1458, 1471, 1472, 1473, 1474], "excluded_lines": [22, 23, 25], "functions": {"EntryManager.__init__": {"executed_lines": [64, 65, 66, 69, 70, 72, 74], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.clear_cache": {"executed_lines": [78], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager._load_index": {"executed_lines": [81, 82, 84, 85, 86, 88, 89, 90, 91, 93, 94, 96, 101, 103, 104, 107, 108, 109, 110, 111, 116, 119, 120, 121], "summary": {"covered_lines": 24, "num_statements": 33, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [92, 95, 100, 102, 105, 106, 112, 113, 114], "excluded_lines": []}, "EntryManager._save_index": {"executed_lines": [124, 125, 126, 127], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [128, 129, 130], "excluded_lines": []}, "EntryManager.get_next_index": {"executed_lines": [138, 139, 140, 141, 142, 145, 146], "summary": {"covered_lines": 7, "num_statements": 12, "percent_covered": 58.333333333333336, "percent_covered_display": "58", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [144, 147, 148, 149, 150], "excluded_lines": []}, "EntryManager.add_entry": {"executed_lines": [183, 184, 185, 187, 188, 202, 203, 204, 205, 207, 209, 211, 213, 215, 216, 217, 219, 220, 222, 224, 228, 229, 230, 232, 233, 235], "summary": {"covered_lines": 26, "num_statements": 36, "percent_covered": 72.22222222222223, "percent_covered_display": "72", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [206, 208, 210, 212, 214, 218, 237, 238, 239, 240], "excluded_lines": []}, "EntryManager.get_next_totp_index": {"executed_lines": [244, 245, 246, 254], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.add_totp": {"executed_lines": [271, 272, 273, 275, 276, 278, 279, 280, 281, 283, 297, 298, 299, 300, 301, 315, 317, 318, 319, 321, 322], "summary": {"covered_lines": 21, "num_statements": 26, "percent_covered": 80.76923076923077, "percent_covered_display": "81", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [277, 282, 323, 324, 325], "excluded_lines": []}, "EntryManager.add_ssh_key": {"executed_lines": [343, 344, 346, 348, 349, 350, 352, 353, 354, 364, 365, 366, 367], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.get_ssh_key_pair": {"executed_lines": [372, 373, 374, 375, 378, 380, 381], "summary": {"covered_lines": 7, "num_statements": 8, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [376], "excluded_lines": []}, "EntryManager.add_pgp_key": {"executed_lines": [396, 397, 399, 400, 401, 403, 404, 406, 407, 408, 410, 411, 412, 424, 425, 426, 427], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.get_pgp_key": {"executed_lines": [432, 433, 434, 435, 438, 439, 440, 442, 443, 445, 446, 447, 448], "summary": {"covered_lines": 13, "num_statements": 14, "percent_covered": 92.85714285714286, "percent_covered_display": "93", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [436], "excluded_lines": []}, "EntryManager.add_nostr_key": {"executed_lines": [461, 462, 464, 465, 466, 468, 469, 470, 471, 472, 473, 474, 475, 477, 478, 479, 489, 490, 491, 492], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.add_key_value": {"executed_lines": [507, 509, 510, 511, 524, 525, 526, 527], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.get_nostr_key_pair": {"executed_lines": [532, 533, 534, 535, 540, 541, 542, 544, 545, 547, 548, 549, 550, 551, 552], "summary": {"covered_lines": 15, "num_statements": 16, "percent_covered": 93.75, "percent_covered_display": "94", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [538], "excluded_lines": []}, "EntryManager.add_seed": {"executed_lines": [566, 567, 569, 570, 571, 573, 574, 575, 576, 577, 579, 580, 581, 592, 593, 594, 595], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.get_seed_phrase": {"executed_lines": [600, 601, 602, 603, 608, 609, 610, 612, 613, 615, 616, 617], "summary": {"covered_lines": 12, "num_statements": 13, "percent_covered": 92.3076923076923, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [606], "excluded_lines": []}, "EntryManager.add_managed_account": {"executed_lines": [634, 635, 637, 638, 639, 641, 642, 644, 646, 647, 648, 649, 651, 652, 654, 655, 656, 669, 670, 671, 672], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.get_managed_account_seed": {"executed_lines": [677, 678, 679, 680, 686, 687, 688, 690, 691, 693, 694, 695], "summary": {"covered_lines": 12, "num_statements": 13, "percent_covered": 92.3076923076923, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [684], "excluded_lines": []}, "EntryManager.get_totp_secret": {"executed_lines": [703, 704, 705, 706, 710, 715], "summary": {"covered_lines": 6, "num_statements": 11, "percent_covered": 54.54545454545455, "percent_covered_display": "55", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [709, 711, 712, 713, 714], "excluded_lines": []}, "EntryManager.get_totp_code": {"executed_lines": [724, 725, 726, 727, 731, 732, 734, 735, 736], "summary": {"covered_lines": 9, "num_statements": 11, "percent_covered": 81.81818181818181, "percent_covered_display": "82", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [730, 733], "excluded_lines": []}, "EntryManager.get_totp_time_remaining": {"executed_lines": [740, 741, 742, 743, 748, 749], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [746], "excluded_lines": []}, "EntryManager.export_totp_entries": {"executed_lines": [755, 756, 757, 758, 759, 760, 762, 763, 764, 765, 766, 768, 769, 772, 773, 782], "summary": {"covered_lines": 16, "num_statements": 19, "percent_covered": 84.21052631578948, "percent_covered_display": "84", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [761, 767, 771], "excluded_lines": []}, "EntryManager.get_encrypted_index": {"executed_lines": [790, 791], "summary": {"covered_lines": 2, "num_statements": 6, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [792, 793, 794, 797], "excluded_lines": []}, "EntryManager.retrieve_entry": {"executed_lines": [806, 807, 808, 810, 811, 812, 817, 818, 821, 822], "summary": {"covered_lines": 10, "num_statements": 17, "percent_covered": 58.8235294117647, "percent_covered_display": "59", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [824, 825, 826, 828, 829, 832, 835], "excluded_lines": []}, "EntryManager.modify_entry": {"executed_lines": [876, 877, 878, 880, 892, 894, 916, 990, 991, 994, 995, 999, 1000, 1003, 1004, 1005, 1006, 1007, 1008, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1019, 1020, 1021, 1022, 1026, 1027, 1028, 1029, 1030, 1031, 1033, 1036, 1037, 1038, 1040, 1044, 1045, 1046, 1048, 1052, 1053, 1054, 1056, 1057, 1059, 1061, 1063, 1065, 1067, 1069, 1071, 1073, 1078, 1080, 1081, 1085, 1086, 1087, 1089, 1090, 1094, 1095, 1096, 1099], "summary": {"covered_lines": 70, "num_statements": 90, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [881, 884, 890, 1001, 1002, 1034, 1039, 1049, 1050, 1058, 1060, 1062, 1064, 1066, 1068, 1070, 1072, 1074, 1075, 1076], "excluded_lines": []}, "EntryManager.archive_entry": {"executed_lines": [1103], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.restore_entry": {"executed_lines": [1107], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.list_entries": {"executed_lines": [1130, 1131, 1132, 1134, 1135, 1136, 1137, 1138, 1140, 1153, 1155, 1156, 1158, 1159, 1160, 1164, 1165, 1168, 1169, 1171, 1172, 1173, 1174, 1175, 1176, 1186, 1196, 1197, 1198, 1199, 1202, 1203, 1204, 1205, 1206, 1209, 1215, 1216, 1222, 1227, 1228, 1235, 1236, 1242, 1244], "summary": {"covered_lines": 45, "num_statements": 50, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [1246, 1247, 1248, 1249, 1250], "excluded_lines": []}, "EntryManager.list_entries.sort_key": {"executed_lines": [1141, 1142, 1143, 1144, 1147, 1148, 1150], "summary": {"covered_lines": 7, "num_statements": 8, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1151], "excluded_lines": []}, "EntryManager.search_entries": {"executed_lines": [1261, 1262, 1264, 1267, 1268, 1272, 1273, 1277, 1278, 1280, 1281, 1284, 1285, 1286, 1288, 1289, 1290, 1291, 1293, 1294, 1305], "summary": {"covered_lines": 21, "num_statements": 22, "percent_covered": 95.45454545454545, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1265], "excluded_lines": []}, "EntryManager.delete_entry": {"executed_lines": [1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322], "summary": {"covered_lines": 10, "num_statements": 15, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [1328, 1331, 1338, 1339, 1340], "excluded_lines": []}, "EntryManager.update_checksum": {"executed_lines": [1348, 1349, 1350, 1351, 1354, 1356, 1358, 1359], "summary": {"covered_lines": 8, "num_statements": 11, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1361, 1362, 1363], "excluded_lines": []}, "EntryManager.restore_from_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [1371, 1372, 1373, 1374, 1375, 1380, 1382, 1385, 1387, 1388, 1394, 1395, 1397, 1398, 1401], "excluded_lines": []}, "EntryManager.list_all_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [1415, 1416, 1421, 1422, 1423, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1435, 1436, 1437, 1438], "excluded_lines": []}, "EntryManager.get_entry_summaries": {"executed_lines": [1447, 1448, 1449, 1451, 1452, 1454, 1455, 1456, 1457, 1459, 1462, 1463, 1464, 1466, 1467, 1469, 1470], "summary": {"covered_lines": 17, "num_statements": 22, "percent_covered": 77.27272727272727, "percent_covered_display": "77", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [1458, 1471, 1472, 1473, 1474], "excluded_lines": []}, "": {"executed_lines": [3, 18, 19, 21, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 48, 49, 50, 53, 56, 57, 76, 80, 123, 132, 152, 242, 256, 327, 369, 383, 429, 450, 494, 529, 554, 597, 619, 674, 697, 717, 738, 751, 784, 799, 837, 1101, 1105, 1109, 1252, 1307, 1344, 1365, 1407, 1440], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [22, 23, 25]}}, "classes": {"EntryManager": {"executed_lines": [64, 65, 66, 69, 70, 72, 74, 78, 81, 82, 84, 85, 86, 88, 89, 90, 91, 93, 94, 96, 101, 103, 104, 107, 108, 109, 110, 111, 116, 119, 120, 121, 124, 125, 126, 127, 138, 139, 140, 141, 142, 145, 146, 183, 184, 185, 187, 188, 202, 203, 204, 205, 207, 209, 211, 213, 215, 216, 217, 219, 220, 222, 224, 228, 229, 230, 232, 233, 235, 244, 245, 246, 254, 271, 272, 273, 275, 276, 278, 279, 280, 281, 283, 297, 298, 299, 300, 301, 315, 317, 318, 319, 321, 322, 343, 344, 346, 348, 349, 350, 352, 353, 354, 364, 365, 366, 367, 372, 373, 374, 375, 378, 380, 381, 396, 397, 399, 400, 401, 403, 404, 406, 407, 408, 410, 411, 412, 424, 425, 426, 427, 432, 433, 434, 435, 438, 439, 440, 442, 443, 445, 446, 447, 448, 461, 462, 464, 465, 466, 468, 469, 470, 471, 472, 473, 474, 475, 477, 478, 479, 489, 490, 491, 492, 507, 509, 510, 511, 524, 525, 526, 527, 532, 533, 534, 535, 540, 541, 542, 544, 545, 547, 548, 549, 550, 551, 552, 566, 567, 569, 570, 571, 573, 574, 575, 576, 577, 579, 580, 581, 592, 593, 594, 595, 600, 601, 602, 603, 608, 609, 610, 612, 613, 615, 616, 617, 634, 635, 637, 638, 639, 641, 642, 644, 646, 647, 648, 649, 651, 652, 654, 655, 656, 669, 670, 671, 672, 677, 678, 679, 680, 686, 687, 688, 690, 691, 693, 694, 695, 703, 704, 705, 706, 710, 715, 724, 725, 726, 727, 731, 732, 734, 735, 736, 740, 741, 742, 743, 748, 749, 755, 756, 757, 758, 759, 760, 762, 763, 764, 765, 766, 768, 769, 772, 773, 782, 790, 791, 806, 807, 808, 810, 811, 812, 817, 818, 821, 822, 876, 877, 878, 880, 892, 894, 916, 990, 991, 994, 995, 999, 1000, 1003, 1004, 1005, 1006, 1007, 1008, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1019, 1020, 1021, 1022, 1026, 1027, 1028, 1029, 1030, 1031, 1033, 1036, 1037, 1038, 1040, 1044, 1045, 1046, 1048, 1052, 1053, 1054, 1056, 1057, 1059, 1061, 1063, 1065, 1067, 1069, 1071, 1073, 1078, 1080, 1081, 1085, 1086, 1087, 1089, 1090, 1094, 1095, 1096, 1099, 1103, 1107, 1130, 1131, 1132, 1134, 1135, 1136, 1137, 1138, 1140, 1141, 1142, 1143, 1144, 1147, 1148, 1150, 1153, 1155, 1156, 1158, 1159, 1160, 1164, 1165, 1168, 1169, 1171, 1172, 1173, 1174, 1175, 1176, 1186, 1196, 1197, 1198, 1199, 1202, 1203, 1204, 1205, 1206, 1209, 1215, 1216, 1222, 1227, 1228, 1235, 1236, 1242, 1244, 1261, 1262, 1264, 1267, 1268, 1272, 1273, 1277, 1278, 1280, 1281, 1284, 1285, 1286, 1288, 1289, 1290, 1291, 1293, 1294, 1305, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1348, 1349, 1350, 1351, 1354, 1356, 1358, 1359, 1447, 1448, 1449, 1451, 1452, 1454, 1455, 1456, 1457, 1459, 1462, 1463, 1464, 1466, 1467, 1469, 1470], "summary": {"covered_lines": 478, "num_statements": 610, "percent_covered": 78.36065573770492, "percent_covered_display": "78", "missing_lines": 132, "excluded_lines": 0}, "missing_lines": [92, 95, 100, 102, 105, 106, 112, 113, 114, 128, 129, 130, 144, 147, 148, 149, 150, 206, 208, 210, 212, 214, 218, 237, 238, 239, 240, 277, 282, 323, 324, 325, 376, 436, 538, 606, 684, 709, 711, 712, 713, 714, 730, 733, 746, 761, 767, 771, 792, 793, 794, 797, 824, 825, 826, 828, 829, 832, 835, 881, 884, 890, 1001, 1002, 1034, 1039, 1049, 1050, 1058, 1060, 1062, 1064, 1066, 1068, 1070, 1072, 1074, 1075, 1076, 1151, 1246, 1247, 1248, 1249, 1250, 1265, 1328, 1331, 1338, 1339, 1340, 1361, 1362, 1363, 1371, 1372, 1373, 1374, 1375, 1380, 1382, 1385, 1387, 1388, 1394, 1395, 1397, 1398, 1401, 1415, 1416, 1421, 1422, 1423, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1435, 1436, 1437, 1438, 1458, 1471, 1472, 1473, 1474], "excluded_lines": []}, "": {"executed_lines": [3, 18, 19, 21, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 48, 49, 50, 53, 56, 57, 76, 80, 123, 132, 152, 242, 256, 327, 369, 383, 429, 450, 494, 529, 554, 597, 619, 674, 697, 717, 738, 751, 784, 799, 837, 1101, 1105, 1109, 1252, 1307, 1344, 1365, 1407, 1440], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [22, 23, 25]}}}, "src/seedpass/core/entry_service.py": {"executed_lines": [1, 3, 4, 5, 7, 9, 14, 15, 17, 21, 22, 24, 25, 27, 28, 29, 30, 31, 39, 40, 41, 44, 45, 46, 47, 52, 53, 54, 55, 61, 62, 64, 65, 66, 68, 69, 71, 77, 78, 81, 88, 90, 91, 92, 100, 102, 103, 104, 105, 106, 107, 108, 114, 115, 119, 120, 122, 123, 124, 127, 128, 131, 139, 140, 142, 143, 144, 150, 151, 152, 153, 154, 162, 164, 167, 168, 171, 174, 175, 177, 178, 179, 181, 184, 185, 188, 191, 194, 196, 199, 202, 204, 205, 208, 210, 213, 216, 218, 237], "summary": {"covered_lines": 97, "num_statements": 114, "percent_covered": 85.08771929824562, "percent_covered_display": "85", "missing_lines": 17, "excluded_lines": 8}, "missing_lines": [116, 117, 129, 155, 156, 157, 158, 169, 186, 192, 193, 200, 201, 206, 207, 214, 215], "excluded_lines": [17, 18, 95, 96, 239, 240, 241, 242], "functions": {"EntryService.__init__": {"executed_lines": [25], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.handle_add_password": {"executed_lines": [28, 29, 30, 31, 39, 64, 102, 103, 104, 105, 106, 107, 108, 114, 115, 119, 120, 122, 123, 124, 127, 128, 131, 139, 140, 142, 143, 144, 150, 151, 152, 153, 154, 162, 164, 167, 168, 171, 174, 175, 177, 178, 179, 181, 184, 185, 188, 191, 194, 196, 199, 202, 204, 205, 208, 210, 213, 216, 218, 237], "summary": {"covered_lines": 60, "num_statements": 77, "percent_covered": 77.92207792207792, "percent_covered_display": "78", "missing_lines": 17, "excluded_lines": 4}, "missing_lines": [116, 117, 129, 155, 156, 157, 158, 169, 186, 192, 193, 200, 201, 206, 207, 214, 215], "excluded_lines": [239, 240, 241, 242]}, "EntryService.handle_add_password.prompt_length": {"executed_lines": [40, 41, 44, 45, 46, 47, 52, 53, 54, 55, 61, 62], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.handle_add_password.finalize_entry": {"executed_lines": [65, 66, 68, 69, 71, 77, 78, 81, 88, 90, 91, 92, 100], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [95, 96]}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 14, 15, 17, 21, 22, 24, 27], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [17, 18]}}, "classes": {"EntryService": {"executed_lines": [25, 28, 29, 30, 31, 39, 40, 41, 44, 45, 46, 47, 52, 53, 54, 55, 61, 62, 64, 65, 66, 68, 69, 71, 77, 78, 81, 88, 90, 91, 92, 100, 102, 103, 104, 105, 106, 107, 108, 114, 115, 119, 120, 122, 123, 124, 127, 128, 131, 139, 140, 142, 143, 144, 150, 151, 152, 153, 154, 162, 164, 167, 168, 171, 174, 175, 177, 178, 179, 181, 184, 185, 188, 191, 194, 196, 199, 202, 204, 205, 208, 210, 213, 216, 218, 237], "summary": {"covered_lines": 86, "num_statements": 103, "percent_covered": 83.49514563106796, "percent_covered_display": "83", "missing_lines": 17, "excluded_lines": 6}, "missing_lines": [116, 117, 129, 155, 156, 157, 158, 169, 186, 192, 193, 200, 201, 206, 207, 214, 215], "excluded_lines": [95, 96, 239, 240, 241, 242]}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 14, 15, 17, 21, 22, 24, 27], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [17, 18]}}}, "src/seedpass/core/entry_types.py": {"executed_lines": [2, 4, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 21], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [2, 4, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 21], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"EntryType": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [2, 4, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 21], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/errors.py": {"executed_lines": [1, 11, 12, 15, 16, 18, 19, 22, 23, 30], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"SeedPassError.__init__": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 15, 16, 18, 22, 23, 30], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"SeedPassError": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DecryptionError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 15, 16, 18, 22, 23, 30], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/manager.py": {"executed_lines": [3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 52, 53, 60, 66, 67, 68, 69, 75, 76, 77, 78, 79, 81, 94, 95, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 112, 113, 114, 115, 118, 121, 122, 124, 125, 126, 127, 128, 129, 141, 142, 143, 148, 149, 152, 153, 154, 155, 158, 160, 161, 164, 189, 190, 191, 193, 194, 197, 200, 201, 202, 204, 206, 209, 210, 212, 215, 216, 218, 220, 221, 222, 223, 224, 227, 228, 237, 238, 239, 240, 241, 242, 244, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 277, 278, 279, 280, 281, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 304, 305, 306, 309, 310, 311, 314, 316, 318, 321, 323, 327, 328, 339, 340, 345, 348, 349, 350, 351, 352, 353, 355, 357, 363, 364, 365, 366, 367, 369, 371, 372, 373, 374, 375, 376, 377, 378, 386, 387, 391, 392, 394, 396, 398, 399, 400, 405, 407, 408, 422, 423, 425, 426, 427, 428, 432, 434, 435, 436, 437, 438, 439, 441, 443, 444, 445, 446, 447, 448, 450, 452, 453, 454, 458, 462, 463, 465, 467, 469, 470, 471, 472, 473, 474, 475, 477, 478, 479, 480, 481, 483, 484, 485, 486, 487, 489, 490, 491, 492, 493, 494, 495, 497, 499, 500, 501, 502, 503, 505, 518, 519, 521, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 536, 541, 542, 543, 546, 547, 548, 549, 551, 555, 556, 557, 565, 569, 570, 572, 575, 577, 581, 582, 583, 586, 587, 588, 590, 591, 592, 597, 598, 600, 602, 603, 607, 608, 613, 614, 621, 626, 627, 634, 635, 636, 637, 638, 639, 644, 648, 649, 657, 658, 660, 662, 663, 664, 665, 667, 670, 671, 672, 675, 686, 688, 689, 690, 700, 709, 710, 711, 712, 713, 714, 716, 721, 726, 727, 729, 730, 731, 733, 734, 735, 736, 737, 738, 739, 741, 744, 745, 746, 747, 752, 753, 754, 755, 757, 764, 765, 766, 767, 768, 770, 775, 776, 781, 794, 799, 802, 805, 806, 811, 816, 817, 822, 825, 826, 830, 831, 832, 833, 839, 840, 841, 842, 844, 845, 847, 850, 851, 852, 853, 855, 859, 860, 861, 863, 864, 865, 866, 867, 869, 870, 871, 872, 873, 875, 876, 878, 880, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 894, 895, 896, 897, 898, 900, 901, 987, 988, 993, 995, 1005, 1006, 1007, 1009, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1029, 1032, 1052, 1053, 1054, 1055, 1056, 1058, 1060, 1064, 1065, 1066, 1071, 1077, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1093, 1094, 1095, 1106, 1109, 1115, 1116, 1117, 1118, 1119, 1120, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1133, 1137, 1138, 1139, 1141, 1146, 1147, 1149, 1150, 1152, 1153, 1157, 1158, 1159, 1160, 1169, 1170, 1177, 1178, 1179, 1180, 1182, 1184, 1185, 1186, 1187, 1192, 1193, 1205, 1214, 1217, 1224, 1225, 1226, 1227, 1228, 1233, 1234, 1235, 1238, 1239, 1240, 1241, 1243, 1244, 1246, 1251, 1261, 1262, 1263, 1264, 1265, 1266, 1271, 1278, 1279, 1280, 1281, 1282, 1292, 1293, 1303, 1304, 1305, 1309, 1313, 1318, 1320, 1321, 1323, 1324, 1325, 1326, 1331, 1335, 1336, 1338, 1342, 1347, 1348, 1350, 1351, 1353, 1354, 1358, 1359, 1365, 1369, 1370, 1371, 1372, 1373, 1374, 1376, 1386, 1387, 1389, 1395, 1400, 1402, 1406, 1409, 1413, 1414, 1419, 1420, 1421, 1427, 1428, 1431, 1432, 1433, 1435, 1440, 1441, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1465, 1466, 1469, 1470, 1471, 1472, 1473, 1474, 1485, 1488, 1490, 1491, 1492, 1499, 1500, 1501, 1502, 1503, 1504, 1507, 1508, 1509, 1530, 1532, 1533, 1534, 1535, 1537, 1539, 1541, 1542, 1543, 1544, 1545, 1546, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1594, 1595, 1596, 1597, 1629, 1630, 1631, 1647, 1651, 1652, 1654, 1656, 1657, 1658, 1659, 1660, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1674, 1675, 1676, 1677, 1680, 1681, 1683, 1685, 1687, 1688, 1690, 1693, 1695, 1702, 1703, 1704, 1707, 1708, 1709, 1714, 1715, 1716, 1717, 1719, 1720, 1722, 1724, 1725, 1727, 1728, 1729, 1730, 1731, 1737, 1738, 1739, 1740, 1743, 1744, 1745, 1746, 1748, 1750, 1757, 1760, 1761, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1797, 1798, 1799, 1800, 1802, 1803, 1804, 1805, 1807, 1811, 1813, 1814, 1816, 1824, 1835, 1837, 1840, 1841, 1842, 1843, 1848, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1859, 1861, 1863, 1864, 1866, 1867, 1868, 1869, 1871, 1872, 1875, 1876, 1877, 1878, 1879, 1880, 1887, 1888, 1890, 1891, 1892, 1894, 1895, 1897, 1898, 1899, 1900, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1916, 1917, 1918, 1923, 1924, 1927, 1932, 1933, 1934, 1939, 1949, 1953, 1954, 1955, 1956, 1957, 1962, 1963, 1964, 1965, 1966, 1967, 1973, 1974, 2036, 2037, 2094, 2095, 2164, 2165, 2232, 2233, 2292, 2293, 2374, 2375, 2437, 2439, 2440, 2441, 2444, 2445, 2453, 2455, 2457, 2458, 2459, 2460, 2461, 2462, 2464, 2481, 2483, 2484, 2485, 2486, 2488, 2492, 2493, 2494, 2496, 2497, 2498, 2500, 2501, 2505, 2506, 2507, 2509, 2511, 2513, 2514, 2515, 2522, 2523, 2524, 2525, 2526, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2539, 2541, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2562, 2576, 2577, 2578, 2584, 2587, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2602, 2604, 2606, 2607, 2608, 2609, 2616, 2617, 2618, 2623, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2638, 2644, 2652, 2657, 2662, 2663, 2664, 2665, 2666, 2667, 2680, 2682, 2685, 2687, 2688, 2703, 2704, 2705, 2706, 2713, 2714, 2715, 2716, 2721, 2722, 2724, 2728, 2729, 2730, 2731, 2732, 2733, 2736, 2737, 2738, 2745, 2756, 2758, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2780, 2781, 2782, 2783, 2784, 2785, 2787, 2788, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2803, 2804, 2812, 2813, 2814, 2815, 2819, 2821, 2822, 2823, 2824, 2827, 2828, 2829, 2830, 2833, 2834, 2835, 2836, 2838, 2839, 2841, 2842, 2843, 2852, 2853, 2857, 2859, 2860, 2861, 2862, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2875, 2876, 2878, 2887, 2888, 2889, 2890, 2892, 2893, 2894, 2895, 2896, 2902, 2906, 2908, 2909, 2910, 2911, 2914, 2915, 2916, 2917, 2920, 2921, 2922, 2923, 2925, 2926, 2928, 2929, 2938, 2942, 2944, 2945, 2946, 2947, 2948, 2951, 2952, 2953, 2954, 2963, 2964, 2966, 2967, 2972, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2982, 2983, 2985, 2990, 2999, 3001, 3002, 3029, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3039, 3040, 3041, 3042, 3044, 3049, 3056, 3057, 3060, 3069, 3070, 3071, 3075, 3078, 3079, 3080, 3081, 3082, 3083, 3085, 3091, 3093, 3095, 3096, 3101, 3103, 3104, 3105, 3106, 3113, 3119, 3120, 3121, 3122, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3144, 3145, 3146, 3147, 3148, 3149, 3160, 3163, 3165, 3166, 3168, 3169, 3170, 3177, 3180, 3184, 3186, 3187, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198, 3200, 3201, 3206, 3207, 3208, 3215, 3218, 3221, 3224, 3225, 3228, 3230, 3339, 3403, 3512, 3513, 3514, 3515, 3516, 3518, 3524, 3525, 3526, 3527, 3534, 3541, 3547, 3553, 3560, 3561, 3573, 3580, 3581, 3582, 3594, 3597, 3603, 3615, 3616, 3618, 3621, 3622, 3623, 3632, 3638, 3639, 3641, 3642, 3643, 3650, 3651, 3652, 3653, 3654, 3656, 3657, 3662, 3663, 3664, 3671, 3672, 3673, 3674, 3676, 3677, 3679, 3682, 3684, 3690, 3691, 3692, 3693, 3694, 3696, 3698, 3699, 3702, 3703, 3704, 3705, 3706, 3709, 3715, 3716, 3718, 3719, 3721, 3722, 3723, 3724, 3725, 3726, 3732, 3733, 3735, 3736, 3738, 3739, 3740, 3741, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3753, 3754, 3756, 3757, 3758, 3759, 3762, 3763, 3764, 3765, 3768, 3769, 3770, 3771, 3776, 3777, 3779, 3780, 3782, 3783, 3784, 3785, 3788, 3789, 3791, 3792, 3794, 3795, 3796, 3797, 3798, 3799, 3800, 3802, 3803, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3815, 3816, 3817, 3818, 3819, 3821, 3822, 3824, 3825, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3840, 3846, 3848, 3849, 3850, 3852, 3854, 3855, 3858, 3861, 3863, 3869, 3872, 3873, 3876, 3877, 3878, 3889, 3890, 3892, 3893, 3896, 3899, 3900, 3901, 3902, 3903, 3908, 3909, 3911, 3913, 3916, 3919, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3940, 3941, 3942, 3943, 3946, 3947, 3948, 3953, 3954, 3955, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3978, 3979, 3986, 3987, 3988, 3990, 3991, 3995, 3996, 3997, 4004, 4005, 4006, 4007, 4008, 4012, 4013, 4015, 4016, 4017, 4019, 4025, 4030, 4031, 4059, 4065, 4066, 4067, 4068, 4069, 4079, 4100, 4104, 4105, 4106, 4107, 4108, 4110, 4111, 4112, 4113, 4114, 4115, 4117, 4121, 4122, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4135, 4136, 4141, 4142, 4143, 4145, 4148, 4150, 4154, 4155, 4156, 4161, 4165, 4166, 4167, 4176, 4177, 4189, 4190, 4191, 4198, 4199, 4202, 4209, 4210, 4211, 4212, 4213, 4219, 4220, 4223, 4224, 4230, 4233, 4234, 4235, 4240, 4241, 4243, 4244, 4252, 4253, 4259, 4268, 4269, 4270, 4271, 4302, 4303, 4305, 4306, 4307, 4308, 4315, 4316, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4330, 4331, 4341, 4345, 4348, 4350, 4352, 4363, 4365, 4366, 4367, 4373, 4374, 4386, 4387, 4388, 4395, 4396, 4400, 4406, 4410, 4415, 4418, 4419, 4422, 4423, 4424, 4431, 4432, 4436, 4439, 4440, 4443, 4444, 4446, 4447, 4451, 4454, 4460, 4461, 4462, 4465, 4470, 4480, 4481, 4482, 4483, 4495, 4496, 4497, 4500, 4515, 4526, 4527, 4528, 4529, 4530, 4532, 4537, 4538, 4539, 4540, 4550, 4573, 4575, 4576, 4577, 4581, 4582, 4585, 4587, 4588, 4591, 4593, 4595, 4596, 4597, 4598, 4599, 4602, 4603, 4604, 4606, 4610, 4611, 4621, 4637, 4638, 4639, 4648, 4720], "summary": {"covered_lines": 1679, "num_statements": 2703, "percent_covered": 62.11616722160562, "percent_covered_display": "62", "missing_lines": 1024, "excluded_lines": 32}, "missing_lines": [130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 174, 175, 176, 177, 180, 182, 183, 185, 186, 203, 333, 334, 335, 343, 389, 395, 401, 402, 403, 410, 411, 412, 413, 414, 417, 418, 419, 420, 429, 430, 455, 456, 468, 520, 522, 558, 559, 560, 563, 604, 605, 610, 616, 617, 618, 619, 641, 642, 645, 676, 682, 697, 698, 758, 759, 760, 761, 762, 777, 778, 779, 780, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 800, 803, 818, 819, 820, 827, 828, 829, 834, 835, 836, 837, 848, 879, 906, 907, 908, 911, 912, 915, 916, 917, 923, 927, 928, 929, 934, 936, 937, 938, 939, 941, 942, 943, 946, 947, 948, 951, 956, 960, 961, 962, 963, 964, 965, 966, 967, 970, 975, 976, 977, 978, 980, 981, 982, 983, 984, 985, 1008, 1010, 1025, 1026, 1030, 1061, 1062, 1063, 1067, 1068, 1069, 1075, 1096, 1102, 1110, 1113, 1161, 1162, 1163, 1165, 1166, 1167, 1188, 1189, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1203, 1204, 1206, 1212, 1218, 1221, 1229, 1230, 1248, 1249, 1267, 1268, 1269, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1314, 1315, 1360, 1361, 1362, 1363, 1379, 1380, 1381, 1384, 1390, 1391, 1392, 1393, 1403, 1459, 1460, 1461, 1462, 1463, 1464, 1516, 1523, 1540, 1547, 1548, 1553, 1557, 1604, 1610, 1611, 1616, 1623, 1632, 1633, 1638, 1639, 1642, 1648, 1649, 1663, 1689, 1691, 1700, 1732, 1733, 1734, 1735, 1758, 1762, 1801, 1808, 1809, 1822, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1838, 1844, 1845, 1846, 1873, 1882, 1885, 1914, 1915, 1919, 1922, 1950, 1951, 1968, 1969, 1975, 1976, 1977, 1978, 1979, 1983, 1984, 1985, 1986, 1987, 1988, 1991, 1996, 1997, 2007, 2008, 2009, 2015, 2016, 2017, 2018, 2019, 2023, 2024, 2025, 2026, 2027, 2028, 2030, 2031, 2032, 2033, 2034, 2039, 2040, 2041, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2059, 2062, 2065, 2066, 2068, 2071, 2072, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2088, 2089, 2090, 2091, 2092, 2097, 2098, 2099, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2118, 2119, 2120, 2121, 2122, 2125, 2126, 2127, 2129, 2132, 2133, 2135, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2150, 2151, 2152, 2153, 2154, 2158, 2159, 2160, 2161, 2162, 2167, 2168, 2169, 2176, 2177, 2178, 2179, 2180, 2184, 2185, 2186, 2187, 2192, 2200, 2203, 2204, 2206, 2209, 2210, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2226, 2227, 2228, 2229, 2230, 2235, 2236, 2237, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2255, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2272, 2273, 2274, 2275, 2278, 2279, 2280, 2286, 2287, 2288, 2289, 2290, 2295, 2296, 2297, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, 2337, 2345, 2346, 2348, 2349, 2350, 2351, 2352, 2353, 2360, 2361, 2362, 2368, 2369, 2370, 2371, 2372, 2377, 2378, 2379, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2397, 2400, 2401, 2402, 2403, 2409, 2410, 2411, 2412, 2419, 2420, 2421, 2423, 2424, 2425, 2431, 2432, 2433, 2434, 2435, 2442, 2466, 2467, 2472, 2473, 2474, 2475, 2477, 2478, 2479, 2557, 2558, 2559, 2560, 2561, 2563, 2564, 2565, 2567, 2568, 2569, 2570, 2573, 2574, 2575, 2601, 2619, 2620, 2624, 2625, 2633, 2634, 2635, 2636, 2637, 2639, 2640, 2641, 2642, 2643, 2645, 2646, 2647, 2648, 2649, 2653, 2654, 2655, 2656, 2658, 2659, 2660, 2661, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2677, 2679, 2689, 2690, 2692, 2696, 2697, 2699, 2700, 2701, 2735, 2740, 2772, 2773, 2786, 2789, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 2837, 2840, 2844, 2845, 2874, 2877, 2879, 2880, 2924, 2927, 2930, 2931, 2955, 2956, 2965, 2968, 2981, 2984, 2991, 2992, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3021, 3028, 3038, 3043, 3061, 3062, 3072, 3073, 3074, 3092, 3094, 3150, 3153, 3162, 3181, 3182, 3183, 3188, 3189, 3219, 3220, 3226, 3231, 3232, 3233, 3234, 3235, 3237, 3243, 3244, 3245, 3251, 3255, 3258, 3259, 3260, 3261, 3263, 3267, 3270, 3271, 3272, 3273, 3275, 3279, 3286, 3287, 3288, 3289, 3290, 3291, 3293, 3297, 3299, 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3320, 3323, 3329, 3340, 3341, 3342, 3344, 3350, 3356, 3360, 3367, 3368, 3369, 3370, 3371, 3372, 3374, 3378, 3380, 3387, 3390, 3396, 3407, 3408, 3409, 3410, 3412, 3418, 3424, 3430, 3434, 3435, 3439, 3440, 3444, 3451, 3452, 3453, 3454, 3455, 3456, 3458, 3462, 3464, 3471, 3472, 3473, 3474, 3475, 3476, 3479, 3480, 3481, 3482, 3483, 3487, 3490, 3496, 3504, 3505, 3507, 3562, 3563, 3564, 3565, 3567, 3571, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3626, 3627, 3634, 3635, 3636, 3658, 3659, 3660, 3675, 3683, 3687, 3688, 3689, 3700, 3717, 3720, 3734, 3737, 3752, 3755, 3778, 3781, 3790, 3793, 3801, 3804, 3820, 3823, 3839, 3859, 3860, 3866, 3867, 3879, 3880, 3885, 3886, 3887, 3897, 3898, 3904, 3905, 3906, 3951, 3952, 3977, 3981, 3982, 3983, 3984, 4026, 4027, 4028, 4033, 4034, 4035, 4036, 4037, 4038, 4045, 4046, 4047, 4054, 4055, 4056, 4057, 4071, 4072, 4073, 4074, 4075, 4076, 4077, 4085, 4086, 4087, 4088, 4089, 4092, 4098, 4109, 4120, 4123, 4157, 4158, 4159, 4172, 4173, 4174, 4214, 4215, 4216, 4217, 4236, 4237, 4238, 4239, 4260, 4261, 4267, 4272, 4273, 4274, 4280, 4282, 4283, 4284, 4285, 4286, 4289, 4290, 4291, 4292, 4293, 4296, 4297, 4299, 4300, 4327, 4328, 4329, 4342, 4343, 4353, 4354, 4355, 4358, 4359, 4360, 4361, 4368, 4369, 4370, 4371, 4407, 4411, 4412, 4433, 4434, 4448, 4449, 4466, 4467, 4468, 4485, 4486, 4487, 4488, 4489, 4491, 4492, 4493, 4499, 4501, 4502, 4503, 4509, 4510, 4511, 4512, 4513, 4543, 4544, 4549, 4551, 4553, 4554, 4555, 4556, 4558, 4559, 4564, 4565, 4568, 4569, 4570, 4571, 4578, 4607, 4608, 4624, 4626, 4627, 4628, 4640, 4641, 4644, 4645, 4646, 4650, 4651, 4653, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4674, 4675, 4676, 4679, 4680, 4681, 4682, 4683, 4685, 4686, 4687, 4689, 4692, 4693, 4694, 4695, 4698, 4701, 4702, 4703, 4708, 4709, 4710, 4711, 4712, 4714, 4715, 4716, 4718, 4722, 4723, 4724, 4725, 4727, 4728, 4729, 4730, 4731, 4732, 4738, 4739, 4744, 4745, 4751, 4757, 4758, 4759, 4760], "excluded_lines": [1804, 1805, 1832, 1833, 2221, 2222, 2281, 2282, 2363, 2364, 2426, 2427, 2741, 2742, 2743, 2816, 2817, 2818, 2854, 2855, 2856, 2903, 2904, 2905, 2939, 2940, 2941, 2969, 2970, 2971, 3772, 3773], "functions": {"AuditLogger.__init__": {"executed_lines": [125, 126, 127, 128, 129], "summary": {"covered_lines": 5, "num_statements": 15, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [130, 131, 132, 133, 134, 135, 136, 137, 138, 139], "excluded_lines": []}, "AuditLogger.log": {"executed_lines": [142, 143, 148, 149, 152, 153, 154, 155], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "calculate_profile_id": {"executed_lines": [160, 161], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "restore_backup_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [174, 175, 176, 177, 180, 182, 183, 185, 186], "excluded_lines": []}, "requires_unlocked": {"executed_lines": [200, 201, 206], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "requires_unlocked.wrapper": {"executed_lines": [202, 204], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [203], "excluded_lines": []}, "AuthGuard.__init__": {"executed_lines": [215, 216], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AuthGuard.check_timeout": {"executed_lines": [220, 221, 222, 223, 224], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.__init__": {"executed_lines": [254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 277, 278, 279, 280, 281, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 304, 305, 306, 309, 310, 311, 314, 316, 318, 321, 323], "summary": {"covered_lines": 55, "num_statements": 55, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.get_bip85_entropy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [333, 334, 335], "excluded_lines": []}, "PasswordManager.clear_bip85_cache": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [343], "excluded_lines": []}, "PasswordManager.derive_key_hierarchy": {"executed_lines": [348, 349, 350, 351, 352, 353], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.ensure_key_hierarchy": {"executed_lines": [357, 363, 364, 365, 366, 367], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.ensure_script_checksum": {"executed_lines": [371, 372, 373, 374, 375, 376, 377, 378], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.get_password_prompt": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [389], "excluded_lines": []}, "PasswordManager.parent_seed": {"executed_lines": [400, 405], "summary": {"covered_lines": 2, "num_statements": 5, "percent_covered": 40.0, "percent_covered_display": "40", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [401, 402, 403], "excluded_lines": []}, "PasswordManager.header_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [410, 411, 412, 413, 414, 417, 418, 419, 420], "excluded_lines": []}, "PasswordManager.header_fingerprint_args": {"executed_lines": [425, 426, 427, 428], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [429, 430], "excluded_lines": []}, "PasswordManager.update_activity": {"executed_lines": [434, 435, 436, 437, 438, 439], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.notify": {"executed_lines": [443, 444, 445, 446, 447, 448], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.get_current_notification": {"executed_lines": [452, 453, 454, 458, 462, 463], "summary": {"covered_lines": 6, "num_statements": 8, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [455, 456], "excluded_lines": []}, "PasswordManager.poll_background_errors": {"executed_lines": [467, 469, 470, 471, 472, 473, 474, 475], "summary": {"covered_lines": 8, "num_statements": 9, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [468], "excluded_lines": []}, "PasswordManager.menu_handler": {"executed_lines": [479, 480, 481], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.profile_service": {"executed_lines": [485, 486, 487], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.entry_service": {"executed_lines": [491, 492, 493, 494, 495], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.lock_vault": {"executed_lines": [499, 500, 501, 502, 503], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.unlock_vault": {"executed_lines": [518, 519, 521, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 536, 541, 542, 543, 546, 547, 548, 549], "summary": {"covered_lines": 21, "num_statements": 23, "percent_covered": 91.30434782608695, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [520, 522], "excluded_lines": []}, "PasswordManager.initialize_fingerprint_manager": {"executed_lines": [555, 556, 557], "summary": {"covered_lines": 3, "num_statements": 7, "percent_covered": 42.857142857142854, "percent_covered_display": "43", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [558, 559, 560, 563], "excluded_lines": []}, "PasswordManager.setup_parent_seed": {"executed_lines": [569, 570, 572, 575], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.select_or_add_fingerprint": {"executed_lines": [581, 582, 583, 586, 587, 588, 590, 591, 592, 597, 598, 600, 602, 603, 607, 608, 613, 614], "summary": {"covered_lines": 18, "num_statements": 25, "percent_covered": 72.0, "percent_covered_display": "72", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [604, 605, 610, 616, 617, 618, 619], "excluded_lines": []}, "PasswordManager.add_new_fingerprint": {"executed_lines": [626, 627, 634, 635, 636, 637, 638, 639, 644, 648, 649, 657, 658, 660, 662, 663, 664, 665], "summary": {"covered_lines": 18, "num_statements": 21, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [641, 642, 645], "excluded_lines": []}, "PasswordManager.select_fingerprint": {"executed_lines": [670, 671, 672, 675, 686, 688, 689, 690], "summary": {"covered_lines": 8, "num_statements": 12, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [676, 682, 697, 698], "excluded_lines": []}, "PasswordManager.setup_encryption_manager": {"executed_lines": [709, 710, 711, 712, 713, 714, 716, 721, 726, 727, 729, 730, 731, 733, 734, 735, 736, 737, 738, 739, 741, 744, 745, 746, 747, 752, 753, 754, 755, 757, 764, 765, 766, 767, 768, 770, 775, 776, 781], "summary": {"covered_lines": 39, "num_statements": 59, "percent_covered": 66.10169491525424, "percent_covered_display": "66", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [758, 759, 760, 761, 762, 777, 778, 779, 780, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792], "excluded_lines": []}, "PasswordManager.load_parent_seed": {"executed_lines": [799, 802, 805, 806, 811, 816, 817, 822, 825, 826, 830, 831, 832, 833], "summary": {"covered_lines": 14, "num_statements": 26, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [800, 803, 818, 819, 820, 827, 828, 829, 834, 835, 836, 837], "excluded_lines": []}, "PasswordManager.handle_switch_fingerprint": {"executed_lines": [842], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.load_managed_account": {"executed_lines": [847, 850, 851, 852, 853, 855, 859, 860, 861, 863, 864, 865, 866, 867, 869, 870, 871, 872, 873], "summary": {"covered_lines": 19, "num_statements": 20, "percent_covered": 95.0, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [848], "excluded_lines": []}, "PasswordManager.exit_managed_account": {"executed_lines": [878, 880, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 894, 895, 896, 897, 898], "summary": {"covered_lines": 18, "num_statements": 19, "percent_covered": 94.73684210526316, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [879], "excluded_lines": []}, "PasswordManager.handle_existing_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 44, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 44, "excluded_lines": 0}, "missing_lines": [906, 907, 908, 911, 912, 915, 916, 917, 923, 927, 928, 929, 934, 936, 937, 938, 939, 941, 942, 943, 946, 947, 948, 951, 956, 960, 961, 962, 963, 964, 965, 966, 967, 970, 975, 976, 977, 978, 980, 981, 982, 983, 984, 985], "excluded_lines": []}, "PasswordManager.handle_new_seed_setup": {"executed_lines": [993, 995, 1005, 1006, 1007, 1009, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1029], "summary": {"covered_lines": 20, "num_statements": 25, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [1008, 1010, 1025, 1026, 1030], "excluded_lines": []}, "PasswordManager.setup_existing_seed": {"executed_lines": [1052, 1053, 1054, 1055, 1056, 1058, 1060, 1064, 1065, 1066], "summary": {"covered_lines": 10, "num_statements": 16, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [1061, 1062, 1063, 1067, 1068, 1069], "excluded_lines": []}, "PasswordManager.setup_existing_seed_word_by_word": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1075], "excluded_lines": []}, "PasswordManager._finalize_existing_seed": {"executed_lines": [1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1093, 1094, 1095, 1106, 1109, 1115, 1116, 1117, 1118, 1119, 1120, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1133, 1137, 1138, 1139, 1141, 1146, 1147, 1149, 1150, 1152, 1153, 1157, 1158, 1159, 1160], "summary": {"covered_lines": 43, "num_statements": 53, "percent_covered": 81.13207547169812, "percent_covered_display": "81", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [1096, 1102, 1110, 1113, 1161, 1162, 1163, 1165, 1166, 1167], "excluded_lines": []}, "PasswordManager.generate_new_seed": {"executed_lines": [1177, 1178, 1179, 1180, 1182, 1184, 1185, 1186, 1187, 1192, 1193, 1205, 1214, 1217, 1224, 1225, 1226, 1227, 1228, 1233, 1234, 1235, 1238, 1239, 1240, 1241, 1243, 1244, 1246], "summary": {"covered_lines": 29, "num_statements": 48, "percent_covered": 60.416666666666664, "percent_covered_display": "60", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [1188, 1189, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1203, 1204, 1206, 1212, 1218, 1221, 1229, 1230, 1248, 1249], "excluded_lines": []}, "PasswordManager.validate_bip85_seed": {"executed_lines": [1261, 1262, 1263, 1264, 1265, 1266], "summary": {"covered_lines": 6, "num_statements": 9, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1267, 1268, 1269], "excluded_lines": []}, "PasswordManager.generate_bip85_seed": {"executed_lines": [1278, 1279, 1280, 1281, 1282], "summary": {"covered_lines": 5, "num_statements": 13, "percent_covered": 38.46153846153846, "percent_covered_display": "38", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290], "excluded_lines": []}, "PasswordManager.save_and_encrypt_seed": {"executed_lines": [1303, 1304, 1305, 1309, 1313, 1318, 1320, 1321, 1323, 1324, 1325, 1326, 1331, 1335, 1336, 1338, 1342, 1347, 1348, 1350, 1351, 1353, 1354, 1358, 1359], "summary": {"covered_lines": 25, "num_statements": 31, "percent_covered": 80.64516129032258, "percent_covered_display": "81", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [1314, 1315, 1360, 1361, 1362, 1363], "excluded_lines": []}, "PasswordManager.initialize_bip85": {"executed_lines": [1369, 1370, 1371, 1372, 1373, 1374, 1376, 1386, 1387, 1389], "summary": {"covered_lines": 10, "num_statements": 14, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [1390, 1391, 1392, 1393], "excluded_lines": []}, "PasswordManager.initialize_bip85.cached_derive": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [1379, 1380, 1381, 1384], "excluded_lines": []}, "PasswordManager.initialize_managers": {"executed_lines": [1400, 1402, 1406, 1409, 1413, 1414, 1419, 1420, 1421, 1427, 1428, 1431, 1432, 1433, 1435, 1440, 1441, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1465, 1466, 1469, 1470, 1471, 1472, 1473, 1474, 1485, 1488, 1490, 1491, 1492, 1499, 1500, 1501, 1502, 1503, 1504, 1507, 1508, 1509, 1530, 1532, 1533, 1534, 1535], "summary": {"covered_lines": 53, "num_statements": 62, "percent_covered": 85.48387096774194, "percent_covered_display": "85", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [1403, 1459, 1460, 1461, 1462, 1463, 1464, 1516, 1523], "excluded_lines": []}, "PasswordManager.sync_index_from_nostr_async": {"executed_lines": [1539, 1541, 1542, 1543, 1544, 1545, 1546, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1594, 1595, 1596, 1597, 1629, 1630, 1631, 1647], "summary": {"covered_lines": 42, "num_statements": 59, "percent_covered": 71.1864406779661, "percent_covered_display": "71", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [1540, 1547, 1548, 1553, 1557, 1604, 1610, 1611, 1616, 1623, 1632, 1633, 1638, 1639, 1642, 1648, 1649], "excluded_lines": []}, "PasswordManager.sync_index_from_nostr": {"executed_lines": [1652], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.start_background_sync": {"executed_lines": [1656, 1657, 1658, 1659, 1660, 1665, 1674, 1675, 1676, 1677, 1680, 1681, 1683], "summary": {"covered_lines": 13, "num_statements": 14, "percent_covered": 92.85714285714286, "percent_covered_display": "93", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1663], "excluded_lines": []}, "PasswordManager.start_background_sync._worker": {"executed_lines": [1666, 1667, 1668, 1669, 1670, 1671, 1672], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.cleanup": {"executed_lines": [1687, 1688, 1690], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [1689, 1691], "excluded_lines": []}, "PasswordManager.start_background_relay_check": {"executed_lines": [1695, 1702, 1719, 1720], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1700], "excluded_lines": []}, "PasswordManager.start_background_relay_check._worker": {"executed_lines": [1703, 1704, 1707, 1708, 1709, 1714, 1715, 1716, 1717], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.start_background_vault_sync": {"executed_lines": [1724, 1725, 1727, 1737, 1738, 1739, 1740, 1743, 1744, 1745, 1746, 1748], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.start_background_vault_sync._worker": {"executed_lines": [1728, 1729, 1730, 1731], "summary": {"covered_lines": 4, "num_statements": 8, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [1732, 1733, 1734, 1735], "excluded_lines": []}, "PasswordManager.attempt_initial_sync_async": {"executed_lines": [1757, 1760, 1761, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1797, 1798, 1799, 1800, 1802, 1803, 1804, 1805, 1807, 1811], "summary": {"covered_lines": 32, "num_statements": 37, "percent_covered": 86.48648648648648, "percent_covered_display": "86", "missing_lines": 5, "excluded_lines": 2}, "missing_lines": [1758, 1762, 1801, 1808, 1809], "excluded_lines": [1804, 1805]}, "PasswordManager.attempt_initial_sync": {"executed_lines": [1814], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.sync_index_from_nostr_if_missing": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1822], "excluded_lines": []}, "PasswordManager.sync_index_from_nostr_if_missing_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 2}, "missing_lines": [1825, 1826, 1827, 1828, 1829, 1830, 1831], "excluded_lines": [1832, 1833]}, "PasswordManager.check_nostr_backup_exists": {"executed_lines": [1837, 1840, 1841, 1842, 1843, 1848, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1859], "summary": {"covered_lines": 16, "num_statements": 20, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [1838, 1844, 1845, 1846], "excluded_lines": []}, "PasswordManager.restore_from_nostr_with_guidance": {"executed_lines": [1863, 1864, 1866, 1867, 1868, 1869, 1871, 1872, 1875, 1876, 1877, 1878, 1879, 1880, 1887, 1888], "summary": {"covered_lines": 16, "num_statements": 19, "percent_covered": 84.21052631578948, "percent_covered_display": "84", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1873, 1882, 1885], "excluded_lines": []}, "PasswordManager.handle_add_password": {"executed_lines": [1892], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.handle_add_totp": {"executed_lines": [1897, 1898, 1899, 1900, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1916, 1917, 1918, 1923, 1924, 1927, 1932, 1933, 1934, 1939, 1949, 1953, 1954, 1955, 1956, 1957, 1962, 1963, 1964, 1965, 1966, 1967, 1973, 1974], "summary": {"covered_lines": 35, "num_statements": 76, "percent_covered": 46.05263157894737, "percent_covered_display": "46", "missing_lines": 41, "excluded_lines": 0}, "missing_lines": [1914, 1915, 1919, 1922, 1950, 1951, 1968, 1969, 1975, 1976, 1977, 1978, 1979, 1983, 1984, 1985, 1986, 1987, 1988, 1991, 1996, 1997, 2007, 2008, 2009, 2015, 2016, 2017, 2018, 2019, 2023, 2024, 2025, 2026, 2027, 2028, 2030, 2031, 2032, 2033, 2034], "excluded_lines": []}, "PasswordManager.handle_add_ssh_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 0}, "missing_lines": [2039, 2040, 2041, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2059, 2062, 2065, 2066, 2068, 2071, 2072, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2088, 2089, 2090, 2091, 2092], "excluded_lines": []}, "PasswordManager.handle_add_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 0}, "missing_lines": [2097, 2098, 2099, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2118, 2119, 2120, 2121, 2122, 2125, 2126, 2127, 2129, 2132, 2133, 2135, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2150, 2151, 2152, 2153, 2154, 2158, 2159, 2160, 2161, 2162], "excluded_lines": []}, "PasswordManager.handle_add_pgp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 2}, "missing_lines": [2167, 2168, 2169, 2176, 2177, 2178, 2179, 2180, 2184, 2185, 2186, 2187, 2192, 2200, 2203, 2204, 2206, 2209, 2210, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2226, 2227, 2228, 2229, 2230], "excluded_lines": [2221, 2222]}, "PasswordManager.handle_add_nostr_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 31, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 31, "excluded_lines": 2}, "missing_lines": [2235, 2236, 2237, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2255, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2272, 2273, 2274, 2275, 2278, 2279, 2280, 2286, 2287, 2288, 2289, 2290], "excluded_lines": [2281, 2282]}, "PasswordManager.handle_add_key_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 2}, "missing_lines": [2295, 2296, 2297, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, 2337, 2345, 2346, 2348, 2349, 2350, 2351, 2352, 2353, 2360, 2361, 2362, 2368, 2369, 2370, 2371, 2372], "excluded_lines": [2363, 2364]}, "PasswordManager.handle_add_managed_account": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 30, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 30, "excluded_lines": 2}, "missing_lines": [2377, 2378, 2379, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2397, 2400, 2401, 2402, 2403, 2409, 2410, 2411, 2412, 2419, 2420, 2421, 2423, 2424, 2425, 2431, 2432, 2433, 2434, 2435], "excluded_lines": [2426, 2427]}, "PasswordManager.show_entry_details_by_index": {"executed_lines": [2439, 2440, 2441, 2444, 2445, 2453, 2455, 2457, 2458, 2459, 2460, 2461, 2462], "summary": {"covered_lines": 13, "num_statements": 14, "percent_covered": 92.85714285714286, "percent_covered_display": "93", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [2442], "excluded_lines": []}, "PasswordManager._prompt_toggle_archive": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [2466, 2467, 2472, 2473, 2474, 2475, 2477, 2478, 2479], "excluded_lines": []}, "PasswordManager._entry_type_str": {"executed_lines": [2483, 2484, 2485, 2486], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager._generate_password_for_entry": {"executed_lines": [2492, 2493, 2494, 2496, 2497, 2498, 2500, 2501, 2505, 2506, 2507, 2509], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager._entry_actions_menu": {"executed_lines": [2513, 2514, 2515, 2522, 2523, 2524, 2525, 2526, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2539, 2541, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2562, 2576, 2577, 2578, 2584, 2587, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2602], "summary": {"covered_lines": 45, "num_statements": 61, "percent_covered": 73.77049180327869, "percent_covered_display": "74", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [2557, 2558, 2559, 2560, 2561, 2563, 2564, 2565, 2567, 2568, 2569, 2570, 2573, 2574, 2575, 2601], "excluded_lines": []}, "PasswordManager._entry_edit_menu": {"executed_lines": [2606, 2607, 2608, 2609, 2616, 2617, 2618, 2623, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2638, 2644, 2652, 2657, 2662, 2663, 2664, 2665, 2666, 2667, 2680], "summary": {"covered_lines": 26, "num_statements": 62, "percent_covered": 41.935483870967744, "percent_covered_display": "42", "missing_lines": 36, "excluded_lines": 0}, "missing_lines": [2619, 2620, 2624, 2625, 2633, 2634, 2635, 2636, 2637, 2639, 2640, 2641, 2642, 2643, 2645, 2646, 2647, 2648, 2649, 2653, 2654, 2655, 2656, 2658, 2659, 2660, 2661, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2677, 2679], "excluded_lines": []}, "PasswordManager._entry_qr_menu": {"executed_lines": [2685, 2687, 2688, 2703, 2704, 2705, 2706, 2713, 2714, 2715, 2716, 2721, 2722, 2724, 2728, 2729, 2730, 2731, 2732, 2733, 2736, 2737, 2738], "summary": {"covered_lines": 23, "num_statements": 33, "percent_covered": 69.6969696969697, "percent_covered_display": "70", "missing_lines": 10, "excluded_lines": 3}, "missing_lines": [2689, 2690, 2692, 2696, 2697, 2699, 2700, 2701, 2735, 2740], "excluded_lines": [2741, 2742, 2743]}, "PasswordManager.display_sensitive_entry_info": {"executed_lines": [2756, 2758, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2780, 2781, 2782, 2783, 2784, 2785, 2787, 2788, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2803, 2804, 2812, 2813, 2814, 2815, 2819, 2821, 2822, 2823, 2824, 2827, 2828, 2829, 2830, 2833, 2834, 2835, 2836, 2838, 2839, 2841, 2842, 2843, 2852, 2853, 2857, 2859, 2860, 2861, 2862, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2875, 2876, 2878, 2887, 2888, 2889, 2890, 2892, 2893, 2894, 2895, 2896, 2902, 2906, 2908, 2909, 2910, 2911, 2914, 2915, 2916, 2917, 2920, 2921, 2922, 2923, 2925, 2926, 2928, 2929, 2938, 2942, 2944, 2945, 2946, 2947, 2948, 2951, 2952, 2953, 2954, 2963, 2964, 2966, 2967, 2972, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2982, 2983, 2985, 2990, 2999, 3001, 3002, 3029, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3039, 3040, 3041, 3042, 3044, 3049, 3056, 3057, 3060, 3069, 3070, 3071, 3075, 3078, 3079, 3080, 3081, 3082, 3083, 3085, 3091, 3093, 3095, 3096, 3101, 3103, 3104, 3105, 3106, 3113, 3119, 3120, 3121, 3122, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3144, 3145, 3146, 3147, 3148, 3149, 3160, 3163], "summary": {"covered_lines": 197, "num_statements": 257, "percent_covered": 76.65369649805447, "percent_covered_display": "77", "missing_lines": 60, "excluded_lines": 15}, "missing_lines": [2772, 2773, 2786, 2789, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 2837, 2840, 2844, 2845, 2874, 2877, 2879, 2880, 2924, 2927, 2930, 2931, 2955, 2956, 2965, 2968, 2981, 2984, 2991, 2992, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3021, 3028, 3038, 3043, 3061, 3062, 3072, 3073, 3074, 3092, 3094, 3150, 3153, 3162], "excluded_lines": [2816, 2817, 2818, 2854, 2855, 2856, 2903, 2904, 2905, 2939, 2940, 2941, 2969, 2970, 2971]}, "PasswordManager.handle_retrieve_entry": {"executed_lines": [3168, 3169, 3170, 3177, 3180, 3184, 3186, 3187, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198], "summary": {"covered_lines": 16, "num_statements": 21, "percent_covered": 76.19047619047619, "percent_covered_display": "76", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [3181, 3182, 3183, 3188, 3189], "excluded_lines": []}, "PasswordManager.handle_modify_entry": {"executed_lines": [3206, 3207, 3208, 3215, 3218, 3221, 3224, 3225, 3228, 3230, 3339, 3403, 3512, 3513, 3514, 3515, 3516, 3518, 3524, 3525, 3526, 3527, 3534, 3541, 3547, 3553, 3560, 3561, 3573, 3580, 3581, 3582, 3594, 3597, 3603, 3615, 3616, 3618, 3621, 3622, 3623, 3632], "summary": {"covered_lines": 42, "num_statements": 168, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 126, "excluded_lines": 0}, "missing_lines": [3219, 3220, 3226, 3231, 3232, 3233, 3234, 3235, 3237, 3243, 3244, 3245, 3251, 3255, 3258, 3259, 3260, 3261, 3263, 3267, 3270, 3271, 3272, 3273, 3275, 3279, 3286, 3287, 3288, 3289, 3290, 3291, 3293, 3297, 3299, 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3320, 3323, 3329, 3340, 3341, 3342, 3344, 3350, 3356, 3360, 3367, 3368, 3369, 3370, 3371, 3372, 3374, 3378, 3380, 3387, 3390, 3396, 3407, 3408, 3409, 3410, 3412, 3418, 3424, 3430, 3434, 3435, 3439, 3440, 3444, 3451, 3452, 3453, 3454, 3455, 3456, 3458, 3462, 3464, 3471, 3472, 3473, 3474, 3475, 3476, 3479, 3480, 3481, 3482, 3483, 3487, 3490, 3496, 3504, 3505, 3507, 3562, 3563, 3564, 3565, 3567, 3571, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3626, 3627, 3634, 3635, 3636], "excluded_lines": []}, "PasswordManager.handle_search_entries": {"executed_lines": [3641, 3642, 3643, 3650, 3651, 3652, 3653, 3654, 3656, 3657, 3662, 3663, 3664, 3671, 3672, 3673, 3674, 3676, 3677, 3679, 3682, 3684, 3690, 3691, 3692, 3693, 3694], "summary": {"covered_lines": 27, "num_statements": 35, "percent_covered": 77.14285714285714, "percent_covered_display": "77", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [3658, 3659, 3660, 3675, 3683, 3687, 3688, 3689], "excluded_lines": []}, "PasswordManager.display_entry_details": {"executed_lines": [3698, 3699, 3702, 3703, 3704, 3705, 3706, 3709, 3715, 3716, 3718, 3719, 3721, 3722, 3723, 3724, 3725, 3726, 3732, 3733, 3735, 3736, 3738, 3739, 3740, 3741, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3753, 3754, 3756, 3757, 3758, 3759, 3762, 3763, 3764, 3765, 3768, 3769, 3770, 3771, 3776, 3777, 3779, 3780, 3782, 3783, 3784, 3785, 3788, 3789, 3791, 3792, 3794, 3795, 3796, 3797, 3798, 3799, 3800, 3802, 3803, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3815, 3816, 3817, 3818, 3819, 3821, 3822, 3824, 3825, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3840, 3846], "summary": {"covered_lines": 100, "num_statements": 116, "percent_covered": 86.20689655172414, "percent_covered_display": "86", "missing_lines": 16, "excluded_lines": 2}, "missing_lines": [3700, 3717, 3720, 3734, 3737, 3752, 3755, 3778, 3781, 3790, 3793, 3801, 3804, 3820, 3823, 3839], "excluded_lines": [3772, 3773]}, "PasswordManager.handle_list_entries": {"executed_lines": [3850], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.delete_entry": {"executed_lines": [3854, 3855, 3858, 3861, 3863, 3869, 3872, 3873, 3876, 3877, 3878], "summary": {"covered_lines": 11, "num_statements": 20, "percent_covered": 55.0, "percent_covered_display": "55", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [3859, 3860, 3866, 3867, 3879, 3880, 3885, 3886, 3887], "excluded_lines": []}, "PasswordManager.handle_archive_entry": {"executed_lines": [3892, 3893, 3896, 3899, 3900, 3901, 3902, 3903], "summary": {"covered_lines": 8, "num_statements": 13, "percent_covered": 61.53846153846154, "percent_covered_display": "62", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [3897, 3898, 3904, 3905, 3906], "excluded_lines": []}, "PasswordManager.handle_view_archived_entries": {"executed_lines": [3911, 3913, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3940, 3941, 3942, 3943, 3946, 3947, 3948, 3953, 3954, 3955, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3978, 3979], "summary": {"covered_lines": 42, "num_statements": 49, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [3951, 3952, 3977, 3981, 3982, 3983, 3984], "excluded_lines": []}, "PasswordManager.handle_view_archived_entries._load_archived_entries": {"executed_lines": [3916, 3919], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.handle_display_totp_codes": {"executed_lines": [3988], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.handle_verify_checksum": {"executed_lines": [3995, 3996, 3997, 4004, 4005, 4006, 4007, 4008, 4012, 4013, 4015, 4016, 4017, 4019, 4025], "summary": {"covered_lines": 15, "num_statements": 18, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [4026, 4027, 4028], "excluded_lines": []}, "PasswordManager.handle_update_script_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [4033, 4034, 4035, 4036, 4037, 4038, 4045, 4046, 4047, 4054, 4055, 4056, 4057], "excluded_lines": []}, "PasswordManager.get_encrypted_data": {"executed_lines": [4065, 4066, 4067, 4068, 4069], "summary": {"covered_lines": 5, "num_statements": 12, "percent_covered": 41.666666666666664, "percent_covered_display": "42", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [4071, 4072, 4073, 4074, 4075, 4076, 4077], "excluded_lines": []}, "PasswordManager.decrypt_and_save_index_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [4085, 4086, 4087, 4088, 4089, 4092, 4098], "excluded_lines": []}, "PasswordManager.sync_vault_async": {"executed_lines": [4104, 4105, 4106, 4107, 4108, 4110, 4111, 4112, 4113, 4114, 4115, 4117, 4121, 4122, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4135, 4136, 4141, 4142, 4143], "summary": {"covered_lines": 26, "num_statements": 29, "percent_covered": 89.65517241379311, "percent_covered_display": "90", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [4109, 4120, 4123], "excluded_lines": []}, "PasswordManager.sync_vault": {"executed_lines": [4148], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.backup_database": {"executed_lines": [4154, 4155, 4156], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [4157, 4158, 4159], "excluded_lines": []}, "PasswordManager.restore_database": {"executed_lines": [4165, 4166, 4167], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [4172, 4173, 4174], "excluded_lines": []}, "PasswordManager.handle_export_database": {"executed_lines": [4189, 4190, 4191, 4198, 4199, 4202, 4209, 4210, 4211, 4212, 4213], "summary": {"covered_lines": 11, "num_statements": 15, "percent_covered": 73.33333333333333, "percent_covered_display": "73", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [4214, 4215, 4216, 4217], "excluded_lines": []}, "PasswordManager.handle_import_database": {"executed_lines": [4223, 4224, 4230, 4233, 4234, 4235, 4240, 4241, 4243, 4244, 4252, 4253, 4259, 4268, 4269, 4270, 4271], "summary": {"covered_lines": 17, "num_statements": 42, "percent_covered": 40.476190476190474, "percent_covered_display": "40", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [4236, 4237, 4238, 4239, 4260, 4261, 4267, 4272, 4273, 4274, 4280, 4282, 4283, 4284, 4285, 4286, 4289, 4290, 4291, 4292, 4293, 4296, 4297, 4299, 4300], "excluded_lines": []}, "PasswordManager.handle_export_totp_codes": {"executed_lines": [4305, 4306, 4307, 4308, 4315, 4316, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4330, 4331, 4341, 4345, 4348, 4350, 4352, 4363, 4365, 4366, 4367], "summary": {"covered_lines": 25, "num_statements": 41, "percent_covered": 60.97560975609756, "percent_covered_display": "61", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [4327, 4328, 4329, 4342, 4343, 4353, 4354, 4355, 4358, 4359, 4360, 4361, 4368, 4369, 4370, 4371], "excluded_lines": []}, "PasswordManager.handle_backup_reveal_parent_seed": {"executed_lines": [4386, 4387, 4388, 4395, 4396, 4400, 4406, 4410, 4415, 4418, 4419, 4422, 4423, 4424, 4431, 4432, 4436, 4439, 4440, 4443, 4444, 4446, 4447, 4451, 4454, 4460, 4461, 4462, 4465], "summary": {"covered_lines": 29, "num_statements": 39, "percent_covered": 74.35897435897436, "percent_covered_display": "74", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [4407, 4411, 4412, 4433, 4434, 4448, 4449, 4466, 4467, 4468], "excluded_lines": []}, "PasswordManager.verify_password": {"executed_lines": [4480, 4481, 4482, 4483, 4495, 4496, 4497, 4500], "summary": {"covered_lines": 8, "num_statements": 25, "percent_covered": 32.0, "percent_covered_display": "32", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [4485, 4486, 4487, 4488, 4489, 4491, 4492, 4493, 4499, 4501, 4502, 4503, 4509, 4510, 4511, 4512, 4513], "excluded_lines": []}, "PasswordManager.is_valid_filename": {"executed_lines": [4526, 4527, 4528, 4529, 4530], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.store_hashed_password": {"executed_lines": [4537, 4538, 4539, 4540, 4550], "summary": {"covered_lines": 5, "num_statements": 21, "percent_covered": 23.80952380952381, "percent_covered_display": "24", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [4543, 4544, 4549, 4551, 4553, 4554, 4555, 4556, 4558, 4559, 4564, 4565, 4568, 4569, 4570, 4571], "excluded_lines": []}, "PasswordManager.change_password": {"executed_lines": [4575, 4576, 4577, 4581, 4582, 4585, 4587, 4588, 4591, 4593, 4595, 4596, 4597, 4598, 4599, 4602, 4603, 4604, 4606, 4610, 4611, 4621, 4637, 4638, 4639], "summary": {"covered_lines": 25, "num_statements": 37, "percent_covered": 67.56756756756756, "percent_covered_display": "68", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [4578, 4607, 4608, 4624, 4626, 4627, 4628, 4640, 4641, 4644, 4645, 4646], "excluded_lines": []}, "PasswordManager.get_profile_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 47, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 47, "excluded_lines": 0}, "missing_lines": [4650, 4651, 4653, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4674, 4675, 4676, 4679, 4680, 4681, 4682, 4683, 4685, 4686, 4687, 4689, 4692, 4693, 4694, 4695, 4698, 4701, 4702, 4703, 4708, 4709, 4710, 4711, 4712, 4714, 4715, 4716, 4718], "excluded_lines": []}, "PasswordManager.display_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [4722, 4723, 4724, 4725, 4727, 4728, 4729, 4730, 4731, 4732, 4738, 4739, 4744, 4745, 4751, 4757, 4758, 4759, 4760], "excluded_lines": []}, "": {"executed_lines": [3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 52, 53, 60, 66, 67, 68, 69, 75, 76, 77, 78, 79, 81, 94, 95, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 112, 113, 114, 115, 118, 121, 122, 124, 141, 158, 164, 189, 190, 191, 193, 194, 197, 209, 210, 212, 218, 227, 228, 237, 238, 239, 240, 241, 242, 244, 327, 328, 339, 340, 345, 355, 369, 386, 387, 391, 392, 398, 399, 407, 408, 422, 423, 432, 441, 450, 465, 477, 478, 483, 484, 489, 490, 497, 505, 551, 565, 577, 621, 667, 700, 794, 839, 840, 841, 844, 845, 875, 876, 900, 901, 987, 988, 1032, 1071, 1077, 1169, 1170, 1251, 1271, 1292, 1293, 1365, 1395, 1537, 1651, 1654, 1685, 1693, 1722, 1750, 1813, 1816, 1824, 1835, 1861, 1890, 1891, 1894, 1895, 2036, 2037, 2094, 2095, 2164, 2165, 2232, 2233, 2292, 2293, 2374, 2375, 2437, 2464, 2481, 2488, 2511, 2604, 2682, 2745, 3165, 3166, 3200, 3201, 3638, 3639, 3696, 3848, 3849, 3852, 3889, 3890, 3908, 3909, 3986, 3987, 3990, 3991, 4030, 4031, 4059, 4079, 4100, 4145, 4150, 4161, 4176, 4177, 4219, 4220, 4302, 4303, 4373, 4374, 4470, 4515, 4532, 4573, 4648, 4720], "summary": {"covered_lines": 219, "num_statements": 219, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"AuditLogger": {"executed_lines": [125, 126, 127, 128, 129, 142, 143, 148, 149, 152, 153, 154, 155], "summary": {"covered_lines": 13, "num_statements": 23, "percent_covered": 56.52173913043478, "percent_covered_display": "57", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [130, 131, 132, 133, 134, 135, 136, 137, 138, 139], "excluded_lines": []}, "Notification": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AuthGuard": {"executed_lines": [215, 216, 220, 221, 222, 223, 224], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager": {"executed_lines": [254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 277, 278, 279, 280, 281, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 304, 305, 306, 309, 310, 311, 314, 316, 318, 321, 323, 348, 349, 350, 351, 352, 353, 357, 363, 364, 365, 366, 367, 371, 372, 373, 374, 375, 376, 377, 378, 394, 396, 400, 405, 425, 426, 427, 428, 434, 435, 436, 437, 438, 439, 443, 444, 445, 446, 447, 448, 452, 453, 454, 458, 462, 463, 467, 469, 470, 471, 472, 473, 474, 475, 479, 480, 481, 485, 486, 487, 491, 492, 493, 494, 495, 499, 500, 501, 502, 503, 518, 519, 521, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 536, 541, 542, 543, 546, 547, 548, 549, 555, 556, 557, 569, 570, 572, 575, 581, 582, 583, 586, 587, 588, 590, 591, 592, 597, 598, 600, 602, 603, 607, 608, 613, 614, 626, 627, 634, 635, 636, 637, 638, 639, 644, 648, 649, 657, 658, 660, 662, 663, 664, 665, 670, 671, 672, 675, 686, 688, 689, 690, 709, 710, 711, 712, 713, 714, 716, 721, 726, 727, 729, 730, 731, 733, 734, 735, 736, 737, 738, 739, 741, 744, 745, 746, 747, 752, 753, 754, 755, 757, 764, 765, 766, 767, 768, 770, 775, 776, 781, 799, 802, 805, 806, 811, 816, 817, 822, 825, 826, 830, 831, 832, 833, 842, 847, 850, 851, 852, 853, 855, 859, 860, 861, 863, 864, 865, 866, 867, 869, 870, 871, 872, 873, 878, 880, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 894, 895, 896, 897, 898, 993, 995, 1005, 1006, 1007, 1009, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1029, 1052, 1053, 1054, 1055, 1056, 1058, 1060, 1064, 1065, 1066, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1093, 1094, 1095, 1106, 1109, 1115, 1116, 1117, 1118, 1119, 1120, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1133, 1137, 1138, 1139, 1141, 1146, 1147, 1149, 1150, 1152, 1153, 1157, 1158, 1159, 1160, 1177, 1178, 1179, 1180, 1182, 1184, 1185, 1186, 1187, 1192, 1193, 1205, 1214, 1217, 1224, 1225, 1226, 1227, 1228, 1233, 1234, 1235, 1238, 1239, 1240, 1241, 1243, 1244, 1246, 1261, 1262, 1263, 1264, 1265, 1266, 1278, 1279, 1280, 1281, 1282, 1303, 1304, 1305, 1309, 1313, 1318, 1320, 1321, 1323, 1324, 1325, 1326, 1331, 1335, 1336, 1338, 1342, 1347, 1348, 1350, 1351, 1353, 1354, 1358, 1359, 1369, 1370, 1371, 1372, 1373, 1374, 1376, 1386, 1387, 1389, 1400, 1402, 1406, 1409, 1413, 1414, 1419, 1420, 1421, 1427, 1428, 1431, 1432, 1433, 1435, 1440, 1441, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1465, 1466, 1469, 1470, 1471, 1472, 1473, 1474, 1485, 1488, 1490, 1491, 1492, 1499, 1500, 1501, 1502, 1503, 1504, 1507, 1508, 1509, 1530, 1532, 1533, 1534, 1535, 1539, 1541, 1542, 1543, 1544, 1545, 1546, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1594, 1595, 1596, 1597, 1629, 1630, 1631, 1647, 1652, 1656, 1657, 1658, 1659, 1660, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1674, 1675, 1676, 1677, 1680, 1681, 1683, 1687, 1688, 1690, 1695, 1702, 1703, 1704, 1707, 1708, 1709, 1714, 1715, 1716, 1717, 1719, 1720, 1724, 1725, 1727, 1728, 1729, 1730, 1731, 1737, 1738, 1739, 1740, 1743, 1744, 1745, 1746, 1748, 1757, 1760, 1761, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1797, 1798, 1799, 1800, 1802, 1803, 1804, 1805, 1807, 1811, 1814, 1837, 1840, 1841, 1842, 1843, 1848, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1859, 1863, 1864, 1866, 1867, 1868, 1869, 1871, 1872, 1875, 1876, 1877, 1878, 1879, 1880, 1887, 1888, 1892, 1897, 1898, 1899, 1900, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1916, 1917, 1918, 1923, 1924, 1927, 1932, 1933, 1934, 1939, 1949, 1953, 1954, 1955, 1956, 1957, 1962, 1963, 1964, 1965, 1966, 1967, 1973, 1974, 2439, 2440, 2441, 2444, 2445, 2453, 2455, 2457, 2458, 2459, 2460, 2461, 2462, 2483, 2484, 2485, 2486, 2492, 2493, 2494, 2496, 2497, 2498, 2500, 2501, 2505, 2506, 2507, 2509, 2513, 2514, 2515, 2522, 2523, 2524, 2525, 2526, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2539, 2541, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2562, 2576, 2577, 2578, 2584, 2587, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2602, 2606, 2607, 2608, 2609, 2616, 2617, 2618, 2623, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2638, 2644, 2652, 2657, 2662, 2663, 2664, 2665, 2666, 2667, 2680, 2685, 2687, 2688, 2703, 2704, 2705, 2706, 2713, 2714, 2715, 2716, 2721, 2722, 2724, 2728, 2729, 2730, 2731, 2732, 2733, 2736, 2737, 2738, 2756, 2758, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2780, 2781, 2782, 2783, 2784, 2785, 2787, 2788, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2803, 2804, 2812, 2813, 2814, 2815, 2819, 2821, 2822, 2823, 2824, 2827, 2828, 2829, 2830, 2833, 2834, 2835, 2836, 2838, 2839, 2841, 2842, 2843, 2852, 2853, 2857, 2859, 2860, 2861, 2862, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2875, 2876, 2878, 2887, 2888, 2889, 2890, 2892, 2893, 2894, 2895, 2896, 2902, 2906, 2908, 2909, 2910, 2911, 2914, 2915, 2916, 2917, 2920, 2921, 2922, 2923, 2925, 2926, 2928, 2929, 2938, 2942, 2944, 2945, 2946, 2947, 2948, 2951, 2952, 2953, 2954, 2963, 2964, 2966, 2967, 2972, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2982, 2983, 2985, 2990, 2999, 3001, 3002, 3029, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3039, 3040, 3041, 3042, 3044, 3049, 3056, 3057, 3060, 3069, 3070, 3071, 3075, 3078, 3079, 3080, 3081, 3082, 3083, 3085, 3091, 3093, 3095, 3096, 3101, 3103, 3104, 3105, 3106, 3113, 3119, 3120, 3121, 3122, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3144, 3145, 3146, 3147, 3148, 3149, 3160, 3163, 3168, 3169, 3170, 3177, 3180, 3184, 3186, 3187, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198, 3206, 3207, 3208, 3215, 3218, 3221, 3224, 3225, 3228, 3230, 3339, 3403, 3512, 3513, 3514, 3515, 3516, 3518, 3524, 3525, 3526, 3527, 3534, 3541, 3547, 3553, 3560, 3561, 3573, 3580, 3581, 3582, 3594, 3597, 3603, 3615, 3616, 3618, 3621, 3622, 3623, 3632, 3641, 3642, 3643, 3650, 3651, 3652, 3653, 3654, 3656, 3657, 3662, 3663, 3664, 3671, 3672, 3673, 3674, 3676, 3677, 3679, 3682, 3684, 3690, 3691, 3692, 3693, 3694, 3698, 3699, 3702, 3703, 3704, 3705, 3706, 3709, 3715, 3716, 3718, 3719, 3721, 3722, 3723, 3724, 3725, 3726, 3732, 3733, 3735, 3736, 3738, 3739, 3740, 3741, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3753, 3754, 3756, 3757, 3758, 3759, 3762, 3763, 3764, 3765, 3768, 3769, 3770, 3771, 3776, 3777, 3779, 3780, 3782, 3783, 3784, 3785, 3788, 3789, 3791, 3792, 3794, 3795, 3796, 3797, 3798, 3799, 3800, 3802, 3803, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3815, 3816, 3817, 3818, 3819, 3821, 3822, 3824, 3825, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3840, 3846, 3850, 3854, 3855, 3858, 3861, 3863, 3869, 3872, 3873, 3876, 3877, 3878, 3892, 3893, 3896, 3899, 3900, 3901, 3902, 3903, 3911, 3913, 3916, 3919, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3940, 3941, 3942, 3943, 3946, 3947, 3948, 3953, 3954, 3955, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3978, 3979, 3988, 3995, 3996, 3997, 4004, 4005, 4006, 4007, 4008, 4012, 4013, 4015, 4016, 4017, 4019, 4025, 4065, 4066, 4067, 4068, 4069, 4104, 4105, 4106, 4107, 4108, 4110, 4111, 4112, 4113, 4114, 4115, 4117, 4121, 4122, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4135, 4136, 4141, 4142, 4143, 4148, 4154, 4155, 4156, 4165, 4166, 4167, 4189, 4190, 4191, 4198, 4199, 4202, 4209, 4210, 4211, 4212, 4213, 4223, 4224, 4230, 4233, 4234, 4235, 4240, 4241, 4243, 4244, 4252, 4253, 4259, 4268, 4269, 4270, 4271, 4305, 4306, 4307, 4308, 4315, 4316, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4330, 4331, 4341, 4345, 4348, 4350, 4352, 4363, 4365, 4366, 4367, 4386, 4387, 4388, 4395, 4396, 4400, 4406, 4410, 4415, 4418, 4419, 4422, 4423, 4424, 4431, 4432, 4436, 4439, 4440, 4443, 4444, 4446, 4447, 4451, 4454, 4460, 4461, 4462, 4465, 4480, 4481, 4482, 4483, 4495, 4496, 4497, 4500, 4526, 4527, 4528, 4529, 4530, 4537, 4538, 4539, 4540, 4550, 4575, 4576, 4577, 4581, 4582, 4585, 4587, 4588, 4591, 4593, 4595, 4596, 4597, 4598, 4599, 4602, 4603, 4604, 4606, 4610, 4611, 4621, 4637, 4638, 4639], "summary": {"covered_lines": 1433, "num_statements": 2437, "percent_covered": 58.80180549856381, "percent_covered_display": "59", "missing_lines": 1004, "excluded_lines": 32}, "missing_lines": [333, 334, 335, 343, 389, 395, 401, 402, 403, 410, 411, 412, 413, 414, 417, 418, 419, 420, 429, 430, 455, 456, 468, 520, 522, 558, 559, 560, 563, 604, 605, 610, 616, 617, 618, 619, 641, 642, 645, 676, 682, 697, 698, 758, 759, 760, 761, 762, 777, 778, 779, 780, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 800, 803, 818, 819, 820, 827, 828, 829, 834, 835, 836, 837, 848, 879, 906, 907, 908, 911, 912, 915, 916, 917, 923, 927, 928, 929, 934, 936, 937, 938, 939, 941, 942, 943, 946, 947, 948, 951, 956, 960, 961, 962, 963, 964, 965, 966, 967, 970, 975, 976, 977, 978, 980, 981, 982, 983, 984, 985, 1008, 1010, 1025, 1026, 1030, 1061, 1062, 1063, 1067, 1068, 1069, 1075, 1096, 1102, 1110, 1113, 1161, 1162, 1163, 1165, 1166, 1167, 1188, 1189, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1203, 1204, 1206, 1212, 1218, 1221, 1229, 1230, 1248, 1249, 1267, 1268, 1269, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1314, 1315, 1360, 1361, 1362, 1363, 1379, 1380, 1381, 1384, 1390, 1391, 1392, 1393, 1403, 1459, 1460, 1461, 1462, 1463, 1464, 1516, 1523, 1540, 1547, 1548, 1553, 1557, 1604, 1610, 1611, 1616, 1623, 1632, 1633, 1638, 1639, 1642, 1648, 1649, 1663, 1689, 1691, 1700, 1732, 1733, 1734, 1735, 1758, 1762, 1801, 1808, 1809, 1822, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1838, 1844, 1845, 1846, 1873, 1882, 1885, 1914, 1915, 1919, 1922, 1950, 1951, 1968, 1969, 1975, 1976, 1977, 1978, 1979, 1983, 1984, 1985, 1986, 1987, 1988, 1991, 1996, 1997, 2007, 2008, 2009, 2015, 2016, 2017, 2018, 2019, 2023, 2024, 2025, 2026, 2027, 2028, 2030, 2031, 2032, 2033, 2034, 2039, 2040, 2041, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2059, 2062, 2065, 2066, 2068, 2071, 2072, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2088, 2089, 2090, 2091, 2092, 2097, 2098, 2099, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2118, 2119, 2120, 2121, 2122, 2125, 2126, 2127, 2129, 2132, 2133, 2135, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2150, 2151, 2152, 2153, 2154, 2158, 2159, 2160, 2161, 2162, 2167, 2168, 2169, 2176, 2177, 2178, 2179, 2180, 2184, 2185, 2186, 2187, 2192, 2200, 2203, 2204, 2206, 2209, 2210, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2226, 2227, 2228, 2229, 2230, 2235, 2236, 2237, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2255, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2272, 2273, 2274, 2275, 2278, 2279, 2280, 2286, 2287, 2288, 2289, 2290, 2295, 2296, 2297, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, 2337, 2345, 2346, 2348, 2349, 2350, 2351, 2352, 2353, 2360, 2361, 2362, 2368, 2369, 2370, 2371, 2372, 2377, 2378, 2379, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2397, 2400, 2401, 2402, 2403, 2409, 2410, 2411, 2412, 2419, 2420, 2421, 2423, 2424, 2425, 2431, 2432, 2433, 2434, 2435, 2442, 2466, 2467, 2472, 2473, 2474, 2475, 2477, 2478, 2479, 2557, 2558, 2559, 2560, 2561, 2563, 2564, 2565, 2567, 2568, 2569, 2570, 2573, 2574, 2575, 2601, 2619, 2620, 2624, 2625, 2633, 2634, 2635, 2636, 2637, 2639, 2640, 2641, 2642, 2643, 2645, 2646, 2647, 2648, 2649, 2653, 2654, 2655, 2656, 2658, 2659, 2660, 2661, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2677, 2679, 2689, 2690, 2692, 2696, 2697, 2699, 2700, 2701, 2735, 2740, 2772, 2773, 2786, 2789, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 2837, 2840, 2844, 2845, 2874, 2877, 2879, 2880, 2924, 2927, 2930, 2931, 2955, 2956, 2965, 2968, 2981, 2984, 2991, 2992, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3021, 3028, 3038, 3043, 3061, 3062, 3072, 3073, 3074, 3092, 3094, 3150, 3153, 3162, 3181, 3182, 3183, 3188, 3189, 3219, 3220, 3226, 3231, 3232, 3233, 3234, 3235, 3237, 3243, 3244, 3245, 3251, 3255, 3258, 3259, 3260, 3261, 3263, 3267, 3270, 3271, 3272, 3273, 3275, 3279, 3286, 3287, 3288, 3289, 3290, 3291, 3293, 3297, 3299, 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3320, 3323, 3329, 3340, 3341, 3342, 3344, 3350, 3356, 3360, 3367, 3368, 3369, 3370, 3371, 3372, 3374, 3378, 3380, 3387, 3390, 3396, 3407, 3408, 3409, 3410, 3412, 3418, 3424, 3430, 3434, 3435, 3439, 3440, 3444, 3451, 3452, 3453, 3454, 3455, 3456, 3458, 3462, 3464, 3471, 3472, 3473, 3474, 3475, 3476, 3479, 3480, 3481, 3482, 3483, 3487, 3490, 3496, 3504, 3505, 3507, 3562, 3563, 3564, 3565, 3567, 3571, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3626, 3627, 3634, 3635, 3636, 3658, 3659, 3660, 3675, 3683, 3687, 3688, 3689, 3700, 3717, 3720, 3734, 3737, 3752, 3755, 3778, 3781, 3790, 3793, 3801, 3804, 3820, 3823, 3839, 3859, 3860, 3866, 3867, 3879, 3880, 3885, 3886, 3887, 3897, 3898, 3904, 3905, 3906, 3951, 3952, 3977, 3981, 3982, 3983, 3984, 4026, 4027, 4028, 4033, 4034, 4035, 4036, 4037, 4038, 4045, 4046, 4047, 4054, 4055, 4056, 4057, 4071, 4072, 4073, 4074, 4075, 4076, 4077, 4085, 4086, 4087, 4088, 4089, 4092, 4098, 4109, 4120, 4123, 4157, 4158, 4159, 4172, 4173, 4174, 4214, 4215, 4216, 4217, 4236, 4237, 4238, 4239, 4260, 4261, 4267, 4272, 4273, 4274, 4280, 4282, 4283, 4284, 4285, 4286, 4289, 4290, 4291, 4292, 4293, 4296, 4297, 4299, 4300, 4327, 4328, 4329, 4342, 4343, 4353, 4354, 4355, 4358, 4359, 4360, 4361, 4368, 4369, 4370, 4371, 4407, 4411, 4412, 4433, 4434, 4448, 4449, 4466, 4467, 4468, 4485, 4486, 4487, 4488, 4489, 4491, 4492, 4493, 4499, 4501, 4502, 4503, 4509, 4510, 4511, 4512, 4513, 4543, 4544, 4549, 4551, 4553, 4554, 4555, 4556, 4558, 4559, 4564, 4565, 4568, 4569, 4570, 4571, 4578, 4607, 4608, 4624, 4626, 4627, 4628, 4640, 4641, 4644, 4645, 4646, 4650, 4651, 4653, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4674, 4675, 4676, 4679, 4680, 4681, 4682, 4683, 4685, 4686, 4687, 4689, 4692, 4693, 4694, 4695, 4698, 4701, 4702, 4703, 4708, 4709, 4710, 4711, 4712, 4714, 4715, 4716, 4718, 4722, 4723, 4724, 4725, 4727, 4728, 4729, 4730, 4731, 4732, 4738, 4739, 4744, 4745, 4751, 4757, 4758, 4759, 4760], "excluded_lines": [1804, 1805, 1832, 1833, 2221, 2222, 2281, 2282, 2363, 2364, 2426, 2427, 2741, 2742, 2743, 2816, 2817, 2818, 2854, 2855, 2856, 2903, 2904, 2905, 2939, 2940, 2941, 2969, 2970, 2971, 3772, 3773]}, "": {"executed_lines": [3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 52, 53, 60, 66, 67, 68, 69, 75, 76, 77, 78, 79, 81, 94, 95, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 112, 113, 114, 115, 118, 121, 122, 124, 141, 158, 160, 161, 164, 189, 190, 191, 193, 194, 197, 200, 201, 202, 204, 206, 209, 210, 212, 218, 227, 228, 237, 238, 239, 240, 241, 242, 244, 327, 328, 339, 340, 345, 355, 369, 386, 387, 391, 392, 398, 399, 407, 408, 422, 423, 432, 441, 450, 465, 477, 478, 483, 484, 489, 490, 497, 505, 551, 565, 577, 621, 667, 700, 794, 839, 840, 841, 844, 845, 875, 876, 900, 901, 987, 988, 1032, 1071, 1077, 1169, 1170, 1251, 1271, 1292, 1293, 1365, 1395, 1537, 1651, 1654, 1685, 1693, 1722, 1750, 1813, 1816, 1824, 1835, 1861, 1890, 1891, 1894, 1895, 2036, 2037, 2094, 2095, 2164, 2165, 2232, 2233, 2292, 2293, 2374, 2375, 2437, 2464, 2481, 2488, 2511, 2604, 2682, 2745, 3165, 3166, 3200, 3201, 3638, 3639, 3696, 3848, 3849, 3852, 3889, 3890, 3908, 3909, 3986, 3987, 3990, 3991, 4030, 4031, 4059, 4079, 4100, 4145, 4150, 4161, 4176, 4177, 4219, 4220, 4302, 4303, 4373, 4374, 4470, 4515, 4532, 4573, 4648, 4720], "summary": {"covered_lines": 226, "num_statements": 236, "percent_covered": 95.76271186440678, "percent_covered_display": "96", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [174, 175, 176, 177, 180, 182, 183, 185, 186, 203], "excluded_lines": []}}}, "src/seedpass/core/menu_handler.py": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 16, 20, 21, 23, 24, 26, 27, 29, 30, 31, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 58, 59, 62, 63, 64, 73, 74, 75, 82, 83, 84, 85, 86, 89, 92, 93, 94, 97, 98, 99, 100, 102, 103, 105, 106, 107, 108, 115, 116, 117, 118, 119, 122, 123, 124, 125, 127, 131, 133, 134, 135, 136, 137, 141, 142, 143, 144, 151, 152, 153, 154, 177, 178, 179, 180, 181, 186, 187, 188, 189, 190, 193, 197, 200, 201, 202, 205, 207, 208, 209], "summary": {"covered_lines": 101, "num_statements": 127, "percent_covered": 79.5275590551181, "percent_covered_display": "80", "missing_lines": 26, "excluded_lines": 8}, "missing_lines": [51, 55, 56, 66, 67, 88, 95, 96, 128, 129, 138, 139, 155, 156, 157, 158, 163, 164, 165, 166, 167, 170, 174, 203, 204, 206], "excluded_lines": [16, 17, 98, 99, 100, 210, 211, 212], "functions": {"MenuHandler.__init__": {"executed_lines": [24], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MenuHandler.handle_list_entries": {"executed_lines": [29, 30, 31, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 58, 59, 62, 63, 64, 73, 74, 75, 82, 83, 84, 85, 86, 89, 92, 93, 94, 97, 98, 99, 100], "summary": {"covered_lines": 36, "num_statements": 44, "percent_covered": 81.81818181818181, "percent_covered_display": "82", "missing_lines": 8, "excluded_lines": 3}, "missing_lines": [51, 55, 56, 66, 67, 88, 95, 96], "excluded_lines": [98, 99, 100]}, "MenuHandler.handle_display_totp_codes": {"executed_lines": [105, 106, 107, 108, 115, 116, 117, 118, 119, 122, 123, 124, 125, 127, 131, 133, 134, 135, 136, 137, 141, 142, 143, 144, 151, 152, 153, 154, 177, 178, 179, 180, 181, 186, 187, 188, 189, 190, 193, 197, 200, 201, 202, 205, 207, 208, 209], "summary": {"covered_lines": 47, "num_statements": 65, "percent_covered": 72.3076923076923, "percent_covered_display": "72", "missing_lines": 18, "excluded_lines": 3}, "missing_lines": [128, 129, 138, 139, 155, 156, 157, 158, 163, 164, 165, 166, 167, 170, 174, 203, 204, 206], "excluded_lines": [210, 211, 212]}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 16, 20, 21, 23, 26, 27, 102, 103], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [16, 17]}}, "classes": {"MenuHandler": {"executed_lines": [24, 29, 30, 31, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 58, 59, 62, 63, 64, 73, 74, 75, 82, 83, 84, 85, 86, 89, 92, 93, 94, 97, 98, 99, 100, 105, 106, 107, 108, 115, 116, 117, 118, 119, 122, 123, 124, 125, 127, 131, 133, 134, 135, 136, 137, 141, 142, 143, 144, 151, 152, 153, 154, 177, 178, 179, 180, 181, 186, 187, 188, 189, 190, 193, 197, 200, 201, 202, 205, 207, 208, 209], "summary": {"covered_lines": 84, "num_statements": 110, "percent_covered": 76.36363636363636, "percent_covered_display": "76", "missing_lines": 26, "excluded_lines": 6}, "missing_lines": [51, 55, 56, 66, 67, 88, 95, 96, 128, 129, 138, 139, 155, 156, 157, 158, 163, 164, 165, 166, 167, 170, 174, 203, 204, 206], "excluded_lines": [98, 99, 100, 210, 211, 212]}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 16, 20, 21, 23, 26, 27, 102, 103], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [16, 17]}}}, "src/seedpass/core/migrations.py": {"executed_lines": [1, 3, 5, 7, 10, 15, 16, 17, 19, 22, 23, 25, 26, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46, 47, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 61, 62, 64, 65, 66, 67, 68, 71, 74, 76, 77, 80, 81, 82, 84, 85, 87], "summary": {"covered_lines": 56, "num_statements": 58, "percent_covered": 96.55172413793103, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [78, 83], "excluded_lines": [], "functions": {"migration": {"executed_lines": [15, 19], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "migration.decorator": {"executed_lines": [16, 17], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_v0_to_v1": {"executed_lines": [25, 26], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_v1_to_v2": {"executed_lines": [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_v2_to_v3": {"executed_lines": [49, 50, 51, 52, 53, 54, 55, 56, 57, 58], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_v3_to_v4": {"executed_lines": [64, 65, 66, 67, 68], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "apply_migrations": {"executed_lines": [76, 77, 80, 81, 82, 84, 85, 87], "summary": {"covered_lines": 8, "num_statements": 10, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [78, 83], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 7, 10, 22, 23, 29, 30, 46, 47, 61, 62, 71, 74], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 7, 10, 15, 16, 17, 19, 22, 23, 25, 26, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46, 47, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 61, 62, 64, 65, 66, 67, 68, 71, 74, 76, 77, 80, 81, 82, 84, 85, 87], "summary": {"covered_lines": 56, "num_statements": 58, "percent_covered": 96.55172413793103, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [78, 83], "excluded_lines": []}}}, "src/seedpass/core/password_generation.py": {"executed_lines": [3, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 47, 49, 55, 58, 61, 62, 63, 76, 77, 78, 79, 80, 81, 82, 83, 86, 87, 95, 110, 111, 112, 113, 114, 116, 117, 119, 123, 129, 131, 132, 134, 141, 142, 144, 145, 146, 148, 150, 151, 152, 154, 163, 164, 165, 166, 167, 168, 169, 170, 172, 175, 176, 177, 178, 179, 181, 202, 204, 205, 208, 211, 219, 221, 222, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 236, 238, 239, 240, 243, 246, 247, 248, 249, 250, 251, 252, 259, 260, 263, 264, 268, 270, 271, 272, 273, 275, 291, 292, 293, 294, 295, 297, 298, 299, 300, 301, 303, 306, 307, 308, 309, 311, 316, 317, 318, 319, 322, 323, 325, 327, 328, 329, 332, 333, 334, 335, 336, 337, 339, 340, 341, 342, 343, 344, 346, 347, 348, 349, 350, 351, 353, 354, 355, 356, 357, 358, 361, 362, 363, 364, 366, 367, 369, 370, 371, 372, 376, 377, 378, 379, 380, 381, 382, 383, 384, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 404, 405, 406, 411, 414, 415, 420, 421, 422, 423, 424, 428, 436, 438, 441, 444, 445, 446, 448, 449, 455, 456, 461, 464, 466, 469, 480, 481, 482, 490, 497, 498, 499, 500, 501, 502, 504, 505, 507, 509, 510, 512, 513, 514, 516, 517, 518, 519, 520, 521, 522, 524, 525, 526, 527, 528, 529, 530, 531, 532, 534, 535, 536, 538, 539, 542, 543, 544, 545, 548, 550, 551, 552, 554, 555, 556, 557, 558, 559, 571], "summary": {"covered_lines": 265, "num_statements": 277, "percent_covered": 95.66787003610108, "percent_covered_display": "96", "missing_lines": 12, "excluded_lines": 13}, "missing_lines": [124, 125, 126, 127, 212, 215, 368, 385, 430, 431, 432, 433], "excluded_lines": [39, 40, 41, 42, 43, 45, 516, 517, 518, 519, 520, 521, 522], "functions": {"PasswordGenerator.__init__": {"executed_lines": [110, 111, 112, 113, 114, 116, 117, 119, 123], "summary": {"covered_lines": 9, "num_statements": 13, "percent_covered": 69.23076923076923, "percent_covered_display": "69", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [124, 125, 126, 127], "excluded_lines": []}, "PasswordGenerator._derive_password_entropy": {"executed_lines": [131, 132, 134, 141, 142, 144, 145, 146], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordGenerator._map_entropy_to_chars": {"executed_lines": [150, 151, 152], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordGenerator._fisher_yates_hmac": {"executed_lines": [163, 164, 165, 166, 167, 168, 169, 170], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordGenerator._shuffle_deterministically": {"executed_lines": [175, 176, 177, 178, 179], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordGenerator.generate_password": {"executed_lines": [202, 204, 205, 208, 211, 219, 221, 222, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 236, 238, 239, 240, 243, 246, 247, 248, 249, 250, 251, 252, 259, 260, 263, 264, 268, 270, 271, 272, 273], "summary": {"covered_lines": 39, "num_statements": 41, "percent_covered": 95.1219512195122, "percent_covered_display": "95", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [212, 215], "excluded_lines": []}, "PasswordGenerator._enforce_complexity": {"executed_lines": [291, 292, 293, 294, 295, 297, 298, 299, 300, 301, 303, 306, 307, 308, 309, 311, 316, 317, 318, 319, 322, 323, 325, 332, 333, 334, 335, 336, 337, 339, 340, 341, 342, 343, 344, 346, 347, 348, 349, 350, 351, 353, 354, 355, 356, 357, 358, 361, 362, 363, 364, 366, 367, 369, 370, 371, 372, 376, 377, 378, 379, 380, 381, 382, 383, 384, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 404, 405, 406, 411, 414, 415, 420, 421, 422, 423, 424, 428], "summary": {"covered_lines": 92, "num_statements": 98, "percent_covered": 93.87755102040816, "percent_covered_display": "94", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [368, 385, 430, 431, 432, 433], "excluded_lines": []}, "PasswordGenerator._enforce_complexity.get_dk_value": {"executed_lines": [327, 328, 329], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "derive_ssh_key": {"executed_lines": [438], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "derive_ssh_key_pair": {"executed_lines": [444, 445, 446, 448, 449, 455, 456, 461], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "derive_seed_phrase": {"executed_lines": [466], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "derive_pgp_key": {"executed_lines": [480, 481, 482, 490, 497, 498, 499, 500, 501, 502, 504, 505, 507, 509, 510, 512, 516, 524, 525, 526, 527, 528, 529, 530, 531, 532, 534, 535, 536, 538, 539, 542, 543, 544, 545, 548, 550, 551, 552, 554, 555, 556, 557, 558, 559, 571], "summary": {"covered_lines": 44, "num_statements": 44, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [516]}, "derive_pgp_key.DRNG.__init__": {"executed_lines": [513, 514], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "derive_pgp_key.DRNG.__call__": {"executed_lines": [517, 518, 519, 520, 521, 522], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [517, 518, 519, 520, 521, 522]}, "": {"executed_lines": [3, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 47, 49, 55, 58, 61, 62, 63, 76, 77, 78, 79, 80, 81, 82, 83, 86, 87, 95, 129, 148, 154, 172, 181, 275, 436, 441, 464, 469], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [39, 40, 41, 42, 43, 45]}}, "classes": {"PasswordPolicy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordGenerator": {"executed_lines": [110, 111, 112, 113, 114, 116, 117, 119, 123, 131, 132, 134, 141, 142, 144, 145, 146, 150, 151, 152, 163, 164, 165, 166, 167, 168, 169, 170, 175, 176, 177, 178, 179, 202, 204, 205, 208, 211, 219, 221, 222, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 236, 238, 239, 240, 243, 246, 247, 248, 249, 250, 251, 252, 259, 260, 263, 264, 268, 270, 271, 272, 273, 291, 292, 293, 294, 295, 297, 298, 299, 300, 301, 303, 306, 307, 308, 309, 311, 316, 317, 318, 319, 322, 323, 325, 327, 328, 329, 332, 333, 334, 335, 336, 337, 339, 340, 341, 342, 343, 344, 346, 347, 348, 349, 350, 351, 353, 354, 355, 356, 357, 358, 361, 362, 363, 364, 366, 367, 369, 370, 371, 372, 376, 377, 378, 379, 380, 381, 382, 383, 384, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 404, 405, 406, 411, 414, 415, 420, 421, 422, 423, 424, 428], "summary": {"covered_lines": 167, "num_statements": 179, "percent_covered": 93.29608938547486, "percent_covered_display": "93", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [124, 125, 126, 127, 212, 215, 368, 385, 430, 431, 432, 433], "excluded_lines": []}, "derive_pgp_key.DRNG": {"executed_lines": [513, 514, 517, 518, 519, 520, 521, 522], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [517, 518, 519, 520, 521, 522]}, "": {"executed_lines": [3, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 47, 49, 55, 58, 61, 62, 63, 76, 77, 78, 79, 80, 81, 82, 83, 86, 87, 95, 129, 148, 154, 172, 181, 275, 436, 438, 441, 444, 445, 446, 448, 449, 455, 456, 461, 464, 466, 469, 480, 481, 482, 490, 497, 498, 499, 500, 501, 502, 504, 505, 507, 509, 510, 512, 516, 524, 525, 526, 527, 528, 529, 530, 531, 532, 534, 535, 536, 538, 539, 542, 543, 544, 545, 548, 550, 551, 552, 554, 555, 556, 557, 558, 559, 571], "summary": {"covered_lines": 96, "num_statements": 96, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 7}, "missing_lines": [], "excluded_lines": [39, 40, 41, 42, 43, 45, 516]}}}, "src/seedpass/core/portable_backup.py": {"executed_lines": [2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 22, 23, 24, 26, 28, 29, 32, 33, 35, 36, 39, 42, 45, 62, 63, 64, 65, 66, 68, 69, 71, 72, 77, 78, 79, 80, 81, 83, 84, 85, 87, 89, 99, 100, 101, 102, 104, 121, 124, 132, 133, 136, 137, 140, 141, 143, 144, 149, 150, 151, 152, 153, 154, 158, 160, 161, 162, 164, 165], "summary": {"covered_lines": 71, "num_statements": 84, "percent_covered": 84.52380952380952, "percent_covered_display": "85", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [105, 106, 107, 108, 109, 110, 111, 117, 118, 119, 134, 138, 156], "excluded_lines": [], "functions": {"_derive_export_key": {"executed_lines": [42], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "export_backup": {"executed_lines": [62, 63, 64, 65, 66, 68, 69, 71, 72, 77, 78, 79, 80, 81, 83, 84, 85, 87, 89, 99, 100, 101, 102, 104, 121], "summary": {"covered_lines": 25, "num_statements": 35, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [105, 106, 107, 108, 109, 110, 111, 117, 118, 119], "excluded_lines": []}, "import_backup": {"executed_lines": [132, 133, 136, 137, 140, 141, 143, 144, 149, 150, 151, 152, 153, 154, 158, 160, 161, 162, 164, 165], "summary": {"covered_lines": 20, "num_statements": 23, "percent_covered": 86.95652173913044, "percent_covered_display": "87", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [134, 138, 156], "excluded_lines": []}, "": {"executed_lines": [2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 22, 23, 24, 26, 28, 29, 32, 33, 35, 36, 39, 45, 124], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"PortableMode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 22, 23, 24, 26, 28, 29, 32, 33, 35, 36, 39, 42, 45, 62, 63, 64, 65, 66, 68, 69, 71, 72, 77, 78, 79, 80, 81, 83, 84, 85, 87, 89, 99, 100, 101, 102, 104, 121, 124, 132, 133, 136, 137, 140, 141, 143, 144, 149, 150, 151, 152, 153, 154, 158, 160, 161, 162, 164, 165], "summary": {"covered_lines": 71, "num_statements": 84, "percent_covered": 84.52380952380952, "percent_covered_display": "85", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [105, 106, 107, 108, 109, 110, 111, 117, 118, 119, 134, 138, 156], "excluded_lines": []}}}, "src/seedpass/core/profile_service.py": {"executed_lines": [1, 3, 4, 6, 8, 10, 12, 17, 18, 20, 21, 23, 25, 26, 27, 28, 29, 30, 35, 37, 38, 42, 43, 44, 45, 46, 48, 49, 58, 59, 63, 68, 69, 70, 71, 73, 74, 82, 95, 105], "summary": {"covered_lines": 38, "num_statements": 51, "percent_covered": 74.50980392156863, "percent_covered_display": "75", "missing_lines": 13, "excluded_lines": 7}, "missing_lines": [39, 40, 50, 56, 66, 85, 87, 88, 89, 98, 99, 100, 103], "excluded_lines": [12, 13, 14, 106, 107, 108, 109], "functions": {"ProfileService.__init__": {"executed_lines": [21], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileService.handle_switch_fingerprint": {"executed_lines": [25, 26, 27, 28, 29, 30, 35, 37, 38, 42, 43, 44, 45, 46, 48, 49, 58, 59, 63, 68, 69, 70, 71, 73, 74, 82, 95, 105], "summary": {"covered_lines": 28, "num_statements": 41, "percent_covered": 68.29268292682927, "percent_covered_display": "68", "missing_lines": 13, "excluded_lines": 4}, "missing_lines": [39, 40, 50, 56, 66, 85, 87, 88, 89, 98, 99, 100, 103], "excluded_lines": [106, 107, 108, 109]}, "": {"executed_lines": [1, 3, 4, 6, 8, 10, 12, 17, 18, 20, 23], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [12, 13, 14]}}, "classes": {"ProfileService": {"executed_lines": [21, 25, 26, 27, 28, 29, 30, 35, 37, 38, 42, 43, 44, 45, 46, 48, 49, 58, 59, 63, 68, 69, 70, 71, 73, 74, 82, 95, 105], "summary": {"covered_lines": 29, "num_statements": 42, "percent_covered": 69.04761904761905, "percent_covered_display": "69", "missing_lines": 13, "excluded_lines": 4}, "missing_lines": [39, 40, 50, 56, 66, 85, 87, 88, 89, 98, 99, 100, 103], "excluded_lines": [106, 107, 108, 109]}, "": {"executed_lines": [1, 3, 4, 6, 8, 10, 12, 17, 18, 20, 23], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [12, 13, 14]}}}, "src/seedpass/core/pubsub.py": {"executed_lines": [1, 2, 5, 6, 8, 9, 11, 13, 15, 17, 18, 20, 22, 23, 27], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"PubSub.__init__": {"executed_lines": [9], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PubSub.subscribe": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PubSub.unsubscribe": {"executed_lines": [17, 18], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PubSub.publish": {"executed_lines": [22, 23], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 8, 11, 15, 20, 27], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"PubSub": {"executed_lines": [9, 13, 17, 18, 22, 23], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 8, 11, 15, 20, 27], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/seedqr.py": {"executed_lines": [1, 3, 5, 6, 9, 11, 12, 13, 14], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"encode_seedqr": {"executed_lines": [11, 12, 13, 14], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 9], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 6, 9, 11, 12, 13, 14], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/state_manager.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 12, 13, 15, 17, 18, 19, 21, 22, 23, 31, 32, 33, 34, 43, 44, 47, 48, 49, 50, 51, 52, 53, 55, 56, 57, 58, 59, 60, 61, 63, 64, 65, 67, 68, 69, 70, 73, 74, 76, 77, 78, 79, 81, 82, 83, 85, 86, 87, 88, 90, 92, 93, 94], "summary": {"covered_lines": 59, "num_statements": 65, "percent_covered": 90.76923076923077, "percent_covered_display": "91", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [35, 45, 46, 80, 89, 91], "excluded_lines": [], "functions": {"StateManager.__init__": {"executed_lines": [18, 19], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "StateManager._load": {"executed_lines": [22, 23, 31, 32, 33, 34, 43, 44, 47, 48, 49, 50, 51, 52, 53], "summary": {"covered_lines": 15, "num_statements": 18, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [35, 45, 46], "excluded_lines": []}, "StateManager._save": {"executed_lines": [56, 57, 58, 59, 60, 61], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "StateManager.state": {"executed_lines": [65], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "StateManager.update_state": {"executed_lines": [68, 69, 70], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "StateManager.list_relays": {"executed_lines": [74], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "StateManager.add_relay": {"executed_lines": [77, 78, 79, 81, 82, 83], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [80], "excluded_lines": []}, "StateManager.remove_relay": {"executed_lines": [86, 87, 88, 90, 92, 93, 94], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [89, 91], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 12, 13, 15, 17, 21, 55, 63, 64, 67, 73, 76, 85], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"StateManager": {"executed_lines": [18, 19, 22, 23, 31, 32, 33, 34, 43, 44, 47, 48, 49, 50, 51, 52, 53, 56, 57, 58, 59, 60, 61, 65, 68, 69, 70, 74, 77, 78, 79, 81, 82, 83, 86, 87, 88, 90, 92, 93, 94], "summary": {"covered_lines": 41, "num_statements": 47, "percent_covered": 87.23404255319149, "percent_covered_display": "87", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [35, 45, 46, 80, 89, 91], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 12, 13, 15, 17, 21, 55, 63, 64, 67, 73, 76, 85], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/stats_manager.py": {"executed_lines": [1, 3, 6, 7, 9, 10, 12, 18, 20], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [14, 15, 16], "excluded_lines": [], "functions": {"StatsManager.__init__": {"executed_lines": [10], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "StatsManager.display_stats_once": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [14, 15, 16], "excluded_lines": []}, "StatsManager.reset": {"executed_lines": [20], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 9, 12, 18], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"StatsManager": {"executed_lines": [10, 20], "summary": {"covered_lines": 2, "num_statements": 5, "percent_covered": 40.0, "percent_covered_display": "40", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [14, 15, 16], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 9, 12, 18], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/totp.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 20, 22, 25, 26, 28, 29, 31, 33, 34, 38, 39, 40, 41, 42, 44, 45, 47, 48, 50, 51, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 65, 66, 70, 71, 73, 74, 76, 77, 78, 80, 81, 83, 84, 85, 86, 94, 95, 97, 98, 100, 101, 102, 103], "summary": {"covered_lines": 64, "num_statements": 71, "percent_covered": 90.14084507042253, "percent_covered_display": "90", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [87, 88, 89, 90, 91, 92, 93], "excluded_lines": [], "functions": {"random_totp_secret": {"executed_lines": [22], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TotpManager.derive_secret": {"executed_lines": [31], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TotpManager.current_code": {"executed_lines": [38, 39, 40, 41, 42], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TotpManager.current_code_from_secret": {"executed_lines": [47, 48], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TotpManager.parse_otpauth": {"executed_lines": [53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TotpManager.make_otpauth_uri": {"executed_lines": [70, 71], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TotpManager.time_remaining": {"executed_lines": [76, 77, 78], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TotpManager.print_progress_bar": {"executed_lines": [83, 84, 85, 86, 94, 95], "summary": {"covered_lines": 6, "num_statements": 13, "percent_covered": 46.15384615384615, "percent_covered_display": "46", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [87, 88, 89, 90, 91, 92, 93], "excluded_lines": []}, "TotpManager.print_qr_code": {"executed_lines": [100, 101, 102, 103], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 20, 25, 26, 28, 29, 33, 34, 44, 45, 50, 51, 65, 66, 73, 74, 80, 81, 97, 98], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"TotpManager": {"executed_lines": [31, 38, 39, 40, 41, 42, 47, 48, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 70, 71, 76, 77, 78, 83, 84, 85, 86, 94, 95, 100, 101, 102, 103], "summary": {"covered_lines": 34, "num_statements": 41, "percent_covered": 82.92682926829268, "percent_covered_display": "83", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [87, 88, 89, 90, 91, 92, 93], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 20, 22, 25, 26, 28, 29, 33, 34, 44, 45, 50, 51, 65, 66, 73, 74, 80, 81, 97, 98], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/vault.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 17, 18, 21, 22, 24, 25, 27, 32, 33, 34, 35, 36, 38, 40, 42, 43, 48, 63, 64, 65, 66, 67, 68, 69, 74, 75, 77, 80, 81, 82, 83, 84, 86, 87, 88, 93, 94, 95, 98, 99, 102, 103, 110, 111, 114, 117, 118, 124, 127, 128, 129, 130, 136, 142, 143, 144, 145, 146, 147, 152, 155, 156, 157, 160, 161, 164, 165, 168, 169, 172, 173, 174, 175, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 191, 192, 194, 196, 197, 198, 201, 203, 204, 205, 206, 209, 232, 235, 236, 237, 239, 241, 245, 247, 249, 264, 267, 270, 271, 272, 275, 277, 279, 281], "summary": {"covered_lines": 119, "num_statements": 140, "percent_covered": 85.0, "percent_covered_display": "85", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [96, 97, 100, 149, 163, 210, 211, 212, 213, 216, 217, 218, 219, 220, 221, 224, 225, 226, 227, 229, 230], "excluded_lines": [], "functions": {"Vault.__init__": {"executed_lines": [32, 33, 34, 35, 36], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Vault.set_encryption_manager": {"executed_lines": [40], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Vault._hkdf_kdf": {"executed_lines": [43], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Vault.load_index": {"executed_lines": [63, 64, 65, 66, 67, 68, 69, 74, 75, 77, 80, 81, 82, 83, 84, 86, 87, 88, 93, 94, 95, 98, 99, 102, 103, 110, 111, 114, 117, 118, 124, 127, 128, 129, 130, 136, 142, 143, 144, 145, 146, 147, 152, 155, 156, 157, 160, 161, 164, 165, 168, 169, 172, 173, 174, 175, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 191, 192, 194, 196, 197, 198, 201, 203, 204, 205, 206, 209, 232, 235, 236, 237], "summary": {"covered_lines": 82, "num_statements": 103, "percent_covered": 79.6116504854369, "percent_covered_display": "80", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [96, 97, 100, 149, 163, 210, 211, 212, 213, 216, 217, 218, 219, 220, 221, 224, 225, 226, 227, 229, 230], "excluded_lines": []}, "Vault.save_index": {"executed_lines": [241], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Vault.get_encrypted_index": {"executed_lines": [247], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Vault.decrypt_and_save_index_from_nostr": {"executed_lines": [264, 267, 270, 271, 272], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Vault.load_config": {"executed_lines": [277], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Vault.save_config": {"executed_lines": [281], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 17, 18, 21, 22, 24, 25, 27, 38, 42, 48, 239, 245, 249, 275, 279], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"Vault": {"executed_lines": [32, 33, 34, 35, 36, 40, 43, 63, 64, 65, 66, 67, 68, 69, 74, 75, 77, 80, 81, 82, 83, 84, 86, 87, 88, 93, 94, 95, 98, 99, 102, 103, 110, 111, 114, 117, 118, 124, 127, 128, 129, 130, 136, 142, 143, 144, 145, 146, 147, 152, 155, 156, 157, 160, 161, 164, 165, 168, 169, 172, 173, 174, 175, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 191, 192, 194, 196, 197, 198, 201, 203, 204, 205, 206, 209, 232, 235, 236, 237, 241, 247, 264, 267, 270, 271, 272, 277, 281], "summary": {"covered_lines": 98, "num_statements": 119, "percent_covered": 82.3529411764706, "percent_covered_display": "82", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [96, 97, 100, 149, 163, 210, 211, 212, 213, 216, 217, 218, 219, 220, 221, 224, 225, 226, 227, 229, 230], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 17, 18, 21, 22, 24, 25, 27, 38, 42, 48, 239, 245, 249, 275, 279], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/errors.py": {"executed_lines": [1, 3, 6, 7, 9, 10, 13], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"VaultLockedError.__init__": {"executed_lines": [10], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 9, 13], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"VaultLockedError": {"executed_lines": [10], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 9, 13], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass_gui/__init__.py": {"executed_lines": [1, 3, 6, 11], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [8], "excluded_lines": [], "functions": {"main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [8], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 11], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 6, 11], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [8], "excluded_lines": []}}}, "src/seedpass_gui/__main__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1, 3, 4], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1, 3, 4], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1, 3, 4], "excluded_lines": []}}}, "src/seedpass_gui/app.py": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 21, 24, 25, 27, 33, 36, 37, 38, 40, 41, 42, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 60, 66, 67, 68, 71, 72, 74, 81, 84, 85, 86, 87, 88, 89, 90, 91, 93, 94, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 115, 117, 118, 119, 120, 121, 123, 125, 126, 127, 150, 154, 161, 165, 169, 173, 176, 177, 179, 182, 183, 185, 186, 187, 189, 194, 195, 196, 197, 198, 199, 203, 204, 206, 207, 208, 209, 210, 212, 213, 217, 218, 219, 220, 223, 224, 226, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 261, 262, 263, 264, 265, 266, 267, 268, 270, 271, 272, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 289, 290, 292, 293, 294, 295, 296, 297, 298, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 312, 320, 321, 323, 324, 325, 326, 327, 329, 331, 334, 335, 337, 350, 367, 368, 370, 388, 393, 404, 408, 409, 411, 434, 439, 451, 464, 469, 470, 484], "summary": {"covered_lines": 203, "num_statements": 303, "percent_covered": 66.996699669967, "percent_covered_display": "67", "missing_lines": 100, "excluded_lines": 24}, "missing_lines": [128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 151, 152, 155, 156, 157, 158, 159, 162, 163, 166, 167, 170, 171, 190, 191, 192, 200, 338, 339, 340, 341, 344, 345, 346, 347, 348, 351, 352, 353, 354, 355, 364, 371, 372, 373, 375, 380, 381, 382, 384, 385, 386, 389, 390, 391, 394, 395, 398, 399, 400, 401, 402, 405, 412, 413, 414, 416, 417, 418, 419, 420, 422, 423, 424, 425, 426, 427, 428, 429, 430, 432, 435, 436, 437, 440, 441, 442, 443, 444, 448, 449, 452, 453, 454, 455, 456, 457, 461, 466], "excluded_lines": [57, 58, 59, 445, 446, 447, 458, 459, 460, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 484, 485, 486], "functions": {"LockScreenWindow.__init__": {"executed_lines": [33, 36, 37, 38, 40, 41, 42, 46, 47, 48, 49, 50, 51], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "LockScreenWindow.handle_unlock": {"executed_lines": [54, 55, 56, 60, 66, 67, 68], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [57, 58, 59]}, "MainWindow.__init__": {"executed_lines": [81, 84, 85, 86, 87, 88, 89, 90, 91, 93, 94, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 115, 117, 118, 119, 120, 121, 123], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MainWindow.refresh_entries": {"executed_lines": [126, 127], "summary": {"covered_lines": 2, "num_statements": 13, "percent_covered": 15.384615384615385, "percent_covered_display": "15", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139], "excluded_lines": []}, "MainWindow.add_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [151, 152], "excluded_lines": []}, "MainWindow.edit_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [155, 156, 157, 158, 159], "excluded_lines": []}, "MainWindow.search_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [162, 163], "excluded_lines": []}, "MainWindow.manage_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [166, 167], "excluded_lines": []}, "MainWindow.show_totp_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [170, 171], "excluded_lines": []}, "MainWindow.start_vault_sync": {"executed_lines": [176, 179], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MainWindow.start_vault_sync._runner": {"executed_lines": [177], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MainWindow.sync_started": {"executed_lines": [183], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MainWindow.sync_finished": {"executed_lines": [186, 187], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MainWindow.vault_locked": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [190, 191, 192], "excluded_lines": []}, "MainWindow.cleanup": {"executed_lines": [195, 196, 197, 198, 199], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [200], "excluded_lines": []}, "EntryDialog.__init__": {"executed_lines": [207, 208, 209, 210, 212, 213, 217, 218, 219, 220, 223, 224, 226, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryDialog.save": {"executed_lines": [262, 263, 264, 265, 266, 267, 268, 270, 271, 272, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 289, 290, 292, 293, 294, 295, 296, 297, 298, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 312, 320, 321, 323, 324, 325, 326, 327, 329, 331], "summary": {"covered_lines": 51, "num_statements": 51, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SearchDialog.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [338, 339, 340, 341, 344, 345, 346, 347, 348], "excluded_lines": []}, "SearchDialog.do_search": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [351, 352, 353, 354, 355, 364], "excluded_lines": []}, "TotpViewerWindow.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [371, 372, 373, 375, 380, 381, 382, 384, 385, 386], "excluded_lines": []}, "TotpViewerWindow._update_loop": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [389, 390, 391], "excluded_lines": []}, "TotpViewerWindow.refresh_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [394, 395, 398, 399, 400, 401, 402], "excluded_lines": []}, "TotpViewerWindow.cleanup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [405], "excluded_lines": []}, "RelayManagerDialog.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [412, 413, 414, 416, 417, 418, 419, 420, 422, 423, 424, 425, 426, 427, 428, 429, 430, 432], "excluded_lines": []}, "RelayManagerDialog.refresh": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [435, 436, 437], "excluded_lines": []}, "RelayManagerDialog.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 3}, "missing_lines": [440, 441, 442, 443, 444, 448, 449], "excluded_lines": [445, 446, 447]}, "RelayManagerDialog.remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 3}, "missing_lines": [452, 453, 454, 455, 456, 457, 461], "excluded_lines": [458, 459, 460]}, "build": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [466], "excluded_lines": []}, "SeedPassApp.startup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 11}, "missing_lines": [], "excluded_lines": [471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481]}, "main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [485, 486]}, "": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 21, 24, 25, 27, 53, 71, 72, 74, 125, 150, 154, 161, 165, 169, 173, 182, 185, 189, 194, 203, 204, 206, 261, 334, 335, 337, 350, 367, 368, 370, 388, 393, 404, 408, 409, 411, 434, 439, 451, 464, 469, 470, 484], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [470, 484]}}, "classes": {"LockScreenWindow": {"executed_lines": [33, 36, 37, 38, 40, 41, 42, 46, 47, 48, 49, 50, 51, 54, 55, 56, 60, 66, 67, 68], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [57, 58, 59]}, "MainWindow": {"executed_lines": [81, 84, 85, 86, 87, 88, 89, 90, 91, 93, 94, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 115, 117, 118, 119, 120, 121, 123, 126, 127, 176, 177, 179, 183, 186, 187, 195, 196, 197, 198, 199], "summary": {"covered_lines": 44, "num_statements": 72, "percent_covered": 61.111111111111114, "percent_covered_display": "61", "missing_lines": 28, "excluded_lines": 0}, "missing_lines": [128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 151, 152, 155, 156, 157, 158, 159, 162, 163, 166, 167, 170, 171, 190, 191, 192, 200], "excluded_lines": []}, "EntryDialog": {"executed_lines": [207, 208, 209, 210, 212, 213, 217, 218, 219, 220, 223, 224, 226, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 262, 263, 264, 265, 266, 267, 268, 270, 271, 272, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 289, 290, 292, 293, 294, 295, 296, 297, 298, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 312, 320, 321, 323, 324, 325, 326, 327, 329, 331], "summary": {"covered_lines": 93, "num_statements": 93, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SearchDialog": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [338, 339, 340, 341, 344, 345, 346, 347, 348, 351, 352, 353, 354, 355, 364], "excluded_lines": []}, "TotpViewerWindow": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [371, 372, 373, 375, 380, 381, 382, 384, 385, 386, 389, 390, 391, 394, 395, 398, 399, 400, 401, 402, 405], "excluded_lines": []}, "RelayManagerDialog": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 35, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 35, "excluded_lines": 6}, "missing_lines": [412, 413, 414, 416, 417, 418, 419, 420, 422, 423, 424, 425, 426, 427, 428, 429, 430, 432, 435, 436, 437, 440, 441, 442, 443, 444, 448, 449, 452, 453, 454, 455, 456, 457, 461], "excluded_lines": [445, 446, 447, 458, 459, 460]}, "SeedPassApp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 11}, "missing_lines": [], "excluded_lines": [471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481]}, "": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 21, 24, 25, 27, 53, 71, 72, 74, 125, 150, 154, 161, 165, 169, 173, 182, 185, 189, 194, 203, 204, 206, 261, 334, 335, 337, 350, 367, 368, 370, 388, 393, 404, 408, 409, 411, 434, 439, 451, 464, 469, 470, 484], "summary": {"covered_lines": 46, "num_statements": 47, "percent_covered": 97.87234042553192, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 4}, "missing_lines": [466], "excluded_lines": [470, 484, 485, 486]}}}, "src/tests/conftest.py": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 14, 15, 26, 27, 28, 29, 30, 33, 36, 37, 40, 41, 42, 45, 46, 52, 58, 66, 67, 68, 71, 74, 77, 78, 79, 80, 82, 83, 84, 85, 86, 89, 90, 91, 92, 95, 96, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 115, 116, 117, 145, 146, 147, 148, 149, 150, 153, 154, 156, 157, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 172, 174, 175, 176, 178, 181, 182, 183, 185, 186, 187, 188, 189, 191, 194, 195, 196], "summary": {"covered_lines": 103, "num_statements": 105, "percent_covered": 98.0952380952381, "percent_covered_display": "98", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [75, 179], "excluded_lines": [], "functions": {"anyio_backend": {"executed_lines": [37], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "mute_logging": {"executed_lines": [42], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pytest_addoption": {"executed_lines": [46, 52, 58], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pytest_configure": {"executed_lines": [67, 68], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pytest_collection_modifyitems": {"executed_lines": [74, 77, 78, 79, 80, 82, 83, 84, 85, 86], "summary": {"covered_lines": 10, "num_statements": 11, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [75], "excluded_lines": []}, "vault": {"executed_lines": [91, 92], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "password_manager": {"executed_lines": [97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "client": {"executed_lines": [117, 145, 146, 147, 148, 149, 150], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_dummy_nostr_client": {"executed_lines": [156, 157, 159, 191], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_dummy_nostr_client._make": {"executed_lines": [160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 172, 174, 175, 178, 181, 182, 185, 186, 187, 188, 189], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_dummy_nostr_client._make.DummyKeys.private_key_hex": {"executed_lines": [176], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_dummy_nostr_client._make.DummyKeys.public_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [179], "excluded_lines": []}, "make_dummy_nostr_client._make.DummyKeyManager.__init__": {"executed_lines": [183], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "dummy_nostr_client": {"executed_lines": [196], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 14, 15, 26, 27, 28, 29, 30, 33, 36, 40, 41, 45, 66, 71, 89, 90, 95, 96, 115, 116, 153, 154, 194, 195], "summary": {"covered_lines": 34, "num_statements": 34, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"make_dummy_nostr_client._make.DummyKeys": {"executed_lines": [176], "summary": {"covered_lines": 1, "num_statements": 2, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [179], "excluded_lines": []}, "make_dummy_nostr_client._make.DummyKeyManager": {"executed_lines": [183], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 14, 15, 26, 27, 28, 29, 30, 33, 36, 37, 40, 41, 42, 45, 46, 52, 58, 66, 67, 68, 71, 74, 77, 78, 79, 80, 82, 83, 84, 85, 86, 89, 90, 91, 92, 95, 96, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 115, 116, 117, 145, 146, 147, 148, 149, 150, 153, 154, 156, 157, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 172, 174, 175, 178, 181, 182, 185, 186, 187, 188, 189, 191, 194, 195, 196], "summary": {"covered_lines": 101, "num_statements": 102, "percent_covered": 99.01960784313725, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [75], "excluded_lines": []}}}, "src/tests/helpers.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 11, 12, 18, 22, 25, 31, 32, 33, 34, 36, 37, 38, 39, 42, 43, 44, 45, 46, 47, 49, 50, 53, 54, 55, 56, 57, 59, 60, 63, 64, 65, 66, 71, 72, 74, 76, 77, 79, 80, 83, 84, 85, 86, 88, 89, 90, 92, 93, 96, 97, 98, 101, 102, 103, 104, 105, 106, 107, 109, 110, 112, 113, 114, 119, 121, 122, 123, 125, 126, 127, 128, 130, 131, 132, 134, 135, 136, 139, 140, 141, 143, 144, 145, 148, 149, 150, 152, 153, 155, 156, 157, 160, 161, 162, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 177, 180, 181, 183, 186, 187, 188, 189, 190, 191, 192, 193, 194, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 226, 227, 228, 230, 231, 233], "summary": {"covered_lines": 156, "num_statements": 167, "percent_covered": 93.41317365269461, "percent_covered_display": "93", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [67, 68, 70, 94, 115, 116, 118, 178, 184, 195, 196], "excluded_lines": [], "functions": {"create_vault": {"executed_lines": [31, 32, 33, 34, 36, 37, 38, 39], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEvent.__init__": {"executed_lines": [44, 45, 46, 47], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEvent.content": {"executed_lines": [50], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyUnsignedEvent.__init__": {"executed_lines": [55, 56, 57], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyUnsignedEvent.sign_with_keys": {"executed_lines": [60], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyBuilder.__init__": {"executed_lines": [65, 66, 71, 72], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [67, 68, 70], "excluded_lines": []}, "DummyBuilder.tags": {"executed_lines": [76, 77], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyBuilder.build": {"executed_lines": [80], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyTag.identifier": {"executed_lines": [86], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyTag.event": {"executed_lines": [90], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyTag.alt": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [94], "excluded_lines": []}, "DummyTag.expiration": {"executed_lines": [98], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyFilter.__init__": {"executed_lines": [103, 104, 105, 106, 107], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyFilter.author": {"executed_lines": [110], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyFilter.kind": {"executed_lines": [113, 114, 119], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [115, 116, 118], "excluded_lines": []}, "DummyFilter.identifier": {"executed_lines": [122, 123], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyFilter.id": {"executed_lines": [126, 127, 128], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyFilter.limit": {"executed_lines": [131, 132], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyFilter.since": {"executed_lines": [135, 136], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyTimestamp.__init__": {"executed_lines": [141], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyTimestamp.from_secs": {"executed_lines": [145], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEventId.__init__": {"executed_lines": [150], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEventId.to_hex": {"executed_lines": [153], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEventId.parse": {"executed_lines": [157], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummySendResult.__init__": {"executed_lines": [162], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyRelayClient.__init__": {"executed_lines": [167, 168, 169, 170, 171, 172], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyRelayClient.add_relays": {"executed_lines": [175], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyRelayClient.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [178], "excluded_lines": []}, "DummyRelayClient.connect": {"executed_lines": [181], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyRelayClient.disconnect": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [184], "excluded_lines": []}, "DummyRelayClient.send_event": {"executed_lines": [187, 188, 189, 190, 191, 192, 193, 194, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207], "summary": {"covered_lines": 19, "num_statements": 21, "percent_covered": 90.47619047619048, "percent_covered_display": "90", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [195, 196], "excluded_lines": []}, "DummyRelayClient.fetch_events": {"executed_lines": [210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 226, 227, 230, 233], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyRelayClient.fetch_events.Result.__init__": {"executed_lines": [228], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyRelayClient.fetch_events.Result.to_vec": {"executed_lines": [231], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 11, 12, 18, 22, 25, 42, 43, 49, 53, 54, 59, 63, 64, 74, 79, 83, 84, 85, 88, 89, 92, 93, 96, 97, 101, 102, 109, 112, 121, 125, 130, 134, 139, 140, 143, 144, 148, 149, 152, 155, 156, 160, 161, 165, 166, 174, 177, 180, 183, 186, 209], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEvent": {"executed_lines": [44, 45, 46, 47, 50], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyUnsignedEvent": {"executed_lines": [55, 56, 57, 60], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyBuilder": {"executed_lines": [65, 66, 71, 72, 76, 77, 80], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [67, 68, 70], "excluded_lines": []}, "DummyTag": {"executed_lines": [86, 90, 98], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [94], "excluded_lines": []}, "DummyFilter": {"executed_lines": [103, 104, 105, 106, 107, 110, 113, 114, 119, 122, 123, 126, 127, 128, 131, 132, 135, 136], "summary": {"covered_lines": 18, "num_statements": 21, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [115, 116, 118], "excluded_lines": []}, "DummyTimestamp": {"executed_lines": [141, 145], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEventId": {"executed_lines": [150, 153, 157], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummySendResult": {"executed_lines": [162], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyRelayClient": {"executed_lines": [167, 168, 169, 170, 171, 172, 175, 181, 187, 188, 189, 190, 191, 192, 193, 194, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 226, 227, 230, 233], "summary": {"covered_lines": 46, "num_statements": 50, "percent_covered": 92.0, "percent_covered_display": "92", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [178, 184, 195, 196], "excluded_lines": []}, "DummyRelayClient.fetch_events.Result": {"executed_lines": [228, 231], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 11, 12, 18, 22, 25, 31, 32, 33, 34, 36, 37, 38, 39, 42, 43, 49, 53, 54, 59, 63, 64, 74, 79, 83, 84, 85, 88, 89, 92, 93, 96, 97, 101, 102, 109, 112, 121, 125, 130, 134, 139, 140, 143, 144, 148, 149, 152, 155, 156, 160, 161, 165, 166, 174, 177, 180, 183, 186, 209], "summary": {"covered_lines": 65, "num_statements": 65, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_add_new_fingerprint_words.py": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 11, 13, 14, 16, 17, 18, 20, 23, 24, 29, 31, 33, 34, 35], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_add_new_fingerprint_word_entry_exits": {"executed_lines": [9, 10, 11, 13, 14, 16, 20, 23, 24, 29, 31, 33, 34, 35], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_new_fingerprint_word_entry_exits.setup_wrapper": {"executed_lines": [17, 18], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 11, 13, 14, 16, 17, 18, 20, 23, 24, 29, 31, 33, 34, 35], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_add_tags_from_retrieve.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 18, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 41, 43, 44, 46, 48, 49], "summary": {"covered_lines": 37, "num_statements": 37, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakePasswordGenerator.generate_password": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_tags_from_retrieve": {"executed_lines": [22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 41, 43, 44, 46, 48, 49], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 21], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakePasswordGenerator": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 41, 43, 44, 46, 48, 49], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_additional_backup.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 24, 25, 26, 27, 29, 31, 32, 34, 35, 36, 37], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_entry_manager_additional_backup": {"executed_lines": [13, 14, 15, 16, 17, 18, 19, 21, 22, 24, 25, 26, 27, 29, 31, 32, 34, 35, 36, 37], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 12], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 24, 25, 26, 27, 29, 31, 32, 34, 35, 36, 37], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_ai_tui_agent_harness.py": {"executed_lines": [1, 3, 4, 5, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 24, 25, 26, 28, 29, 31, 33, 34, 35, 36, 37, 40, 41, 43, 44, 46, 47, 49, 50, 51, 52, 55, 56, 57, 58, 59, 61, 62, 64, 65, 67, 68, 69, 70, 71, 74, 75, 76, 77, 78, 80, 81, 83, 84, 86, 87, 88, 89, 94, 95, 96, 97, 105, 107, 108, 109, 110, 112, 113, 115, 118, 119, 120, 121, 124, 125, 126, 129, 132, 135, 136, 137, 140, 141, 142, 143, 144, 146, 147, 148, 149, 150, 152, 153, 154, 156, 159, 160, 161, 162, 163, 166, 167, 168, 169, 171, 172, 174, 175, 177, 178, 180, 183], "summary": {"covered_lines": 118, "num_statements": 123, "percent_covered": 95.9349593495935, "percent_covered_display": "96", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [116, 127, 130, 133, 157], "excluded_lines": [], "functions": {"_load_harness_module": {"executed_lines": [11, 12, 13, 14, 15, 16, 17, 18], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_run_step_records_passed_result": {"executed_lines": [25, 26, 28, 31, 33, 34, 35, 36, 37], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_run_step_records_passed_result._ok": {"executed_lines": [29], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_run_step_records_failed_result_and_reraises": {"executed_lines": [41, 43, 46, 47, 49, 50, 51, 52], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_run_step_records_failed_result_and_reraises._boom": {"executed_lines": [44], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_waits_when_choice_omitted": {"executed_lines": [56, 57, 61, 64, 67, 68, 69, 70, 71], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_waits_when_choice_omitted.Runner.__init__": {"executed_lines": [58, 59], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_waits_when_choice_omitted.Runner.sendline": {"executed_lines": [62], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_waits_when_choice_omitted.Runner.wait_for": {"executed_lines": [65], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_sends_choice_when_provided": {"executed_lines": [75, 76, 80, 83, 86, 87, 88, 89], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_sends_choice_when_provided.Runner.__init__": {"executed_lines": [77, 78], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_sends_choice_when_provided.Runner.sendline": {"executed_lines": [81], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_sends_choice_when_provided.Runner.expect_and_send": {"executed_lines": [84], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password": {"executed_lines": [95, 96, 107, 112, 115, 118, 119, 120, 121], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password.Runner.__init__": {"executed_lines": [97, 105], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password.Runner.try_wait_for": {"executed_lines": [108, 109, 110], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password.Runner.sendline": {"executed_lines": [113], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password.Runner.pump": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [116], "excluded_lines": []}, "test_complete_onboarding_times_out_without_expected_prompts": {"executed_lines": [125, 126, 129, 132, 135, 136, 137], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_times_out_without_expected_prompts.Runner.try_wait_for": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [127], "excluded_lines": []}, "test_complete_onboarding_times_out_without_expected_prompts.Runner.sendline": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [130], "excluded_lines": []}, "test_complete_onboarding_times_out_without_expected_prompts.Runner.pump": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [133], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns": {"executed_lines": [141, 142, 146, 152, 156, 159, 160, 161, 162, 163], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns.Runner.__init__": {"executed_lines": [143, 144], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns.Runner.wait_for": {"executed_lines": [147, 148, 149, 150], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns.Runner.expect_and_send": {"executed_lines": [153, 154], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns.Runner.pump": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [157], "excluded_lines": []}, "test_drain_to_main_menu_times_out_when_no_prompt_progress": {"executed_lines": [167, 168, 171, 174, 177, 178, 180, 183], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_times_out_when_no_prompt_progress.Runner.wait_for": {"executed_lines": [169], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_times_out_when_no_prompt_progress.Runner.expect_and_send": {"executed_lines": [172], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_times_out_when_no_prompt_progress.Runner.pump": {"executed_lines": [175], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 10, 21, 24, 40, 55, 74, 94, 124, 140, 166], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_add_entry_menu_open_waits_when_choice_omitted.Runner": {"executed_lines": [58, 59, 62, 65], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_sends_choice_when_provided.Runner": {"executed_lines": [77, 78, 81, 84], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password.Runner": {"executed_lines": [97, 105, 108, 109, 110, 113], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [116], "excluded_lines": []}, "test_complete_onboarding_times_out_without_expected_prompts.Runner": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [127, 130, 133], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns.Runner": {"executed_lines": [143, 144, 147, 148, 149, 150, 153, 154], "summary": {"covered_lines": 8, "num_statements": 9, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [157], "excluded_lines": []}, "test_drain_to_main_menu_times_out_when_no_prompt_progress.Runner": {"executed_lines": [169, 172, 175], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 24, 25, 26, 28, 29, 31, 33, 34, 35, 36, 37, 40, 41, 43, 44, 46, 47, 49, 50, 51, 52, 55, 56, 57, 61, 64, 67, 68, 69, 70, 71, 74, 75, 76, 80, 83, 86, 87, 88, 89, 94, 95, 96, 107, 112, 115, 118, 119, 120, 121, 124, 125, 126, 129, 132, 135, 136, 137, 140, 141, 142, 146, 152, 156, 159, 160, 161, 162, 163, 166, 167, 168, 171, 174, 177, 178, 180, 183], "summary": {"covered_lines": 93, "num_statements": 93, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_api.py": {"executed_lines": [1, 2, 4, 5, 7, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 36, 39, 40, 41, 42, 47, 48, 49, 50, 53, 54, 55, 56, 60, 61, 62, 63, 66, 67, 68, 69, 73, 74, 75, 76, 79, 80, 81, 82, 86, 87, 88, 89, 92, 93, 94, 95, 97, 102, 103, 105, 110, 111, 113, 114, 115, 117, 118, 119, 122, 123, 124, 125, 127, 128, 130, 131, 132, 137, 138, 139, 140, 143, 144, 145, 146, 147, 150, 151, 156, 157, 158, 161, 162, 163, 164, 165, 166, 167, 172, 173, 174, 175, 178, 179, 180, 181, 182, 187, 190, 191, 192, 194, 196, 197, 198, 199, 201, 203, 207, 208, 209, 210, 211, 212, 215, 216, 233, 234, 235, 236, 237, 238, 239, 240], "summary": {"covered_lines": 137, "num_statements": 137, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_token_hashed": {"executed_lines": [14, 15, 16], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cors_and_auth": {"executed_lines": [21, 22, 23, 24, 25], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_invalid_token": {"executed_lines": [30, 31, 36], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_entry_by_id": {"executed_lines": [41, 42, 47, 48, 49, 50], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_config_value": {"executed_lines": [55, 56, 60, 61, 62, 63], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_list_fingerprint": {"executed_lines": [68, 69, 73, 74, 75, 76], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_nostr_pubkey": {"executed_lines": [81, 82, 86, 87, 88, 89], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_create_modify_archive_entry": {"executed_lines": [94, 95, 97, 102, 103, 105, 110, 111, 113, 114, 115, 117, 118, 119], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_config": {"executed_lines": [124, 125, 127, 130, 131, 132, 137, 138, 139, 140], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_config.set_timeout": {"executed_lines": [128], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_config_quick_unlock": {"executed_lines": [145, 146, 147, 150, 151, 156, 157, 158], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_change_password_route": {"executed_lines": [163, 164, 165, 166, 167, 172, 173, 174, 175], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_config_unknown_key": {"executed_lines": [180, 181, 182, 187], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_shutdown": {"executed_lines": [192, 194, 196, 197, 201, 203, 207, 208, 209, 210, 211, 212], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_shutdown.Loop.call_soon": {"executed_lines": [198, 199], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_invalid_token_other_endpoints": {"executed_lines": [234, 235, 236, 237, 238, 239, 240], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 7, 9, 12, 13, 19, 20, 28, 29, 39, 40, 53, 54, 66, 67, 79, 80, 92, 93, 122, 123, 143, 144, 161, 162, 178, 179, 190, 191, 215, 216, 233], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_shutdown.Loop": {"executed_lines": [198, 199], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 7, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 36, 39, 40, 41, 42, 47, 48, 49, 50, 53, 54, 55, 56, 60, 61, 62, 63, 66, 67, 68, 69, 73, 74, 75, 76, 79, 80, 81, 82, 86, 87, 88, 89, 92, 93, 94, 95, 97, 102, 103, 105, 110, 111, 113, 114, 115, 117, 118, 119, 122, 123, 124, 125, 127, 128, 130, 131, 132, 137, 138, 139, 140, 143, 144, 145, 146, 147, 150, 151, 156, 157, 158, 161, 162, 163, 164, 165, 166, 167, 172, 173, 174, 175, 178, 179, 180, 181, 182, 187, 190, 191, 192, 194, 196, 197, 201, 203, 207, 208, 209, 210, 211, 212, 215, 216, 233, 234, 235, 236, 237, 238, 239, 240], "summary": {"covered_lines": 135, "num_statements": 135, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_api_new_endpoints.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 16, 17, 19, 20, 21, 23, 24, 26, 27, 28, 29, 31, 32, 45, 46, 47, 57, 62, 63, 64, 65, 68, 69, 70, 71, 73, 74, 75, 77, 78, 80, 81, 82, 84, 85, 90, 91, 92, 94, 99, 100, 101, 104, 105, 106, 108, 109, 111, 112, 113, 114, 115, 118, 119, 120, 121, 123, 124, 126, 127, 128, 133, 134, 135, 138, 139, 140, 141, 142, 143, 144, 145, 146, 149, 150, 151, 152, 155, 156, 157, 158, 159, 160, 161, 168, 169, 170, 171, 174, 177, 178, 179, 180, 182, 183, 186, 188, 190, 191, 192, 193, 195, 196, 197, 198, 200, 205, 206, 207, 210, 211, 212, 213, 215, 216, 220, 222, 223, 224, 225, 227, 228, 229, 230, 233, 234, 235, 236, 238, 239, 241, 242, 243, 246, 247, 249, 250, 255, 256, 257, 258, 261, 262, 263, 264, 266, 267, 269, 270, 271, 272, 274, 275, 276, 281, 282, 283, 284, 287, 288, 289, 290, 291, 292, 296, 297, 302, 305, 306, 307, 308, 309, 310, 311, 313, 314, 319, 322, 323, 324, 325, 327, 328, 329, 331, 332, 334, 335, 336, 337, 338, 339, 340, 343, 344, 347, 348, 349, 350, 352, 353, 355, 356, 358, 359, 361, 362, 367, 368, 369, 370, 373, 374, 375, 376, 377, 379, 381, 385, 386, 387, 389, 392, 395, 396, 397, 398, 399, 400, 404, 405, 409, 414, 415, 416, 418, 423, 426, 427, 428, 429, 430, 431, 432, 436, 441, 444, 445, 446, 447, 448, 450, 451, 453, 455, 456, 458, 459, 460, 465, 468, 469, 471, 473, 474, 475, 477, 478, 479, 481, 484, 485, 486, 488, 489, 490, 491, 494, 495, 496, 498, 499, 500, 502, 503, 506, 508, 511, 513, 514, 519, 520, 521, 524, 525, 526, 528, 529, 530, 532, 533, 536, 538, 541, 543, 544, 545, 550, 551, 552, 553], "summary": {"covered_lines": 323, "num_statements": 323, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_create_and_modify_totp_entry": {"executed_lines": [16, 17, 19, 23, 26, 27, 28, 29, 31, 32, 45, 46, 47, 57, 62, 63, 64, 65], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_create_and_modify_totp_entry.add_totp": {"executed_lines": [20, 21], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_create_and_modify_totp_entry.modify": {"executed_lines": [24], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_create_and_modify_ssh_entry": {"executed_lines": [70, 71, 73, 77, 80, 81, 82, 84, 85, 90, 91, 92, 94, 99, 100, 101], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_create_and_modify_ssh_entry.add_ssh": {"executed_lines": [74, 75], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_create_and_modify_ssh_entry.modify": {"executed_lines": [78], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_entry_error": {"executed_lines": [106, 108, 111, 112, 113, 114, 115], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_entry_error.modify": {"executed_lines": [109], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_config_secret_mode": {"executed_lines": [120, 121, 123, 126, 127, 128, 133, 134, 135], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_config_secret_mode.set_secret": {"executed_lines": [124], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_totp_export_endpoint": {"executed_lines": [140, 141, 142, 143, 144, 145, 146], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_totp_codes_endpoint": {"executed_lines": [151, 152, 155, 156, 157, 158, 159, 160, 161], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_parent_seed_endpoint_removed": {"executed_lines": [170, 171, 174], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fingerprint_endpoints": {"executed_lines": [179, 180, 182, 183, 186, 188, 190, 191, 192, 193, 195, 196, 197, 198, 200, 205, 206, 207], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_checksum_endpoints": {"executed_lines": [212, 213, 215, 216, 220, 222, 223, 224, 225, 227, 228, 229, 230], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_via_path": {"executed_lines": [235, 236, 238, 241, 242, 243, 246, 247, 249, 250, 255, 256, 257, 258], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_via_path.import_db": {"executed_lines": [239], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_via_upload": {"executed_lines": [263, 264, 266, 269, 270, 271, 272, 274, 275, 276, 281, 282, 283, 284], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_via_upload.import_db": {"executed_lines": [267], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_invalid_extension": {"executed_lines": [289, 290, 291, 292, 296, 297, 302], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_path_traversal_blocked": {"executed_lines": [307, 308, 309, 310, 311, 313, 314, 319], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_lock_endpoint": {"executed_lines": [324, 325, 327, 331, 332, 334, 335, 336, 337, 338, 339, 340, 343, 344], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_lock_endpoint.lock": {"executed_lines": [328, 329], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_secret_mode_endpoint": {"executed_lines": [349, 350, 352, 355, 358, 359, 361, 362, 367, 368, 369, 370], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_secret_mode_endpoint.set_secret": {"executed_lines": [353], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_secret_mode_endpoint.set_delay": {"executed_lines": [356], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_export_endpoint": {"executed_lines": [375, 376, 377, 379, 381, 385, 386, 387, 389, 392], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_backup_parent_seed_endpoint": {"executed_lines": [397, 398, 399, 400, 404, 405, 409, 414, 415, 416, 418, 423], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_backup_parent_seed_path_traversal_blocked": {"executed_lines": [428, 429, 430, 431, 432, 436, 441], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_relay_management_endpoints": {"executed_lines": [446, 447, 448, 450, 453, 455, 458, 459, 460, 465, 468, 469, 471, 473, 474, 475, 477, 478, 479, 481, 484, 485, 486, 488, 489, 490, 491], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_relay_management_endpoints.load_config": {"executed_lines": [451], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_relay_management_endpoints.set_relays": {"executed_lines": [456], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_no_special_chars": {"executed_lines": [496, 498, 499, 502, 503, 508, 511, 513, 514, 519, 520, 521], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_no_special_chars.DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [500], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_no_special_chars.DummyBIP85.derive_entropy": {"executed_lines": [506], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_allowed_chars": {"executed_lines": [526, 528, 529, 532, 533, 538, 541, 543, 544, 545, 550, 551, 552, 553], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_allowed_chars.DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [530], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_allowed_chars.DummyBIP85.derive_entropy": {"executed_lines": [536], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 68, 69, 104, 105, 118, 119, 138, 139, 149, 150, 168, 169, 177, 178, 210, 211, 233, 234, 261, 262, 287, 288, 305, 306, 322, 323, 347, 348, 373, 374, 395, 396, 426, 427, 444, 445, 494, 495, 524, 525], "summary": {"covered_lines": 52, "num_statements": 52, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_generate_password_no_special_chars.DummyEnc": {"executed_lines": [500], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_no_special_chars.DummyBIP85": {"executed_lines": [506], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_allowed_chars.DummyEnc": {"executed_lines": [530], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_allowed_chars.DummyBIP85": {"executed_lines": [536], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 16, 17, 19, 20, 21, 23, 24, 26, 27, 28, 29, 31, 32, 45, 46, 47, 57, 62, 63, 64, 65, 68, 69, 70, 71, 73, 74, 75, 77, 78, 80, 81, 82, 84, 85, 90, 91, 92, 94, 99, 100, 101, 104, 105, 106, 108, 109, 111, 112, 113, 114, 115, 118, 119, 120, 121, 123, 124, 126, 127, 128, 133, 134, 135, 138, 139, 140, 141, 142, 143, 144, 145, 146, 149, 150, 151, 152, 155, 156, 157, 158, 159, 160, 161, 168, 169, 170, 171, 174, 177, 178, 179, 180, 182, 183, 186, 188, 190, 191, 192, 193, 195, 196, 197, 198, 200, 205, 206, 207, 210, 211, 212, 213, 215, 216, 220, 222, 223, 224, 225, 227, 228, 229, 230, 233, 234, 235, 236, 238, 239, 241, 242, 243, 246, 247, 249, 250, 255, 256, 257, 258, 261, 262, 263, 264, 266, 267, 269, 270, 271, 272, 274, 275, 276, 281, 282, 283, 284, 287, 288, 289, 290, 291, 292, 296, 297, 302, 305, 306, 307, 308, 309, 310, 311, 313, 314, 319, 322, 323, 324, 325, 327, 328, 329, 331, 332, 334, 335, 336, 337, 338, 339, 340, 343, 344, 347, 348, 349, 350, 352, 353, 355, 356, 358, 359, 361, 362, 367, 368, 369, 370, 373, 374, 375, 376, 377, 379, 381, 385, 386, 387, 389, 392, 395, 396, 397, 398, 399, 400, 404, 405, 409, 414, 415, 416, 418, 423, 426, 427, 428, 429, 430, 431, 432, 436, 441, 444, 445, 446, 447, 448, 450, 451, 453, 455, 456, 458, 459, 460, 465, 468, 469, 471, 473, 474, 475, 477, 478, 479, 481, 484, 485, 486, 488, 489, 490, 491, 494, 495, 496, 498, 499, 502, 503, 508, 511, 513, 514, 519, 520, 521, 524, 525, 526, 528, 529, 532, 533, 538, 541, 543, 544, 545, 550, 551, 552, 553], "summary": {"covered_lines": 319, "num_statements": 319, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_api_notifications.py": {"executed_lines": [1, 2, 3, 4, 7, 8, 9, 10, 11, 12, 13, 16, 17, 21, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 38, 41, 42, 43, 44, 45, 46, 47, 48, 52, 55, 56, 57, 58], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_notifications_endpoint": {"executed_lines": [9, 10, 11, 12, 13, 16, 17, 21], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_notifications_endpoint_clears_queue": {"executed_lines": [26, 27, 28, 29, 32, 33, 34, 35, 38], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_notifications_endpoint_does_not_clear_current": {"executed_lines": [43, 44, 45, 46, 47, 48, 52, 55, 56, 57, 58], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 7, 8, 24, 25, 41, 42], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 7, 8, 9, 10, 11, 12, 13, 16, 17, 21, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 38, 41, 42, 43, 44, 45, 46, 47, 48, 52, 55, 56, 57, 58], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_api_profile_stats.py": {"executed_lines": [1, 4, 5, 6, 7, 8, 10, 11, 12, 13], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_profile_stats_endpoint": {"executed_lines": [6, 7, 8, 10, 11, 12, 13], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 4, 5], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 4, 5, 6, 7, 8, 10, 11, 12, 13], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_api_rate_limit.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 13, 14, 15, 16, 17, 19, 21, 34, 35, 36, 37, 38, 40, 41, 44, 46, 47], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_rate_limit_exceeded": {"executed_lines": [15, 16, 17, 19, 21, 34, 35, 36, 37, 38, 40, 41, 44, 46, 47], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 13, 14], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 13, 14, 15, 16, 17, 19, 21, 34, 35, 36, 37, 38, 40, 41, 44, 46, 47], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_api_reload_relays.py": {"executed_lines": [1, 2, 4, 7, 8, 9, 11, 12, 14, 21, 23, 24, 26, 27, 28, 29], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_reload_relays_logs_errors": {"executed_lines": [8, 11, 14, 21, 23, 24, 26, 27, 28, 29], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_reload_relays_logs_errors.close": {"executed_lines": [9], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_reload_relays_logs_errors.init": {"executed_lines": [12], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 7], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 7, 8, 9, 11, 12, 14, 21, 23, 24, 26, 27, 28, 29], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_archive_from_retrieve.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 45, 46, 48, 50, 53, 55, 56, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 76, 78, 79, 81, 83], "summary": {"covered_lines": 63, "num_statements": 63, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakePasswordGenerator.generate_password": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_archive_entry_from_retrieve": {"executed_lines": [23, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 45, 46, 48, 50], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_restore_entry_from_retrieve": {"executed_lines": [55, 56, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 76, 78, 79, 81, 83], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 17, 18, 22, 53], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakePasswordGenerator": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 17, 18, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 45, 46, 48, 50, 53, 55, 56, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 76, 78, 79, 81, 83], "summary": {"covered_lines": 62, "num_statements": 62, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_archive_nonpassword.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 29, 30, 34, 35, 36, 37, 40, 44, 45, 46, 47], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_entry_mgr": {"executed_lines": [16, 17, 18, 19], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_archive_nonpassword_list_search": {"executed_lines": [23, 24, 25, 26, 27, 29, 30, 34, 35, 36, 37, 40, 44, 45, 46, 47], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 22], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 29, 30, 34, 35, 36, 37, 40, 44, 45, 46, 47], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_archive_restore.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 27, 28, 29, 30, 31, 33, 34, 38, 39, 40, 41, 44, 48, 49, 50, 51, 56, 57, 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 78, 79, 80, 82, 83, 84, 85, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 108, 110, 111, 112, 114, 115, 116, 117, 118, 119, 122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 142, 144, 145, 146, 148, 149, 150, 151, 153, 154, 155, 156, 157, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 180, 181, 184, 185, 186, 187, 190, 191, 192, 193, 194, 195, 198, 199, 200, 201, 202, 203, 204, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 218, 219, 220, 222, 227, 228, 229, 231, 233, 234, 235, 236], "summary": {"covered_lines": 179, "num_statements": 179, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_entry_mgr": {"executed_lines": [21, 22, 23, 24], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_archive_restore_affects_listing_and_search": {"executed_lines": [28, 29, 30, 31, 33, 34, 38, 39, 40, 41, 44, 48, 49, 50, 51], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_view_archived_entries_cli": {"executed_lines": [57, 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 78, 79, 80, 82, 83, 84, 85], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_view_archived_entries_view_only": {"executed_lines": [89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 108, 110, 111, 112, 114, 115, 116, 117, 118, 119], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_view_archived_entries_removed_after_restore": {"executed_lines": [123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 142, 144, 145, 146, 148, 149, 150, 151, 153, 154, 155, 156, 157], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_archived_entries_menu_hides_active": {"executed_lines": [161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 180, 181, 184, 185, 186, 187, 190, 191, 192, 193, 194, 195], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_view_archived_entries_refreshes_after_view_action": {"executed_lines": [199, 200, 201, 202, 203, 204, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 218, 219, 220, 222, 227, 228, 229, 231, 233, 234, 235, 236], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 13, 14, 15, 16, 17, 20, 27, 56, 88, 122, 160, 198], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 27, 28, 29, 30, 31, 33, 34, 38, 39, 40, 41, 44, 48, 49, 50, 51, 56, 57, 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 78, 79, 80, 82, 83, 84, 85, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 108, 110, 111, 112, 114, 115, 116, 117, 118, 119, 122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 142, 144, 145, 146, 148, 149, 150, 151, 153, 154, 155, 156, 157, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 180, 181, 184, 185, 186, 187, 190, 191, 192, 193, 194, 195, 198, 199, 200, 201, 202, 203, 204, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 218, 219, 220, 222, 227, 228, 229, 231, 233, 234, 235, 236], "summary": {"covered_lines": 179, "num_statements": 179, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_atomic_write.py": {"executed_lines": [1, 2, 3, 5, 8, 13, 16, 17, 19, 23, 24, 25, 26, 28, 29, 30], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [9, 10], "excluded_lines": [], "functions": {"_writer": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [9, 10], "excluded_lines": []}, "test_atomic_write_concurrent": {"executed_lines": [16, 17, 19, 23, 24, 25, 26, 28, 29, 30], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 8, 13], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 8, 13, 16, 17, 19, 23, 24, 25, 26, 28, 29, 30], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [9, 10], "excluded_lines": []}}}, "src/tests/test_audit_logger.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 11, 12, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 33, 35, 36, 37, 38, 39, 40, 42, 43, 46, 47, 49, 50, 51, 52, 53, 54, 57, 58, 59, 60, 61, 62, 63, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85], "summary": {"covered_lines": 67, "num_statements": 67, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_audit_logger_records_events": {"executed_lines": [16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 33, 35, 36, 37, 38, 39, 40, 42, 43, 46, 47, 49, 50, 51, 52, 53, 54], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_verify_chain": {"executed_lines": [58, 59, 60, 61, 62, 63, 66, 67, 68, 69], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_audit_log_tamper_evident": {"executed_lines": [73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 11, 12, 15, 57, 72], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 11, 12, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 33, 35, 36, 37, 38, 39, 40, 42, 43, 46, 47, 49, 50, 51, 52, 53, 54, 57, 58, 59, 60, 61, 62, 63, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85], "summary": {"covered_lines": 67, "num_statements": 67, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_auto_sync.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13, 14, 30, 32, 34, 36, 37, 39, 40, 42, 43], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_auto_sync_triggers_post": {"executed_lines": [14, 30, 32, 36, 37, 39, 40, 42, 43], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_auto_sync_triggers_post.fake_post": {"executed_lines": [34], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13, 14, 30, 32, 34, 36, 37, 39, 40, 42, 43], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_background_error_reporting.py": {"executed_lines": [1, 2, 4, 7, 8, 9, 10, 11, 12, 15, 16, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 36, 39, 40, 42, 43, 44, 46, 48, 49, 51, 52, 54, 55, 56], "summary": {"covered_lines": 37, "num_statements": 37, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [8, 9, 10, 11, 12, 15, 16], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_sync_error": {"executed_lines": [20, 22, 25, 26, 28, 29, 31, 32, 34, 35, 36], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_sync_error.failing_sync": {"executed_lines": [23], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_relay_check_error": {"executed_lines": [40, 42, 43, 46, 48, 49, 51, 52, 54, 55, 56], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_relay_check_error.DummyClient.check_relay_health": {"executed_lines": [44], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 7, 19, 39], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_start_background_relay_check_error.DummyClient": {"executed_lines": [44], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 7, 8, 9, 10, 11, 12, 15, 16, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 36, 39, 40, 42, 43, 46, 48, 49, 51, 52, 54, 55, 56], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_background_relay_check.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 13, 14, 15, 16, 17, 18, 23, 24, 26, 29, 30, 31, 32, 33, 34, 36, 37, 39, 40, 41], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_background_relay_check_runs_async": {"executed_lines": [14, 15, 16, 17, 18, 23, 24, 26], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_background_relay_check_warns_when_unhealthy": {"executed_lines": [30, 31, 32, 33, 34, 36, 37, 39, 40, 41], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 13, 29], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 13, 14, 15, 16, 17, 18, 23, 24, 26, 29, 30, 31, 32, 33, 34, 36, 37, 39, 40, 41], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_background_sync_always.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 13, 14, 19, 20, 21, 22, 23, 25, 26, 29, 30, 31, 33, 35, 36, 38, 40, 41, 44, 45, 46, 47, 49, 50, 53, 54, 55, 56, 58, 60, 61, 63, 65, 66], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_switch_fingerprint_triggers_bg_sync": {"executed_lines": [12, 13, 14, 19, 20, 21, 22, 23, 25, 26, 29, 30, 31, 33, 35, 38, 40, 41], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_switch_fingerprint_triggers_bg_sync.fake_bg": {"executed_lines": [36], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_exit_managed_account_triggers_bg_sync": {"executed_lines": [45, 46, 47, 49, 50, 53, 54, 55, 56, 58, 60, 63, 65, 66], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_exit_managed_account_triggers_bg_sync.fake_bg": {"executed_lines": [61], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 44], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 13, 14, 19, 20, 21, 22, 23, 25, 26, 29, 30, 31, 33, 35, 36, 38, 40, 41, 44, 45, 46, 47, 49, 50, 53, 54, 55, 56, 58, 60, 61, 63, 65, 66], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_background_vault_sync_paths.py": {"executed_lines": [1, 3, 4, 7, 8, 9, 11, 13, 14, 16, 17, 21, 22, 23, 24, 26, 27, 29, 31, 33, 34, 37, 38, 39, 41, 43, 44, 46, 47, 51, 52, 53, 55, 57, 58], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_start_background_vault_sync_thread_worker_path": {"executed_lines": [8, 9, 11, 13, 16, 17, 21, 22, 26, 29, 31, 33, 34], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_vault_sync_thread_worker_path.fake_sync_vault_async": {"executed_lines": [14], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_vault_sync_thread_worker_path.ImmediateThread.__init__": {"executed_lines": [23, 24], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_vault_sync_thread_worker_path.ImmediateThread.start": {"executed_lines": [27], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_vault_sync_async_worker_path": {"executed_lines": [38, 39, 41, 43, 46, 47, 51, 55, 57, 58], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_vault_sync_async_worker_path.fake_sync_vault_async": {"executed_lines": [44], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_vault_sync_async_worker_path.runner": {"executed_lines": [52, 53], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 7, 37], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_start_background_vault_sync_thread_worker_path.ImmediateThread": {"executed_lines": [23, 24, 27], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 7, 8, 9, 11, 13, 14, 16, 17, 21, 22, 26, 29, 31, 33, 34, 37, 38, 39, 41, 43, 44, 46, 47, 51, 52, 53, 55, 57, 58], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_backup_interval.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 13, 14, 15, 16, 17, 19, 21, 22, 23, 24, 26, 27, 28, 29, 31, 32, 33, 34], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_backup_interval": {"executed_lines": [12, 13, 14, 15, 16, 17, 19, 21, 22, 23, 24, 26, 27, 28, 29, 31, 32, 33, 34], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 11], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 13, 14, 15, 16, 17, 19, 21, 22, 23, 24, 26, 27, 28, 29, 31, 32, 33, 34], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_backup_restore.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 15, 16, 17, 18, 19, 20, 22, 24, 39, 40, 42, 43, 44, 45, 46, 47, 49, 64, 65, 67, 68, 69, 70, 71, 72, 74, 75, 76, 78, 79, 80, 82, 83, 84, 85, 88, 89, 90, 91, 92, 93, 94, 96, 98, 99, 101, 102, 104, 105, 106, 107], "summary": {"covered_lines": 60, "num_statements": 60, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_backup_restore_workflow": {"executed_lines": [16, 17, 18, 19, 20, 22, 24, 39, 40, 42, 43, 44, 45, 46, 47, 49, 64, 65, 67, 68, 69, 70, 71, 72, 74, 75, 76, 78, 79, 80, 82, 83, 84, 85], "summary": {"covered_lines": 34, "num_statements": 34, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_additional_backup_location": {"executed_lines": [89, 90, 91, 92, 93, 94, 96, 98, 99, 101, 102, 104, 105, 106, 107], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 15, 88], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 15, 16, 17, 18, 19, 20, 22, 24, 39, 40, 42, 43, 44, 45, 46, 47, 49, 64, 65, 67, 68, 69, 70, 71, 72, 74, 75, 76, 78, 79, 80, 82, 83, 84, 85, 88, 89, 90, 91, 92, 93, 94, 96, 98, 99, 101, 102, 104, 105, 106, 107], "summary": {"covered_lines": 60, "num_statements": 60, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_backup_restore_startup.py": {"executed_lines": [1, 2, 5, 6, 7, 8, 10, 11, 13, 14, 15, 16, 17, 19, 20, 21, 23, 24, 25, 26, 27, 28, 31, 32, 33, 34, 36, 37, 39, 40, 41, 42, 43, 45, 46, 47, 48, 49, 51, 52, 53, 54, 55, 56], "summary": {"covered_lines": 44, "num_statements": 44, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_cli_flag_restores_before_init": {"executed_lines": [6, 7, 8, 10, 13, 14, 19, 20, 21, 23, 24, 25, 26, 27, 28], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_flag_restores_before_init.fake_restore": {"executed_lines": [11], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_flag_restores_before_init.DummyPM.__init__": {"executed_lines": [15, 16, 17], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_option_restores_before_init": {"executed_lines": [32, 33, 34, 36, 39, 40, 45, 46, 47, 48, 49, 51, 52, 53, 54, 55, 56], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_option_restores_before_init.fake_restore": {"executed_lines": [37], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_option_restores_before_init.DummyPM.__init__": {"executed_lines": [41, 42, 43], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 31], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_cli_flag_restores_before_init.DummyPM": {"executed_lines": [15, 16, 17], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_option_restores_before_init.DummyPM": {"executed_lines": [41, 42, 43], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 7, 8, 10, 11, 13, 14, 19, 20, 21, 23, 24, 25, 26, 27, 28, 31, 32, 33, 34, 36, 37, 39, 40, 45, 46, 47, 48, 49, 51, 52, 53, 54, 55, 56], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_bip85_derivation_path.py": {"executed_lines": [1, 4, 5, 6, 8, 9, 11, 12, 15, 16, 17, 19, 20, 21, 24, 25, 26, 27, 29, 35, 36, 42, 45, 46, 47, 48, 50, 52], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"DummyChild.PrivateKey": {"executed_lines": [6], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyChild.Raw": {"executed_lines": [9], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyChild.ToBytes": {"executed_lines": [12], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyCtx.__init__": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyCtx.DerivePath": {"executed_lines": [20, 21], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_derivation_paths_for_entropy_lengths": {"executed_lines": [25, 26, 27, 29, 35, 36, 42], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_default_word_count_from_entropy_bytes": {"executed_lines": [46, 47, 48, 50, 52], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 4, 5, 8, 11, 15, 16, 19, 24, 45], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyChild": {"executed_lines": [6, 9, 12], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyCtx": {"executed_lines": [17, 20, 21], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 4, 5, 8, 11, 15, 16, 19, 24, 25, 26, 27, 29, 35, 36, 42, 45, 46, 47, 48, 50, 52], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_bip85_init.py": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 11, 14, 15, 16, 17, 20, 21, 22, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 38, 39], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_init_with_seed_bytes": {"executed_lines": [15, 16, 17], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_init_with_xprv": {"executed_lines": [21, 22], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_initialize_bip85_works_while_locked": {"executed_lines": [26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 38, 39], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 11, 14, 20, 25], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 11, 14, 15, 16, 17, 20, 21, 22, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 38, 39], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_bip85_vectors.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 12, 14, 16, 18, 20, 21, 22, 25, 26, 27, 30, 31, 34, 35, 38, 39, 42, 43, 46, 47, 50, 51, 54, 55, 56, 57, 58], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"bip85": {"executed_lines": [27], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_bip85_mnemonic_12": {"executed_lines": [31], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_bip85_mnemonic_24": {"executed_lines": [35], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_bip85_symmetric_key": {"executed_lines": [39], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_derive_totp_secret": {"executed_lines": [43], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_derive_ssh_key": {"executed_lines": [47], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_derive_seed_phrase": {"executed_lines": [51], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_invalid_params": {"executed_lines": [55, 56, 57, 58], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 12, 14, 16, 18, 20, 21, 22, 25, 26, 30, 34, 38, 42, 46, 50, 54], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 12, 14, 16, 18, 20, 21, 22, 25, 26, 27, 30, 31, 34, 35, 38, 39, 42, 43, 46, 47, 50, 51, 54, 55, 56, 57, 58], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_check_critical_coverage.py": {"executed_lines": [1, 3, 4, 5, 7, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 26, 27, 30, 31, 34, 44, 45, 46, 49, 50, 56, 57, 60, 61, 62, 78, 81, 82, 83, 84], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_load_module": {"executed_lines": [11, 12, 13, 16, 17, 18, 19, 20], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_parse_threshold_overrides_valid": {"executed_lines": [27, 30, 31], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_parse_threshold_overrides_invalid": {"executed_lines": [45, 46], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_find_file_payload_accepts_absolute_path_suffix": {"executed_lines": [50, 56, 57], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_compute_function_coverage_reports_uncovered": {"executed_lines": [61, 62, 78, 81, 82, 83, 84], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 10, 23, 26, 34, 44, 49, 60], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 7, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 26, 27, 30, 31, 34, 44, 45, 46, 49, 50, 56, 57, 60, 61, 62, 78, 81, 82, 83, 84], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_checksum_utils.py": {"executed_lines": [1, 2, 3, 5, 8, 9, 10, 13, 16, 17, 18, 19, 20, 21, 22, 25, 26, 27, 30, 31, 32, 33, 34, 36, 37, 38, 41, 42, 43, 44, 45, 46, 47], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_json_checksum": {"executed_lines": [9, 10, 13], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_calculate_checksum": {"executed_lines": [17, 18, 19, 20, 21, 22], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_calculate_checksum_missing": {"executed_lines": [26, 27], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_verify_and_update": {"executed_lines": [31, 32, 33, 34, 36, 37, 38], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_initialize_checksum": {"executed_lines": [42, 43, 44, 45, 46, 47], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 8, 16, 25, 30, 41], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 8, 9, 10, 13, 16, 17, 18, 19, 20, 21, 22, 25, 26, 27, 30, 31, 32, 33, 34, 36, 37, 38, 41, 42, 43, 44, 45, 46, 47], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_clipboard_flag.py": {"executed_lines": [1, 3, 4, 5, 7, 10, 11, 12, 13, 15, 16, 18, 19, 20, 21, 23, 26, 27, 30, 31, 32, 35, 36, 39, 42, 43], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_stub_service": {"executed_lines": [11, 12, 15, 18, 23], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_stub_service.Service.search_entries": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_stub_service.Service.retrieve_entry": {"executed_lines": [16], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_stub_service.Service.generate_password": {"executed_lines": [19, 20, 21], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_get_handles_missing_clipboard": {"executed_lines": [27, 30, 31, 32], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_get_no_clipboard_flag": {"executed_lines": [36, 39, 42, 43], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 10, 26, 35], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"_stub_service.Service": {"executed_lines": [13, 16, 19, 20, 21], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 10, 11, 12, 15, 18, 23, 26, 27, 30, 31, 32, 35, 36, 39, 42, 43], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_config_set_extra.py": {"executed_lines": [1, 2, 3, 5, 6, 8, 11, 31, 32, 34, 35, 36, 38, 42, 44, 46, 47, 48, 49, 50], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_config_set_variants": {"executed_lines": [32, 34, 38, 42, 44, 46, 47, 48, 49, 50], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_config_set_variants.func": {"executed_lines": [35, 36], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 8, 11, 31], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 8, 11, 31, 32, 34, 35, 36, 38, 42, 44, 46, 47, 48, 49, 50], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_core_services.py": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 14, 15, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 30, 31, 33, 34, 35, 37, 38, 39, 41, 42, 43, 45, 53, 56, 57, 58, 59, 60, 63, 66, 67, 68, 71, 72, 73, 74], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_cli_vault_unlock": {"executed_lines": [15, 17, 21, 22, 23, 24, 25, 26, 27], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_vault_unlock.unlock_vault": {"executed_lines": [18, 19], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_entry_add_search_sync": {"executed_lines": [31, 33, 37, 41, 45, 53, 56, 57, 58, 59, 60, 63, 66, 67, 68, 71, 72, 73, 74], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_entry_add_search_sync.add_entry": {"executed_lines": [34, 35], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_entry_add_search_sync.search_entries": {"executed_lines": [38, 39], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_entry_add_search_sync.start_background_vault_sync": {"executed_lines": [42, 43], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 14, 30], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 14, 15, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 30, 31, 33, 34, 35, 37, 38, 39, 41, 42, 43, 45, 53, 56, 57, 58, 59, 60, 63, 66, 67, 68, 71, 72, 73, 74], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_doc_examples.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 16, 17, 18, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 57, 60, 65, 66, 82, 83, 84, 87, 88, 89, 90, 91, 92, 93, 94, 95, 98, 101, 102, 103, 104, 105, 108, 111, 114, 115, 116, 117, 118], "summary": {"covered_lines": 56, "num_statements": 56, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"DummyPM.__init__": {"executed_lines": [18, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 57, 60, 65, 66, 82, 83, 84], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "load_doc_commands": {"executed_lines": [88, 89, 90, 91, 92, 93, 94, 95], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_setup": {"executed_lines": [102, 103, 104, 105, 108], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_doc_cli_examples": {"executed_lines": [116, 117, 118], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 16, 17, 87, 98, 101, 111, 114, 115], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyPM": {"executed_lines": [18, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 57, 60, 65, 66, 82, 83, 84], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 16, 17, 87, 88, 89, 90, 91, 92, 93, 94, 95, 98, 101, 102, 103, 104, 105, 108, 111, 114, 115, 116, 117, 118], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_entry_add_commands.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 12, 138, 141, 143, 144, 145, 146, 148, 149, 151, 157, 158, 159, 160, 161, 162, 163], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_entry_add_commands": {"executed_lines": [141, 143, 148, 151, 157, 158, 159, 160, 161, 162, 163], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_add_commands.func": {"executed_lines": [144, 145, 146], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_add_commands.start_background_vault_sync": {"executed_lines": [149], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 12, 138], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 12, 138, 141, 143, 144, 145, 146, 148, 149, 151, 157, 158, 159, 160, 161, 162, 163], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_export_import.py": {"executed_lines": [1, 2, 4, 6, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 28, 31, 32, 33, 46, 48, 49, 50, 51, 53, 54, 55, 56, 59, 60, 61, 74, 76, 77, 84, 86, 87, 88, 89, 91, 92, 93, 96, 97, 98, 111, 113, 114, 115, 116, 118, 119, 120, 121, 123, 124, 125, 126], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_setup_pm": {"executed_lines": [16, 17, 18, 19, 28], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_export_creates_file": {"executed_lines": [32, 33, 46, 48, 49, 50, 51, 53, 54, 55, 56], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_import_round_trip": {"executed_lines": [60, 61, 74, 76, 77, 84, 86, 87, 88, 89, 91, 92, 93], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_export_import_unencrypted": {"executed_lines": [97, 98, 111, 113, 114, 115, 116, 118, 119, 120, 121, 123, 124, 125, 126], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 8, 9, 10, 11, 12, 15, 31, 59, 96], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 28, 31, 32, 33, 46, 48, 49, 50, 51, 53, 54, 55, 56, 59, 60, 61, 74, 76, 77, 84, 86, 87, 88, 89, 91, 92, 93, 96, 97, 98, 111, 113, 114, 115, 116, 118, 119, 120, 121, 123, 124, 125, 126], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_integration.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 29, 32, 33, 34, 37, 42, 47, 51, 56, 57, 59, 61, 63, 65, 66, 67, 68, 69, 71], "summary": {"covered_lines": 40, "num_statements": 41, "percent_covered": 97.5609756097561, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [52], "excluded_lines": [], "functions": {"test_cli_integration": {"executed_lines": [17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 29, 32, 33, 34, 37, 42, 47, 51, 56, 57, 59, 61, 63, 65, 66, 67, 68, 69, 71], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_integration.auto_add": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [52], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 29, 32, 33, 34, 37, 42, 47, 51, 56, 57, 59, 61, 63, 65, 66, 67, 68, 69, 71], "summary": {"covered_lines": 40, "num_statements": 41, "percent_covered": 97.5609756097561, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [52], "excluded_lines": []}}}, "src/tests/test_cli_invalid_input.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13, 14, 15, 17, 20, 23, 26, 27, 29, 30, 32, 33, 34, 36, 52, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104], "summary": {"covered_lines": 66, "num_statements": 69, "percent_covered": 95.65217391304348, "percent_covered_display": "96", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [18, 21, 24], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [14, 15, 17, 20, 23, 26, 29, 32, 36, 52], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_make_pm.add": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [18], "excluded_lines": []}, "_make_pm.retrieve": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [21], "excluded_lines": []}, "_make_pm.modify": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [24], "excluded_lines": []}, "_make_pm.update": {"executed_lines": [27], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_make_pm.lock": {"executed_lines": [30], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_make_pm.unlock": {"executed_lines": [33, 34], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_empty_and_non_numeric_choice": {"executed_lines": [56, 57, 58, 59, 60, 61, 62, 63, 64], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_out_of_range_menu": {"executed_lines": [68, 69, 70, 71, 72, 73, 74, 75, 76], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_invalid_add_entry_submenu": {"executed_lines": [80, 81, 82, 83, 84, 85, 86, 87, 88, 89], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_inactivity_timeout_loop": {"executed_lines": [93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13, 55, 67, 79, 92], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13, 14, 15, 17, 20, 23, 26, 27, 29, 30, 32, 33, 34, 36, 52, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104], "summary": {"covered_lines": 66, "num_statements": 69, "percent_covered": 95.65217391304348, "percent_covered_display": "96", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [18, 21, 24], "excluded_lines": []}}}, "src/tests/test_cli_relays.py": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 12, 15, 16, 18, 19, 21, 23, 24, 26, 28, 31, 34, 35, 37, 38, 40, 41, 43, 44, 46, 47, 48, 49, 51, 52, 53], "summary": {"covered_lines": 33, "num_statements": 37, "percent_covered": 89.1891891891892, "percent_covered_display": "89", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [13, 20, 25, 27], "excluded_lines": [], "functions": {"DummyService.__init__": {"executed_lines": [10], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyService.get_pubkey": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [13], "excluded_lines": []}, "DummyService.list_relays": {"executed_lines": [16], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyService.add_relay": {"executed_lines": [19, 21], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [20], "excluded_lines": []}, "DummyService.remove_relay": {"executed_lines": [24, 26, 28], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [25, 27], "excluded_lines": []}, "test_cli_relay_crud": {"executed_lines": [35, 37, 40, 41, 43, 44, 46, 47, 48, 49, 51, 52, 53], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_relay_crud.pm_factory": {"executed_lines": [38], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8, 9, 12, 15, 18, 23, 31, 34], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyService": {"executed_lines": [10, 16, 19, 21, 24, 26, 28], "summary": {"covered_lines": 7, "num_statements": 11, "percent_covered": 63.63636363636363, "percent_covered_display": "64", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [13, 20, 25, 27], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8, 9, 12, 15, 18, 23, 31, 34, 35, 37, 38, 40, 41, 43, 44, 46, 47, 48, 49, 51, 52, 53], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_subcommands.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 17, 18, 26, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 58, 59, 60, 61, 62, 65, 66, 67, 68, 69, 70, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 85, 86, 90, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 114, 115, 119, 120, 121, 122, 123, 124, 125, 126, 127, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 143, 145, 147, 148, 149, 151, 152, 153, 154, 156, 157, 158], "summary": {"covered_lines": 113, "num_statements": 113, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"make_pm": {"executed_lines": [12, 17, 18, 26], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_command": {"executed_lines": [30, 31, 32, 33, 34, 35, 36, 37, 38], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_command": {"executed_lines": [42, 43, 44, 45, 46, 47, 48, 49, 50, 51], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_totp_command": {"executed_lines": [55, 56, 57, 58, 59, 60, 61, 62, 65, 66, 67, 68, 69, 70], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_command_no_results": {"executed_lines": [74, 75, 76, 77, 78, 79, 80, 81, 82], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_command_multiple_matches": {"executed_lines": [86, 90, 91, 92, 93, 94, 95, 96, 97, 98], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_command_wrong_type": {"executed_lines": [102, 103, 104, 105, 106, 107, 108, 109, 110, 111], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_totp_command_multiple_matches": {"executed_lines": [115, 119, 120, 121, 122, 123, 124, 125, 126, 127], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_totp_command_wrong_type": {"executed_lines": [131, 132, 133, 134, 135, 136, 137, 138, 139, 140], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_main_fingerprint_option": {"executed_lines": [145, 147, 151, 152, 153, 154, 156, 157, 158], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_main_fingerprint_option.fake_pm": {"executed_lines": [148, 149], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 29, 41, 54, 73, 85, 101, 114, 130, 143], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 17, 18, 26, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 58, 59, 60, 61, 62, 65, 66, 67, 68, 69, 70, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 85, 86, 90, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 114, 115, 119, 120, 121, 122, 123, 124, 125, 126, 127, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 143, 145, 147, 148, 149, 151, 152, 153, 154, 156, 157, 158], "summary": {"covered_lines": 113, "num_statements": 113, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_toggle_offline_mode.py": {"executed_lines": [1, 2, 4, 5, 7, 10, 11, 15, 20, 23, 24, 25, 26, 27, 28, 29, 30, 33, 34, 35, 36, 37, 38, 39, 40], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [11, 15, 20], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_toggle_offline_updates": {"executed_lines": [24, 25, 26, 27, 28, 29, 30], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_toggle_offline_keep": {"executed_lines": [34, 35, 36, 37, 38, 39, 40], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 7, 10, 23, 33], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 7, 10, 11, 15, 20, 23, 24, 25, 26, 27, 28, 29, 30, 33, 34, 35, 36, 37, 38, 39, 40], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_toggle_secret_mode.py": {"executed_lines": [1, 2, 3, 5, 6, 8, 11, 12, 18, 24, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 44], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [12, 18, 24], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_toggle_secret_mode_updates": {"executed_lines": [28, 29, 30, 31, 32, 33, 34], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_toggle_secret_mode_keep": {"executed_lines": [38, 39, 40, 41, 42, 43, 44], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 8, 11, 27, 37], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 8, 11, 12, 18, 24, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 44], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_vault_stats.py": {"executed_lines": [1, 2, 3, 5, 6, 8, 11, 12, 16, 19, 20, 21, 22, 24, 25], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_vault_stats_command": {"executed_lines": [12, 16, 19, 20, 21, 22, 24, 25], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 8, 11], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 8, 11, 12, 16, 19, 20, 21, 22, 24, 25], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_clipboard_utils.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 15, 16, 18, 19, 21, 22, 24, 26, 27, 28, 29, 31, 32, 34, 35, 36, 38, 39, 40, 41, 42, 43, 46, 47, 49, 50, 52, 53, 55, 57, 58, 59, 61, 62, 64, 65, 66, 68, 69, 70, 71, 74, 75, 76, 78, 79, 80, 82, 83], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_copy_to_clipboard_clears": {"executed_lines": [16, 18, 21, 24, 26, 27, 31, 34, 35, 36, 38, 39, 40, 41, 42, 43], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_clears.fake_copy": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_clears.fake_paste": {"executed_lines": [22], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_clears.DummyTimer.__init__": {"executed_lines": [28, 29], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_clears.DummyTimer.start": {"executed_lines": [32], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_does_not_clear_if_changed": {"executed_lines": [47, 49, 52, 55, 57, 58, 61, 64, 65, 66, 68, 69, 70, 71], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_does_not_clear_if_changed.fake_copy": {"executed_lines": [50], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_does_not_clear_if_changed.fake_paste": {"executed_lines": [53], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_does_not_clear_if_changed.DummyTimer.__init__": {"executed_lines": [59], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_does_not_clear_if_changed.DummyTimer.start": {"executed_lines": [62], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_missing_dependency": {"executed_lines": [75, 78, 79, 80, 82, 83], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_missing_dependency.fail_copy": {"executed_lines": [76], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 15, 46, 74], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_copy_to_clipboard_clears.DummyTimer": {"executed_lines": [28, 29, 32], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_does_not_clear_if_changed.DummyTimer": {"executed_lines": [59, 62], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 15, 16, 18, 19, 21, 22, 24, 26, 27, 31, 34, 35, 36, 38, 39, 40, 41, 42, 43, 46, 47, 49, 50, 52, 53, 55, 57, 58, 61, 64, 65, 66, 68, 69, 70, 71, 74, 75, 76, 78, 79, 80, 82, 83], "summary": {"covered_lines": 52, "num_statements": 52, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_concurrency_stress.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 17, 29, 39, 51, 52, 53, 54, 55, 56, 57, 58, 59, 61, 62, 70, 71, 72, 73, 75, 76, 79, 81, 82], "summary": {"covered_lines": 35, "num_statements": 55, "percent_covered": 63.63636363636363, "percent_covered_display": "64", "missing_lines": 20, "excluded_lines": 6}, "missing_lines": [18, 19, 20, 21, 22, 23, 24, 30, 31, 32, 33, 34, 40, 41, 42, 43, 44, 45, 46, 77], "excluded_lines": [25, 26, 35, 36, 47, 48], "functions": {"_writer": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 2}, "missing_lines": [18, 19, 20, 21, 22, 23, 24], "excluded_lines": [25, 26]}, "_reader": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 2}, "missing_lines": [30, 31, 32, 33, 34], "excluded_lines": [35, 36]}, "_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 2}, "missing_lines": [40, 41, 42, 43, 44, 45, 46], "excluded_lines": [47, 48]}, "test_concurrency_stress": {"executed_lines": [54, 55, 56, 57, 58, 59, 61, 62, 70, 71, 72, 73, 75, 76, 79, 81, 82], "summary": {"covered_lines": 17, "num_statements": 18, "percent_covered": 94.44444444444444, "percent_covered_display": "94", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [77], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 17, 29, 39, 51, 52, 53], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 17, 29, 39, 51, 52, 53, 54, 55, 56, 57, 58, 59, 61, 62, 70, 71, 72, 73, 75, 76, 79, 81, 82], "summary": {"covered_lines": 35, "num_statements": 55, "percent_covered": 63.63636363636363, "percent_covered_display": "64", "missing_lines": 20, "excluded_lines": 6}, "missing_lines": [18, 19, 20, 21, 22, 23, 24, 30, 31, 32, 33, 34, 40, 41, 42, 43, 44, 45, 46, 77], "excluded_lines": [25, 26, 35, 36, 47, 48]}}}, "src/tests/test_config_manager.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 29, 30, 32, 33, 34, 37, 38, 39, 40, 42, 43, 44, 45, 46, 49, 52, 53, 54, 55, 57, 58, 60, 61, 62, 64, 65, 66, 67, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 84, 87, 88, 89, 90, 92, 93, 95, 96, 97, 100, 101, 102, 105, 106, 108, 109, 111, 112, 114, 115, 116, 119, 120, 121, 122, 125, 127, 128, 129, 130, 132, 133, 134, 137, 138, 139, 140, 142, 143, 144, 146, 147, 148, 149, 150, 153, 154, 155, 156, 158, 160, 161, 164, 165, 166, 167, 169, 171, 172, 175, 176, 177, 178, 180, 182, 183, 186, 187, 188, 189, 191, 192, 193, 195, 196, 197, 198, 201, 202, 203, 204, 206, 207, 208, 209, 210, 212, 213, 214, 215, 217, 218, 219, 220, 221, 224, 225, 226, 227, 229, 230, 231, 232, 234, 235, 236, 237, 238], "summary": {"covered_lines": 171, "num_statements": 171, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_config_defaults_and_round_trip": {"executed_lines": [17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 29, 30, 32, 33, 34], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_pin_verification_and_change": {"executed_lines": [38, 39, 40, 42, 43, 44, 45, 46], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_config_file_encrypted_after_save": {"executed_lines": [53, 54, 55, 57, 58, 60, 61, 62, 64, 65, 66, 67], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_set_relays_persists_changes": {"executed_lines": [71, 72, 73, 74, 75, 76], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_set_relays_requires_at_least_one": {"executed_lines": [80, 81, 82, 83, 84], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_inactivity_timeout_round_trip": {"executed_lines": [88, 89, 90, 92, 93, 95, 96, 97], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_password_hash_migrates_from_file": {"executed_lines": [101, 102, 105, 106, 108, 109, 111, 112, 114, 115, 116], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_additional_backup_path_round_trip": {"executed_lines": [120, 121, 122, 125, 127, 128, 129, 130, 132, 133, 134], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_secret_mode_round_trip": {"executed_lines": [138, 139, 140, 142, 143, 144, 146, 147, 148, 149, 150], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_kdf_iterations_round_trip": {"executed_lines": [154, 155, 156, 158, 160, 161], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_backup_interval_round_trip": {"executed_lines": [165, 166, 167, 169, 171, 172], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_quick_unlock_round_trip": {"executed_lines": [176, 177, 178, 180, 182, 183], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_nostr_retry_settings_round_trip": {"executed_lines": [187, 188, 189, 191, 192, 193, 195, 196, 197, 198], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_special_char_settings_round_trip": {"executed_lines": [202, 203, 204, 206, 207, 208, 209, 210, 212, 213, 214, 215, 217, 218, 219, 220, 221], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_password_policy_extended_fields": {"executed_lines": [225, 226, 227, 229, 230, 231, 232, 234, 235, 236, 237, 238], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 16, 37, 49, 52, 70, 79, 87, 100, 119, 137, 153, 164, 175, 186, 201, 224], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 29, 30, 32, 33, 34, 37, 38, 39, 40, 42, 43, 44, 45, 46, 49, 52, 53, 54, 55, 57, 58, 60, 61, 62, 64, 65, 66, 67, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 84, 87, 88, 89, 90, 92, 93, 95, 96, 97, 100, 101, 102, 105, 106, 108, 109, 111, 112, 114, 115, 116, 119, 120, 121, 122, 125, 127, 128, 129, 130, 132, 133, 134, 137, 138, 139, 140, 142, 143, 144, 146, 147, 148, 149, 150, 153, 154, 155, 156, 158, 160, 161, 164, 165, 166, 167, 169, 171, 172, 175, 176, 177, 178, 180, 182, 183, 186, 187, 188, 189, 191, 192, 193, 195, 196, 197, 198, 201, 202, 203, 204, 206, 207, 208, 209, 210, 212, 213, 214, 215, 217, 218, 219, 220, 221, 224, 225, 226, 227, 229, 230, 231, 232, 234, 235, 236, 237, 238], "summary": {"covered_lines": 171, "num_statements": 171, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_core_api_services.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 30, 31, 34, 35, 36, 37, 40, 41, 43, 46, 47, 48, 49, 50, 51, 52, 53, 56, 57, 58, 60, 63, 64, 66, 67, 70, 71, 72, 73, 75, 76, 77, 79, 80, 82, 83, 84, 86, 87, 89, 90, 91, 92, 94, 96, 97, 100, 103, 105, 106, 107, 108, 112, 114, 117, 120, 122, 123, 124, 126, 128, 129, 130, 131, 133, 134, 136, 137, 138, 140, 141, 142, 144, 148, 149, 150, 152, 154, 155, 158, 159, 160, 161, 163, 164, 165, 167, 168, 170, 171, 172, 174, 175, 177, 178, 179, 181, 185, 186, 187, 189, 192, 193, 194, 195, 197, 198, 199, 201, 203, 206, 207, 209, 210, 212, 214, 217, 219, 220, 221, 223, 224, 225, 228, 229, 230, 231, 233, 234, 235, 237, 240, 242, 243, 244, 246, 249, 251, 252, 253, 254, 256, 257, 259, 261, 262, 263, 265, 267, 268, 270, 272, 273, 275, 277, 278, 280, 281, 282, 284, 286, 287, 289, 290, 292, 294, 295, 296, 298, 299, 301, 303, 304, 305, 307, 308, 310, 312, 313, 314, 316, 317, 319, 321, 322, 323, 325, 326, 328, 330, 331, 332, 334, 335, 337, 339, 340, 341, 343, 344, 346, 348, 349, 350, 352, 353, 355, 357, 358, 359, 361, 362, 364, 375, 377, 378, 380, 381, 383, 384, 386, 387, 389, 390, 392, 394, 395, 397, 398, 399, 402, 403, 404, 405, 407, 408, 409, 411, 414, 416, 417, 418, 420, 421, 422, 426, 433, 434, 438, 439, 440, 442, 443, 444, 446, 447, 448, 450, 451, 453, 456, 459, 460, 462, 463, 464, 466, 467, 469, 470, 473, 474, 475, 476, 478, 479, 482, 483, 485, 489, 490, 493, 495, 496, 497, 499, 500, 501, 504, 505, 506, 507, 509, 510, 511, 513, 514, 515, 517, 518, 519, 521, 522, 524, 525, 526, 528, 529], "summary": {"covered_lines": 315, "num_statements": 315, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"mock_manager": {"executed_lines": [43, 46, 47, 48, 49, 50, 51, 52, 53, 56, 57, 58, 60], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "mock_bus": {"executed_lines": [66, 67], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.service": {"executed_lines": [73], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_export_vault": {"executed_lines": [76, 77, 79, 80], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_import_vault": {"executed_lines": [83, 84, 86, 87], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_export_profile": {"executed_lines": [90, 91, 92, 94, 96, 97, 100, 103], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_import_profile": {"executed_lines": [106, 107, 108, 112, 114, 117, 120], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_change_password": {"executed_lines": [123, 124, 126], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_unlock": {"executed_lines": [129, 130, 131, 133, 134], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_lock": {"executed_lines": [137, 138], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_backup_parent_seed": {"executed_lines": [141, 142, 144], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_stats": {"executed_lines": [149, 150, 152, 154, 155], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestProfileService.service": {"executed_lines": [161], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestProfileService.test_list_profiles": {"executed_lines": [164, 165, 167, 168], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestProfileService.test_add_profile": {"executed_lines": [171, 172, 174, 175], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestProfileService.test_remove_profile": {"executed_lines": [178, 179, 181], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestProfileService.test_switch_profile": {"executed_lines": [186, 187, 189], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestSyncService.service": {"executed_lines": [195], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestSyncService.test_sync": {"executed_lines": [198, 199, 201, 203, 206, 207], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestSyncService.test_sync_none": {"executed_lines": [210, 212, 214, 217], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestSyncService.test_start_background_sync": {"executed_lines": [220, 221], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestSyncService.test_start_background_vault_sync": {"executed_lines": [224, 225], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.service": {"executed_lines": [231], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_list_entries": {"executed_lines": [234, 235, 237, 240], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_search_entries": {"executed_lines": [243, 244, 246, 249], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_retrieve_entry": {"executed_lines": [252, 253, 254, 256, 257], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_generate_password_default": {"executed_lines": [261, 262, 263, 265, 267, 268], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_generate_password_custom": {"executed_lines": [272, 273, 275, 277, 278], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_get_totp_code": {"executed_lines": [281, 282, 284, 286, 287], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_add_entry": {"executed_lines": [290, 292, 294, 295, 296], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_add_totp": {"executed_lines": [299, 301, 303, 304, 305], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_add_ssh_key": {"executed_lines": [308, 310, 312, 313, 314], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_add_pgp_key": {"executed_lines": [317, 319, 321, 322, 323], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_add_nostr_key": {"executed_lines": [326, 328, 330, 331, 332], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_add_seed": {"executed_lines": [335, 337, 339, 340, 341], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_add_key_value": {"executed_lines": [344, 346, 348, 349, 350], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_add_managed_account": {"executed_lines": [353, 355, 357, 358, 359], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_modify_entry": {"executed_lines": [362, 364, 375], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_archive_entry": {"executed_lines": [378, 380, 381], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_restore_entry": {"executed_lines": [384, 386, 387], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_export_totp_entries": {"executed_lines": [390, 392, 394, 395], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_display_totp_codes": {"executed_lines": [398, 399], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.service": {"executed_lines": [405], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_get": {"executed_lines": [408, 409, 411, 414], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_set_simple": {"executed_lines": [417, 418], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_set_bool": {"executed_lines": [421, 422], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_set_relays": {"executed_lines": [433, 434], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_set_invalid_key": {"executed_lines": [439, 440], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_get_secret_mode_enabled": {"executed_lines": [443, 444], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_get_clipboard_clear_delay": {"executed_lines": [447, 448], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_set_secret_mode": {"executed_lines": [451, 453, 456, 459, 460], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_get_offline_mode": {"executed_lines": [463, 464], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_set_offline_mode": {"executed_lines": [467, 469, 470], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestUtilityService.service": {"executed_lines": [476], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestUtilityService.test_generate_password": {"executed_lines": [479, 482, 483, 485, 489, 490, 493], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestUtilityService.test_verify_checksum": {"executed_lines": [496, 497], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestUtilityService.test_update_checksum": {"executed_lines": [500, 501], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestNostrService.service": {"executed_lines": [507], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestNostrService.test_get_pubkey": {"executed_lines": [510, 511], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestNostrService.test_list_relays": {"executed_lines": [514, 515], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestNostrService.test_add_relay": {"executed_lines": [518, 519, 521, 522], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestNostrService.test_remove_relay": {"executed_lines": [525, 526, 528, 529], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 30, 31, 34, 35, 36, 37, 40, 41, 63, 64, 70, 71, 72, 75, 82, 89, 105, 122, 128, 136, 140, 148, 158, 159, 160, 163, 170, 177, 185, 192, 193, 194, 197, 209, 219, 223, 228, 229, 230, 233, 242, 251, 259, 270, 280, 289, 298, 307, 316, 325, 334, 343, 352, 361, 377, 383, 389, 397, 402, 403, 404, 407, 416, 420, 426, 438, 442, 446, 450, 462, 466, 473, 474, 475, 478, 495, 499, 504, 505, 506, 509, 513, 517, 524], "summary": {"covered_lines": 91, "num_statements": 91, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"MockPolicy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService": {"executed_lines": [73, 76, 77, 79, 80, 83, 84, 86, 87, 90, 91, 92, 94, 96, 97, 100, 103, 106, 107, 108, 112, 114, 117, 120, 123, 124, 126, 129, 130, 131, 133, 134, 137, 138, 141, 142, 144, 149, 150, 152, 154, 155], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestProfileService": {"executed_lines": [161, 164, 165, 167, 168, 171, 172, 174, 175, 178, 179, 181, 186, 187, 189], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestSyncService": {"executed_lines": [195, 198, 199, 201, 203, 206, 207, 210, 212, 214, 217, 220, 221, 224, 225], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService": {"executed_lines": [231, 234, 235, 237, 240, 243, 244, 246, 249, 252, 253, 254, 256, 257, 261, 262, 263, 265, 267, 268, 272, 273, 275, 277, 278, 281, 282, 284, 286, 287, 290, 292, 294, 295, 296, 299, 301, 303, 304, 305, 308, 310, 312, 313, 314, 317, 319, 321, 322, 323, 326, 328, 330, 331, 332, 335, 337, 339, 340, 341, 344, 346, 348, 349, 350, 353, 355, 357, 358, 359, 362, 364, 375, 378, 380, 381, 384, 386, 387, 390, 392, 394, 395, 398, 399], "summary": {"covered_lines": 85, "num_statements": 85, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService": {"executed_lines": [405, 408, 409, 411, 414, 417, 418, 421, 422, 433, 434, 439, 440, 443, 444, 447, 448, 451, 453, 456, 459, 460, 463, 464, 467, 469, 470], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestUtilityService": {"executed_lines": [476, 479, 482, 483, 485, 489, 490, 493, 496, 497, 500, 501], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestNostrService": {"executed_lines": [507, 510, 511, 514, 515, 518, 519, 521, 522, 525, 526, 528, 529], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 30, 31, 34, 35, 36, 37, 40, 41, 43, 46, 47, 48, 49, 50, 51, 52, 53, 56, 57, 58, 60, 63, 64, 66, 67, 70, 71, 72, 75, 82, 89, 105, 122, 128, 136, 140, 148, 158, 159, 160, 163, 170, 177, 185, 192, 193, 194, 197, 209, 219, 223, 228, 229, 230, 233, 242, 251, 259, 270, 280, 289, 298, 307, 316, 325, 334, 343, 352, 361, 377, 383, 389, 397, 402, 403, 404, 407, 416, 420, 426, 438, 442, 446, 450, 462, 466, 473, 474, 475, 478, 495, 499, 504, 505, 506, 509, 513, 517, 524], "summary": {"covered_lines": 106, "num_statements": 106, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_core_services.py": {"executed_lines": [1, 2, 4, 5, 8, 9, 11, 12, 13, 15, 16, 17, 18, 19, 22, 23, 25, 26, 27, 29, 30, 31, 33, 34, 36, 37, 38, 44, 45, 46, 47, 48, 50, 51, 52, 55, 56, 58, 59, 60, 66, 67, 68, 69, 70, 71, 72], "summary": {"covered_lines": 47, "num_statements": 47, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_vault_service_unlock": {"executed_lines": [9, 11, 15, 16, 17, 18, 19], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_service_unlock.unlock_vault": {"executed_lines": [12, 13], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_service_add_entry_and_search": {"executed_lines": [23, 25, 29, 33, 36, 37, 38, 44, 45, 46, 47, 48, 50, 51, 52], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_service_add_entry_and_search.add_entry": {"executed_lines": [26, 27], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_service_add_entry_and_search.search_entries": {"executed_lines": [30, 31], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_service_add_entry_and_search.start_background_vault_sync": {"executed_lines": [34], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sync_service_sync": {"executed_lines": [56, 58, 66, 67, 68, 69, 70, 71, 72], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sync_service_sync.sync_vault": {"executed_lines": [59, 60], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8, 22, 55], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 8, 9, 11, 12, 13, 15, 16, 17, 18, 19, 22, 23, 25, 26, 27, 29, 30, 31, 33, 34, 36, 37, 38, 44, 45, 46, 47, 48, 50, 51, 52, 55, 56, 58, 59, 60, 66, 67, 68, 69, 70, 71, 72], "summary": {"covered_lines": 47, "num_statements": 47, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_custom_fields_display.py": {"executed_lines": [1, 2, 3, 5, 8, 9, 10, 11, 13, 22, 23, 25, 26, 27, 28, 29, 30], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_retrieve_entry_shows_custom_fields": {"executed_lines": [9, 10, 11, 13, 22, 23, 25, 26, 27, 28, 29, 30], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 8], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 8, 9, 10, 11, 13, 22, 23, 25, 26, 27, 28, 29, 30], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_decrypt_messages.py": {"executed_lines": [1, 2, 3, 5, 6, 8, 9, 13, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 30, 31, 32, 33, 34, 36, 40, 41, 42, 44, 45, 46, 47, 50, 51, 52, 53, 54, 56, 57, 58], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_wrong_password_message": {"executed_lines": [17, 18, 19, 21, 22, 23, 25, 26, 27], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_file_requires_migration_message": {"executed_lines": [31, 36, 40, 41, 42, 44, 45, 46, 47], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_file_requires_migration_message._fast_legacy_key": {"executed_lines": [32, 33, 34], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_corrupted_data_message": {"executed_lines": [51, 52, 53, 54, 56, 57, 58], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 8, 9, 13, 16, 30, 50], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 8, 9, 13, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 30, 31, 32, 33, 34, 36, 40, 41, 42, 44, 45, 46, 47, 50, 51, 52, 53, 54, 56, 57, 58], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_default_encryption_mode.py": {"executed_lines": [1, 2, 4, 6, 7, 9, 10, 13, 14, 26, 28, 29], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_default_encryption_mode": {"executed_lines": [14, 26, 28, 29], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 9, 10, 13], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 7, 9, 10, 13, 14, 26, 28, 29], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_delta_merge.py": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 25, 26, 29, 30, 31, 32, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 46, 47, 48, 49], "summary": {"covered_lines": 37, "num_statements": 37, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_setup_mgr": {"executed_lines": [13, 14, 15, 16], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_merge_modified_ts": {"executed_lines": [20, 21, 22, 23, 25, 26, 29, 30, 31, 32, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 46, 47, 48, 49], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 19], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 25, 26, 29, 30, 31, 32, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 46, 47, 48, 49], "summary": {"covered_lines": 37, "num_statements": 37, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_duplicate_seed_profile_creation.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 12, 13, 14, 15, 16, 17, 18, 22, 23, 24, 26, 27, 29, 30, 31, 34, 35, 36, 37, 38, 39, 42, 43, 44, 45, 47, 48, 49, 51, 52, 53], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_setup_pm": {"executed_lines": [13, 14, 15, 16, 17, 18, 22, 23, 26, 29, 30, 31, 34, 35, 36, 37, 38, 39], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_setup_pm.DummyEnc.__init__": {"executed_lines": [24], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_setup_pm.DummyEnc.encrypt_parent_seed": {"executed_lines": [27], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_duplicate_seed_profile_creation": {"executed_lines": [43, 44, 45, 47, 48, 49, 51, 52, 53], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 12, 42], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"_setup_pm.DummyEnc": {"executed_lines": [24, 27], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 12, 13, 14, 15, 16, 17, 18, 22, 23, 26, 29, 30, 31, 34, 35, 36, 37, 38, 39, 42, 43, 44, 45, 47, 48, 49, 51, 52, 53], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_edit_tags_from_retrieve.py": {"executed_lines": [1, 2, 3, 5, 8, 9, 10, 13, 14, 15, 16, 18, 20, 21, 23, 25, 26], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakePasswordGenerator.generate_password": {"executed_lines": [10], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_edit_tags_from_retrieve": {"executed_lines": [14, 15, 16, 18, 20, 21, 23, 25, 26], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 8, 9, 13], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakePasswordGenerator": {"executed_lines": [10], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 8, 9, 13, 14, 15, 16, 18, 20, 21, 23, 25, 26], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_encryption_checksum.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 10, 12, 13, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 39, 40, 41, 43, 45, 46, 48, 50, 51, 53, 54, 56, 57], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_encryption_checksum_workflow": {"executed_lines": [17, 18, 19, 20, 22, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_checksum_removes_legacy": {"executed_lines": [40, 41, 43, 45, 46, 48, 50, 51, 53, 54, 56, 57], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 10, 12, 13, 16, 39], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 10, 12, 13, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 39, 40, 41, 43, 45, 46, 48, 50, 51, 53, 54, 56, 57], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_encryption_files.py": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 10, 12, 15, 16, 17, 18, 20, 21, 22, 23, 25, 26, 27, 30, 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 46, 47, 48, 49, 51, 52, 54, 55], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_json_save_and_load_round_trip": {"executed_lines": [16, 17, 18, 20, 21, 22, 23, 25, 26, 27], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_encrypt_and_decrypt_file_binary_round_trip": {"executed_lines": [31, 32, 33, 35, 36, 37, 38, 39, 41, 42, 43], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_encrypt_file_rejects_traversal": {"executed_lines": [47, 48, 49, 51, 52, 54, 55], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 10, 12, 15, 30, 46], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 10, 12, 15, 16, 17, 18, 20, 21, 22, 23, 25, 26, 27, 30, 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 46, 47, 48, 49, 51, 52, 54, 55], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_encryption_fuzz.py": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 15, 17, 18, 19, 20, 23, 24, 29, 31, 32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_encrypt_decrypt_roundtrip": {"executed_lines": [17, 18, 19, 20], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_corrupted_ciphertext_fails": {"executed_lines": [31, 32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 15, 23, 24, 29], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 15, 17, 18, 19, 20, 23, 24, 29, 31, 32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_encryption_validate_seed.py": {"executed_lines": [1, 2, 4, 5, 7, 9, 12, 13, 14, 17, 18, 19, 20, 21, 22, 25, 26, 27, 28, 29, 30], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"make_manager": {"executed_lines": [13, 14], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_validate_seed_valid_mnemonic": {"executed_lines": [18, 19, 20, 21, 22], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_validate_seed_invalid_mnemonic": {"executed_lines": [26, 27, 28, 29, 30], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 7, 9, 12, 17, 25], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 7, 9, 12, 13, 14, 17, 18, 19, 20, 21, 22, 25, 26, 27, 28, 29, 30], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_entries_empty.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 21, 22], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_list_entries_empty": {"executed_lines": [15, 16, 17, 18, 19, 21, 22], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 21, 22], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_entry_add.py": {"executed_lines": [1, 2, 3, 4, 6, 7, 9, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 24, 29, 30, 32, 45, 46, 47, 48, 49, 52, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 87, 88, 89, 90, 91, 92, 95, 96, 97, 98, 99, 100, 102, 104, 105, 106, 108, 109, 112, 125, 126, 127, 128, 129, 130, 132, 133, 134, 136, 138, 139], "summary": {"covered_lines": 77, "num_statements": 78, "percent_covered": 98.71794871794872, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [85], "excluded_lines": [], "functions": {"test_add_and_retrieve_entry": {"executed_lines": [18, 19, 20, 21, 22, 24, 29, 30, 32, 45, 46, 47, 48, 49], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_round_trip_entry_types": {"executed_lines": [64, 65, 66, 67, 68, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 87, 88, 89, 90, 91, 92], "summary": {"covered_lines": 24, "num_statements": 25, "percent_covered": 96.0, "percent_covered_display": "96", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [85], "excluded_lines": []}, "test_legacy_entry_defaults_to_password": {"executed_lines": [96, 97, 98, 99, 100, 102, 104, 105, 106, 108, 109], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_default_archived_false": {"executed_lines": [126, 127, 128, 129, 130, 132, 133, 134, 136, 138, 139], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 9, 11, 12, 13, 14, 17, 52, 63, 95, 112, 125], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 7, 9, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 24, 29, 30, 32, 45, 46, 47, 48, 49, 52, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 87, 88, 89, 90, 91, 92, 95, 96, 97, 98, 99, 100, 102, 104, 105, 106, 108, 109, 112, 125, 126, 127, 128, 129, 130, 132, 133, 134, 136, 138, 139], "summary": {"covered_lines": 77, "num_statements": 78, "percent_covered": 98.71794871794872, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [85], "excluded_lines": []}}}, "src/tests/test_entry_management_checksum_path.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 23, 24, 26, 27, 30, 31, 32, 33, 34, 35, 36, 38, 39, 41, 42, 43], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_update_checksum_writes_to_expected_path": {"executed_lines": [15, 16, 17, 18, 19, 20, 23, 24, 26, 27], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_backup_index_file_creates_backup_in_directory": {"executed_lines": [31, 32, 33, 34, 35, 36, 38, 39, 41, 42, 43], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14, 30], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 23, 24, 26, 27, 30, 31, 32, 33, 34, 35, 36, 38, 39, 41, 42, 43], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_entry_policy_override.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 15, 18, 19, 23, 24, 25, 28, 29, 30, 31, 32, 34, 35, 36, 37, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 58, 64, 65, 66, 67], "summary": {"covered_lines": 46, "num_statements": 47, "percent_covered": 97.87234042553192, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [20], "excluded_lines": [], "functions": {"DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [20], "excluded_lines": []}, "DummyBIP85.derive_entropy": {"executed_lines": [25], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_manager": {"executed_lines": [29, 30, 31, 32, 34, 35, 36, 37, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_policy_override_changes_password": {"executed_lines": [55, 56, 57, 58, 64, 65, 66, 67], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 15, 18, 19, 23, 24, 28, 54], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEnc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [20], "excluded_lines": []}, "DummyBIP85": {"executed_lines": [25], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 15, 18, 19, 23, 24, 28, 29, 30, 31, 32, 34, 35, 36, 37, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 58, 64, 65, 66, 67], "summary": {"covered_lines": 45, "num_statements": 45, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_export_totp_codes.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 15, 18, 19, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 40, 41, 43, 44, 45, 47, 49, 50, 51, 52, 54, 55], "summary": {"covered_lines": 39, "num_statements": 40, "percent_covered": 97.5, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [20], "excluded_lines": [], "functions": {"FakeNostrClient.publish_snapshot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [20], "excluded_lines": []}, "test_handle_export_totp_codes": {"executed_lines": [24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 40, 41, 43, 44, 45, 47, 49, 50, 51, 52, 54, 55], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 15, 18, 19, 23], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeNostrClient": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [20], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 15, 18, 19, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 40, 41, 43, 44, 45, 47, 49, 50, 51, 52, 54, 55], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_file_lock.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 17, 23, 27, 28, 33, 34, 38, 39, 41, 42, 44, 45, 46, 47, 49, 50, 56], "summary": {"covered_lines": 24, "num_statements": 31, "percent_covered": 77.41935483870968, "percent_covered_display": "77", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [12, 13, 14, 18, 19, 20, 36], "excluded_lines": [], "functions": {"_hold_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [12, 13, 14], "excluded_lines": []}, "_try_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [18, 19, 20], "excluded_lines": []}, "test_exclusive_lock_blocks_until_released": {"executed_lines": [28, 33, 34, 38, 39, 41, 42, 44, 45, 46, 47, 49, 50, 56], "summary": {"covered_lines": 14, "num_statements": 15, "percent_covered": 93.33333333333333, "percent_covered_display": "93", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [36], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 17, 23, 27], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 17, 23, 27, 28, 33, 34, 38, 39, 41, 42, 44, 45, 46, 47, 49, 50, 56], "summary": {"covered_lines": 24, "num_statements": 31, "percent_covered": 77.41935483870968, "percent_covered_display": "77", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [12, 13, 14, 18, 19, 20, 36], "excluded_lines": []}}}, "src/tests/test_file_locking.py": {"executed_lines": [1, 2, 3, 5, 8, 9, 10, 11, 16, 17, 18, 19, 24, 27, 28, 29, 30, 32, 33, 34, 35, 38, 40, 41, 42, 43, 45, 46, 47], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 4}, "missing_lines": [], "excluded_lines": [12, 13, 20, 21], "functions": {"_writer": {"executed_lines": [9, 10, 11], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [12, 13]}, "_reader": {"executed_lines": [17, 18, 19], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [20, 21]}, "test_concurrent_shared_and_exclusive_lock": {"executed_lines": [29, 30, 32, 33, 34, 35, 38, 40, 41, 42, 43, 45, 46, 47], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 8, 16, 24, 27, 28], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 8, 9, 10, 11, 16, 17, 18, 19, 24, 27, 28, 29, 30, 32, 33, 34, 35, 38, 40, 41, 42, 43, 45, 46, 47], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 4}, "missing_lines": [], "excluded_lines": [12, 13, 20, 21]}}}, "src/tests/test_fingerprint_encryption.py": {"executed_lines": [1, 2, 3, 4, 6, 7, 9, 11, 12, 15, 16, 17, 20, 21, 22, 23, 26, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_generate_fingerprint_deterministic": {"executed_lines": [16, 17, 20, 21, 22, 23], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_encryption_round_trip": {"executed_lines": [27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 9, 11, 12, 15, 26], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 7, 9, 11, 12, 15, 16, 17, 20, 21, 22, 23, 26, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_fingerprint_manager_utils.py": {"executed_lines": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_add_and_remove_fingerprint": {"executed_lines": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_remove_nonexistent_fingerprint": {"executed_lines": [19, 20], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 4, 18], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_full_sync_roundtrip.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 51, 52, 53, 56, 57, 58, 59, 60, 63, 64, 65, 66], "summary": {"covered_lines": 50, "num_statements": 50, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_init_pm": {"executed_lines": [14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_full_sync_roundtrip": {"executed_lines": [33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 51, 52, 53, 56, 57, 58, 59, 60, 63, 64, 65, 66], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 32], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 51, 52, 53, 56, 57, 58, 59, 60, 63, 64, 65, 66], "summary": {"covered_lines": 50, "num_statements": 50, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_full_sync_roundtrip_new.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 51, 52, 53, 56, 57, 58, 59, 60, 63, 64, 65, 66], "summary": {"covered_lines": 50, "num_statements": 50, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_init_pm": {"executed_lines": [14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_full_sync_roundtrip": {"executed_lines": [33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 51, 52, 53, 56, 57, 58, 59, 60, 63, 64, 65, 66], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 32], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 51, 52, 53, 56, 57, 58, 59, 60, 63, 64, 65, 66], "summary": {"covered_lines": 50, "num_statements": 50, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_fuzz_key_derivation.py": {"executed_lines": [1, 2, 4, 5, 6, 7, 8, 10, 16, 17, 19, 26, 32, 37, 39, 40, 41, 42, 48, 50, 51, 59, 62, 63, 66, 67, 68, 71, 72, 73, 76, 77, 78, 79], "summary": {"covered_lines": 34, "num_statements": 34, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_fuzz_key_round_trip": {"executed_lines": [39, 40, 41, 42, 48, 50, 51, 59, 62, 63, 66, 67, 68, 71, 72, 73, 76, 77, 78, 79], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 6, 7, 8, 10, 16, 17, 19, 26, 32, 37], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 6, 7, 8, 10, 16, 17, 19, 26, 32, 37, 39, 40, 41, 42, 48, 50, 51, 59, 62, 63, 66, 67, 68, 71, 72, 73, 76, 77, 78, 79], "summary": {"covered_lines": 34, "num_statements": 34, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_generate_test_profile.py": {"executed_lines": [1, 2, 3, 4, 7, 8, 9, 11, 14, 15, 17, 20, 23, 24, 25, 27, 28, 30, 31, 32, 33], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_initialize_profile_creates_directories": {"executed_lines": [8, 9, 11, 14, 15, 17, 20, 23, 24, 25, 27, 28, 30, 31, 32, 33], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 7], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 7, 8, 9, 11, 14, 15, 17, 20, 23, 24, 25, 27, 28, 30, 31, 32, 33], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_generate_test_profile_sync.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 26, 27, 28, 30, 32, 33, 35, 36, 42, 44, 46, 47, 48, 50, 53, 54, 55, 57, 58, 64, 66, 67, 68, 69, 70], "summary": {"covered_lines": 43, "num_statements": 44, "percent_covered": 97.72727272727273, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [51], "excluded_lines": [], "functions": {"load_script": {"executed_lines": [10, 13, 14, 15, 16, 17], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_test_profile_sync": {"executed_lines": [21, 22, 23, 24, 26, 27, 28, 30, 32, 33, 35, 36, 42, 44, 46, 47, 50, 53, 54, 57, 58, 64, 66, 67, 68, 69, 70], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_test_profile_sync.DummyKeys.private_key_hex": {"executed_lines": [48], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_test_profile_sync.DummyKeys.public_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [51], "excluded_lines": []}, "test_generate_test_profile_sync.DummyKeyManager.__init__": {"executed_lines": [55], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 9, 20], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_generate_test_profile_sync.DummyKeys": {"executed_lines": [48], "summary": {"covered_lines": 1, "num_statements": 2, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [51], "excluded_lines": []}, "test_generate_test_profile_sync.DummyKeyManager": {"executed_lines": [55], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 26, 27, 28, 30, 32, 33, 35, 36, 42, 44, 46, 47, 50, 53, 54, 57, 58, 64, 66, 67, 68, 69, 70], "summary": {"covered_lines": 41, "num_statements": 41, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_get_entry_summaries_archived_view.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 38, 39, 40, 41, 43, 44, 46, 47, 48, 49, 50], "summary": {"covered_lines": 41, "num_statements": 41, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_get_entry_summaries_excludes_archived_and_view_handler": {"executed_lines": [15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 38, 39, 40, 41, 43, 44, 46, 47, 48, 49, 50], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 38, 39, 40, 41, 43, 44, 46, 47, 48, 49, 50], "summary": {"covered_lines": 41, "num_statements": 41, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_get_entry_summaries_updates.py": {"executed_lines": [1, 2, 4, 6, 7, 8, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 24, 25, 27, 28, 29, 32, 33, 34, 35, 36, 37, 39, 40, 42, 43, 44, 46, 47, 48], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_create_entry_manager": {"executed_lines": [12, 13, 14, 15], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_entry_summaries_updates_label": {"executed_lines": [19, 20, 21, 22, 24, 25, 27, 28, 29], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_entry_summaries_updates_archive_restore": {"executed_lines": [33, 34, 35, 36, 37, 39, 40, 42, 43, 44, 46, 47, 48], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 8, 11, 18, 32], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 7, 8, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 24, 25, 27, 28, 29, 32, 33, 34, 35, 36, 37, 39, 40, 42, 43, 44, 46, 47, 48], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_gui_features.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 18, 21, 24, 28, 29, 33, 38, 41, 44, 48, 49, 57, 58, 65, 78, 94], "summary": {"covered_lines": 26, "num_statements": 83, "percent_covered": 31.325301204819276, "percent_covered_display": "31", "missing_lines": 57, "excluded_lines": 0}, "missing_lines": [16, 19, 22, 25, 30, 31, 34, 35, 36, 39, 42, 45, 50, 51, 52, 53, 54, 59, 60, 62, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 95, 96, 97, 98, 99, 100, 101, 104, 108, 109, 112, 113, 114, 115], "excluded_lines": [], "functions": {"DummyNostr.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [16], "excluded_lines": []}, "DummyNostr.list_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [19], "excluded_lines": []}, "DummyNostr.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": []}, "DummyNostr.remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [25], "excluded_lines": []}, "DummyEntries.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [30, 31], "excluded_lines": []}, "DummyEntries.list_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [34, 35, 36], "excluded_lines": []}, "DummyEntries.search_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [39], "excluded_lines": []}, "DummyEntries.retrieve_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [42], "excluded_lines": []}, "DummyEntries.get_totp_code": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [45], "excluded_lines": []}, "DummyController.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [50, 51, 52, 53, 54], "excluded_lines": []}, "set_backend": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [59, 60, 62], "excluded_lines": []}, "test_relay_manager_add_remove": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [66, 67, 68, 69, 70, 71, 72, 73, 74, 75], "excluded_lines": []}, "test_status_bar_updates_and_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91], "excluded_lines": []}, "test_totp_viewer_refresh_on_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [95, 96, 97, 98, 99, 100, 101, 104, 108, 109, 112, 113, 114, 115], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 18, 21, 24, 28, 29, 33, 38, 41, 44, 48, 49, 57, 58, 65, 78, 94], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyNostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [16, 19, 22, 25], "excluded_lines": []}, "DummyEntries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [30, 31, 34, 35, 36, 39, 42, 45], "excluded_lines": []}, "DummyController": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [50, 51, 52, 53, 54], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 18, 21, 24, 28, 29, 33, 38, 41, 44, 48, 49, 57, 58, 65, 78, 94], "summary": {"covered_lines": 26, "num_statements": 66, "percent_covered": 39.39393939393939, "percent_covered_display": "39", "missing_lines": 40, "excluded_lines": 0}, "missing_lines": [59, 60, 62, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 95, 96, 97, 98, 99, 100, 101, 104, 108, 109, 112, 113, 114, 115], "excluded_lines": []}}}, "src/tests/test_gui_headless.py": {"executed_lines": [1, 2, 3, 5, 6, 8, 10, 13, 14, 15, 17, 18, 21, 22, 23, 24, 26, 27, 29, 32, 33, 34, 36, 39, 40, 42, 43, 44, 46, 47, 48, 50, 51, 52, 54, 55, 56, 58, 59, 60, 62, 63, 64, 66, 69, 72, 73, 74, 76, 79, 80, 83, 86, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, 101, 104, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 135, 136, 137, 138, 141, 149, 150, 151, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170], "summary": {"covered_lines": 105, "num_statements": 109, "percent_covered": 96.3302752293578, "percent_covered_display": "96", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [30, 81, 84, 87], "excluded_lines": [], "functions": {"FakeVault.__init__": {"executed_lines": [15], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeVault.unlock": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.__init__": {"executed_lines": [23, 24], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.list_entries": {"executed_lines": [27], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.search_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [30], "excluded_lines": []}, "FakeEntries.add_entry": {"executed_lines": [33, 34], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.add_totp": {"executed_lines": [39, 40], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.add_ssh_key": {"executed_lines": [43, 44], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.add_seed": {"executed_lines": [47, 48], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.add_pgp_key": {"executed_lines": [51, 52], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.add_nostr_key": {"executed_lines": [55, 56], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.add_key_value": {"executed_lines": [59, 60], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.add_managed_account": {"executed_lines": [63, 64], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.modify_entry": {"executed_lines": [69], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "setup_module": {"executed_lines": [73, 74, 76], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostr.list_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [81], "excluded_lines": []}, "FakeNostr.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [84], "excluded_lines": []}, "FakeNostr.remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [87], "excluded_lines": []}, "test_unlock_creates_main_window": {"executed_lines": [91, 92, 93, 94, 95, 96, 97, 99, 100, 101], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entrydialog_add_calls_service": {"executed_lines": [118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 135, 136, 137, 138], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entrydialog_edit_calls_service": {"executed_lines": [150, 151, 153, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entrydialog_edit_calls_service.retrieve": {"executed_lines": [154], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 8, 10, 13, 14, 17, 21, 22, 26, 29, 32, 36, 42, 46, 50, 54, 58, 62, 66, 72, 79, 80, 83, 86, 90, 104, 117, 141, 149], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeVault": {"executed_lines": [15, 18], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries": {"executed_lines": [23, 24, 27, 33, 34, 39, 40, 43, 44, 47, 48, 51, 52, 55, 56, 59, 60, 63, 64, 69], "summary": {"covered_lines": 20, "num_statements": 21, "percent_covered": 95.23809523809524, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [30], "excluded_lines": []}, "FakeNostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [81, 84, 87], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 8, 10, 13, 14, 17, 21, 22, 26, 29, 32, 36, 42, 46, 50, 54, 58, 62, 66, 72, 73, 74, 76, 79, 80, 83, 86, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, 101, 104, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 135, 136, 137, 138, 141, 149, 150, 151, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170], "summary": {"covered_lines": 83, "num_statements": 83, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_gui_sync.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 11, 12, 13, 15, 19, 20, 21, 23, 24, 26, 30, 31, 32, 33, 34, 35, 36, 37, 40, 41, 42, 43, 46, 47, 49, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62, 63, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77], "summary": {"covered_lines": 54, "num_statements": 56, "percent_covered": 96.42857142857143, "percent_covered_display": "96", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [16, 27], "excluded_lines": [], "functions": {"DummyEntries.list_entries": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEntries.search_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [16], "excluded_lines": []}, "DummyNostr.__init__": {"executed_lines": [21], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyNostr.start_background_vault_sync": {"executed_lines": [24], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyNostr.list_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [27], "excluded_lines": []}, "DummyController.__init__": {"executed_lines": [32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "set_backend": {"executed_lines": [42, 43], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_vault_sync_schedules_task": {"executed_lines": [47, 49, 51, 54, 55, 56, 57, 59, 60, 61, 62, 63], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_vault_sync_schedules_task.create_task": {"executed_lines": [52], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_status_updates_on_bus_events": {"executed_lines": [67, 68, 69, 70, 71, 73, 74, 75, 76, 77], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 11, 12, 15, 19, 20, 23, 26, 30, 31, 40, 41, 46, 66], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEntries": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 2, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [16], "excluded_lines": []}, "DummyNostr": {"executed_lines": [21, 24], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [27], "excluded_lines": []}, "DummyController": {"executed_lines": [32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 11, 12, 15, 19, 20, 23, 26, 30, 31, 40, 41, 42, 43, 46, 47, 49, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62, 63, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77], "summary": {"covered_lines": 45, "num_statements": 45, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_handle_switch_fingerprint.py": {"executed_lines": [1, 4, 5, 6, 7, 9, 10, 12, 13, 15, 16, 17, 18, 19, 21, 25, 26, 28, 30, 31, 32], "summary": {"covered_lines": 21, "num_statements": 23, "percent_covered": 91.30434782608695, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [22, 23], "excluded_lines": [], "functions": {"test_handle_switch_fingerprint_active_profile": {"executed_lines": [5, 6, 9, 12, 15, 16, 21, 25, 26, 28, 30, 31, 32], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_switch_fingerprint_active_profile.DummyFingerprintManager.__init__": {"executed_lines": [7], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_switch_fingerprint_active_profile.DummyFingerprintManager.list_fingerprints": {"executed_lines": [10], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_switch_fingerprint_active_profile.DummyFingerprintManager.display_name": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_switch_fingerprint_active_profile.DummyPM.__init__": {"executed_lines": [17, 18, 19], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_switch_fingerprint_active_profile.DummyPM.select_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [22, 23], "excluded_lines": []}, "": {"executed_lines": [1, 4], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_handle_switch_fingerprint_active_profile.DummyFingerprintManager": {"executed_lines": [7, 10, 13], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_switch_fingerprint_active_profile.DummyPM": {"executed_lines": [17, 18, 19], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [22, 23], "excluded_lines": []}, "": {"executed_lines": [1, 4, 5, 6, 9, 12, 15, 16, 21, 25, 26, 28, 30, 31, 32], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_import.py": {"executed_lines": [3, 4, 6], "summary": {"covered_lines": 3, "num_statements": 7, "percent_covered": 42.857142857142854, "percent_covered_display": "43", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [7, 8, 9, 10], "excluded_lines": [], "functions": {"": {"executed_lines": [3, 4, 6], "summary": {"covered_lines": 3, "num_statements": 7, "percent_covered": 42.857142857142854, "percent_covered_display": "43", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [7, 8, 9, 10], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 4, 6], "summary": {"covered_lines": 3, "num_statements": 7, "percent_covered": 42.857142857142854, "percent_covered_display": "43", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [7, 8, 9, 10], "excluded_lines": []}}}, "src/tests/test_inactivity_lock.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13, 14, 16, 17, 19, 20, 22, 23, 24, 26, 41, 43, 44, 46, 47, 50, 52, 54, 55, 57, 58, 60, 61, 62, 64, 79, 81, 82, 83, 84, 85, 87, 89, 90, 92, 93, 96, 98, 100, 101, 103, 104, 105, 106, 107, 109, 110, 111, 113, 114, 116, 117, 118, 120, 121, 122], "summary": {"covered_lines": 63, "num_statements": 63, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_inactivity_triggers_lock": {"executed_lines": [14, 16, 19, 22, 26, 41, 43, 44, 46, 47], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_inactivity_triggers_lock.update_activity": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_inactivity_triggers_lock.lock_vault": {"executed_lines": [20], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_inactivity_triggers_lock.unlock_vault": {"executed_lines": [23, 24], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_input_timeout_triggers_lock": {"executed_lines": [52, 54, 57, 60, 64, 79, 81, 87, 89, 90, 92, 93], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_input_timeout_triggers_lock.update_activity": {"executed_lines": [55], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_input_timeout_triggers_lock.lock_vault": {"executed_lines": [58], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_input_timeout_triggers_lock.unlock_vault": {"executed_lines": [61, 62], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_input_timeout_triggers_lock.fake_input": {"executed_lines": [82, 83, 84, 85], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_activity_checks_timeout": {"executed_lines": [98, 100, 101, 103, 104, 105, 106, 107, 109, 113, 114, 116, 117, 118, 120, 121, 122], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_activity_checks_timeout.lock": {"executed_lines": [110, 111], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13, 50, 96], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13, 14, 16, 17, 19, 20, 22, 23, 24, 26, 41, 43, 44, 46, 47, 50, 52, 54, 55, 57, 58, 60, 61, 62, 64, 79, 81, 82, 83, 84, 85, 87, 89, 90, 92, 93, 96, 98, 100, 101, 103, 104, 105, 106, 107, 109, 110, 111, 113, 114, 116, 117, 118, 120, 121, 122], "summary": {"covered_lines": 63, "num_statements": 63, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_index_cache.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 19, 20, 22, 23, 24, 26, 27, 28, 30, 31, 32, 33], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_index_caching": {"executed_lines": [12, 13, 14, 15, 16, 19, 20, 22, 23, 24, 26, 27, 28, 30, 31, 32, 33], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 11], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 19, 20, 22, 23, 24, 26, 27, 28, 30, 31, 32, 33], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_index_import_export.py": {"executed_lines": [1, 2, 4, 5, 6, 7, 9, 11, 12, 13, 15, 16, 19, 20, 21, 22, 23, 25, 26, 27, 30, 31, 32, 33, 35, 48, 50, 51, 53, 68, 70, 71, 74, 75, 76], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_vault": {"executed_lines": [20, 21, 22, 23, 25, 26, 27], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_index_export_import_round_trip": {"executed_lines": [31, 32, 33, 35, 48, 50, 51, 53, 68, 70, 71], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_encrypted_index_missing_file": {"executed_lines": [75, 76], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 6, 7, 9, 11, 12, 13, 15, 16, 19, 30, 74], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 6, 7, 9, 11, 12, 13, 15, 16, 19, 20, 21, 22, 23, 25, 26, 27, 30, 31, 32, 33, 35, 48, 50, 51, 53, 68, 70, 71, 74, 75, 76], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_invalid_password_message.py": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_invalid_password_shows_friendly_message_once": {"executed_lines": [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_kdf_iteration_fallback.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 21, 22, 24, 25, 26, 27, 28, 29, 32, 33, 35, 36, 38, 39, 40, 41, 42, 43, 45, 49, 50, 51], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_kdf_iteration_fallback": {"executed_lines": [15, 16, 17, 18, 19, 21, 22, 24, 25, 26, 27, 28, 29, 32, 33, 35, 36, 38, 39, 40, 41, 42, 43, 45, 49, 50, 51], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 14], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 21, 22, 24, 25, 26, 27, 28, 29, 32, 33, 35, 36, 38, 39, 40, 41, 42, 43, 45, 49, 50, 51], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_kdf_modes.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 14, 15, 16, 17, 19, 20, 23, 24, 25, 26, 27, 33, 34, 36, 37, 44, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 60, 61, 62, 63, 64, 65, 66, 67, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 83, 84, 90, 91, 94, 95, 98, 99, 103, 104, 105, 106, 107, 110, 111, 112, 113, 114, 115, 116, 117, 118], "summary": {"covered_lines": 73, "num_statements": 73, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_setup_profile": {"executed_lines": [24, 25, 26, 27, 33, 34, 36, 37, 44, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_make_pm": {"executed_lines": [61, 62, 63, 64, 65, 66, 67], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_setup_encryption_manager_kdf_modes": {"executed_lines": [71, 72, 73, 74, 75, 76, 77, 78, 79, 83, 84, 90, 91, 94, 95], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_kdf_param_round_trip": {"executed_lines": [99, 103, 104, 105, 106, 107], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_kdf_migration": {"executed_lines": [111, 112, 113, 114, 115, 116, 117, 118], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 14, 15, 16, 17, 19, 20, 23, 60, 70, 98, 110], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 14, 15, 16, 17, 19, 20, 23, 24, 25, 26, 27, 33, 34, 36, 37, 44, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 60, 61, 62, 63, 64, 65, 66, 67, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 83, 84, 90, 91, 94, 95, 98, 99, 103, 104, 105, 106, 107, 110, 111, 112, 113, 114, 115, 116, 117, 118], "summary": {"covered_lines": 73, "num_statements": 73, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_kdf_strength_slider.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_kdf_strength_slider_persists": {"executed_lines": [11, 12, 13, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 10], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_key_derivation.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 28, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 45, 46, 47, 50, 51, 52, 53, 55, 59, 63, 64, 65, 67, 68, 69], "summary": {"covered_lines": 43, "num_statements": 43, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_pbkdf2_fingerprint_affects_key": {"executed_lines": [17, 18, 19, 21, 22, 23, 25, 26, 27, 28], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_derive_key_empty_password_error": {"executed_lines": [32, 33, 34], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_seed_only_key_deterministic": {"executed_lines": [38, 39, 40, 41, 42], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_derive_index_key_seed_only": {"executed_lines": [46, 47], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_argon2_fingerprint_affects_key": {"executed_lines": [51, 52, 53, 55, 59, 63, 64, 65, 67, 68, 69], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 16, 31, 37, 45, 50], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 28, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 45, 46, 47, 50, 51, 52, 53, 55, 59, 63, 64, 65, 67, 68, 69], "summary": {"covered_lines": 43, "num_statements": 43, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_key_hierarchy.py": {"executed_lines": [1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_kd_distinct_infos": {"executed_lines": [8, 9, 10, 11], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_derive_index_key_matches_hierarchy": {"executed_lines": [15, 16, 17, 18, 19], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 7, 14], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_key_manager_helpers.py": {"executed_lines": [1, 2, 4, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19, 21, 23, 24, 26, 29], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_key_manager_getters": {"executed_lines": [8, 9, 11, 12, 15, 18, 19, 21, 23, 24, 26, 29], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_key_manager_getters.DummyKeys.public_key_hex": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_key_manager_getters.DummyKeys.private_key_hex": {"executed_lines": [16], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 7], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_key_manager_getters.DummyKeys": {"executed_lines": [13, 16], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 7, 8, 9, 11, 12, 15, 18, 19, 21, 23, 24, 26, 29], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_key_validation_failures.py": {"executed_lines": [1, 2, 4, 6, 7, 8, 11, 12, 13, 14, 15, 18, 19, 20, 21, 24, 25, 26, 29, 30, 33, 34, 35, 38, 39, 42, 43, 44, 47, 48, 51, 52, 53, 56, 57, 60, 61, 62, 65, 66], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_mgr": {"executed_lines": [12, 13, 14, 15], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_totp_invalid_secret": {"executed_lines": [19, 20, 21], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_ssh_key_validation_failure": {"executed_lines": [25, 26, 29, 30], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_pgp_key_validation_failure": {"executed_lines": [34, 35, 38, 39], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_nostr_key_validation_failure": {"executed_lines": [43, 44, 47, 48], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_seed_validation_failure": {"executed_lines": [52, 53, 56, 57], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_managed_account_validation_failure": {"executed_lines": [61, 62, 65, 66], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 8, 11, 18, 24, 33, 42, 51, 60], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 7, 8, 11, 12, 13, 14, 15, 18, 19, 20, 21, 24, 25, 26, 29, 30, 33, 34, 35, 38, 39, 42, 43, 44, 47, 48, 51, 52, 53, 56, 57, 60, 61, 62, 65, 66], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_key_value_entry.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 24, 26, 27, 28, 41, 44, 45, 46, 47, 50, 51, 52, 53, 54, 59, 60, 61, 62, 65, 66], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_entry_mgr": {"executed_lines": [15, 16, 17, 18], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_and_modify_key_value": {"executed_lines": [22, 23, 24, 26, 27, 28, 41, 44, 45, 46, 47, 50, 51, 52, 53, 54, 59, 60, 61, 62, 65, 66], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 21], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 24, 26, 27, 28, 41, 44, 45, 46, 47, 50, 51, 52, 53, 54, 59, 60, 61, 62, 65, 66], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_last_used_fingerprint.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 13, 14, 15, 16, 18, 19, 21, 22, 23, 26, 27, 29, 30, 32, 35, 40, 43, 46, 51, 54, 59, 60], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_last_used_fingerprint": {"executed_lines": [14, 15, 16, 18, 19, 21, 22, 23, 26, 27, 29, 32, 35, 40, 43, 46, 51, 54, 59, 60], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_last_used_fingerprint.init_fm": {"executed_lines": [30], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 13], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 13, 14, 15, 16, 18, 19, 21, 22, 23, 26, 27, 29, 30, 32, 35, 40, 43, 46, 51, 54, 59, 60], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_legacy_format_exception.py": {"executed_lines": [1, 2, 4, 5, 7, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 29, 30, 31, 33, 34, 36, 37, 41, 42, 43], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_decrypt_data_raises_legacy_exception": {"executed_lines": [16, 17, 18, 19], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_handles_legacy_exception": {"executed_lines": [23, 24, 25, 26, 29, 30, 31, 33, 34, 36, 37, 41, 42, 43], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 7, 12, 15, 22], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 7, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 29, 30, 31, 33, 34, 36, 37, 41, 42, 43], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_legacy_migration.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 13, 15, 16, 17, 20, 21, 23, 24, 39, 40, 41, 42, 46, 48, 49, 51, 52, 53, 54, 55, 56, 59, 60, 62, 63, 64, 65, 66, 67, 68, 70, 72, 75, 77, 78, 81, 82, 83, 84, 87, 88, 90, 91, 92, 93, 94, 95, 99, 101, 103, 104, 105, 106, 109, 110, 112, 113, 114, 116, 117, 118, 122, 123, 125, 128, 129, 130, 133, 134, 136, 137, 138, 141, 142, 144, 145, 146, 147, 148, 150, 152, 153, 154, 155, 156, 157, 158, 159, 160, 162, 163, 164, 165, 166, 167, 169, 170, 176, 179, 181, 182, 183, 186, 187, 189, 190, 191, 192, 193, 195, 197, 198, 199, 200, 201, 202, 203, 204, 206, 207, 213, 216, 218, 219, 220, 223, 224, 226, 227, 228, 229, 231, 232, 233, 234, 235, 237, 238, 240, 244, 247, 248, 249, 250, 251, 252, 253, 254, 255, 257, 259, 260, 261, 263, 264, 266, 267, 268, 269, 272, 273, 275, 276, 277, 278, 279, 281, 283, 284, 285, 286, 287, 288, 289, 290, 291, 293, 297, 298, 304, 306, 307, 309, 310, 313, 314, 316, 317, 318, 319, 321, 322, 323, 324, 325, 326, 327, 328, 329, 331, 332, 333, 334, 335, 336, 338, 340, 346, 350, 354, 356, 357, 358, 359, 362, 363, 365, 366, 367, 368, 369, 371, 373, 374, 375, 376, 377, 378, 379, 380, 382, 384, 388, 390, 391, 393, 396, 397, 399, 400, 401, 402, 403, 405, 407, 408, 410, 412, 413, 414, 415, 416, 417, 418, 419, 421, 423, 427, 429, 430, 432], "summary": {"covered_lines": 271, "num_statements": 279, "percent_covered": 97.1326164874552, "percent_covered_display": "97", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [73, 245, 351, 352, 385, 386, 424, 425], "excluded_lines": [], "functions": {"test_legacy_index_migrates": {"executed_lines": [21, 23, 24, 39, 40, 41, 42, 46, 48, 49, 51, 52, 53, 54, 55, 56], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_failed_migration_restores_legacy": {"executed_lines": [60, 62, 63, 64, 65, 66, 67, 68, 70, 72, 75, 77, 78, 81, 82, 83, 84], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_failed_migration_restores_legacy.bad_load_json": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [73], "excluded_lines": []}, "test_migrated_index_has_v3_prefix": {"executed_lines": [88, 90, 91, 92, 93, 94, 95, 99, 101, 103, 104, 105, 106], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_index_migration_removes_strays": {"executed_lines": [110, 112, 113, 114, 116, 117, 118, 122, 123, 125, 128, 129, 130, 133, 134, 136, 137, 138], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migration_syncs_when_confirmed": {"executed_lines": [142, 144, 145, 146, 147, 148, 150, 152, 153, 154, 155, 156, 157, 158, 159, 160, 162, 163, 164, 165, 166, 167, 169, 170, 176, 179, 181, 182, 183], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migration_declines_sync": {"executed_lines": [187, 189, 190, 191, 192, 193, 195, 197, 198, 199, 200, 201, 202, 203, 204, 206, 207, 213, 216, 218, 219, 220], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_nostr_payload_syncs_when_confirmed": {"executed_lines": [224, 226, 227, 228, 229, 231, 232, 237, 244, 247, 248, 249, 250, 251, 252, 253, 254, 255, 257, 259, 263, 264, 266, 267, 268, 269], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_nostr_payload_syncs_when_confirmed.DummyClient.__init__": {"executed_lines": [233, 234, 235], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_nostr_payload_syncs_when_confirmed.DummyClient.fetch_latest_snapshot": {"executed_lines": [238, 240], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_nostr_payload_syncs_when_confirmed.DummyClient.fetch_deltas_since": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [245], "excluded_lines": []}, "test_legacy_nostr_payload_syncs_when_confirmed.fake_sync_vault_async": {"executed_lines": [260, 261], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_index_reinit_syncs_once_when_confirmed": {"executed_lines": [273, 275, 276, 277, 278, 279, 281, 283, 284, 285, 286, 287, 288, 289, 290, 291, 293, 297, 298, 304, 306, 307, 309, 310], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_schema_migration_no_sync_prompt": {"executed_lines": [314, 316, 317, 318, 319, 321, 322, 323, 324, 325, 326, 327, 328, 329, 331, 332, 333, 334, 335, 336, 338, 340, 346, 350, 354, 356, 357, 358, 359], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_schema_migration_no_sync_prompt.fake_confirm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [351, 352], "excluded_lines": []}, "test_declined_migration_no_sync_prompt": {"executed_lines": [363, 365, 366, 367, 368, 369, 371, 373, 374, 375, 376, 377, 378, 379, 380, 382, 384, 388, 390, 391, 393], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_declined_migration_no_sync_prompt.fake_confirm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [385, 386], "excluded_lines": []}, "test_failed_migration_no_sync_prompt": {"executed_lines": [397, 399, 400, 401, 402, 403, 405, 407, 410, 412, 413, 414, 415, 416, 417, 418, 419, 421, 423, 427, 429, 430, 432], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_failed_migration_no_sync_prompt.fail": {"executed_lines": [408], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_failed_migration_no_sync_prompt.fake_confirm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [424, 425], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 13, 15, 16, 17, 20, 59, 87, 109, 141, 186, 223, 272, 313, 362, 396], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_legacy_nostr_payload_syncs_when_confirmed.DummyClient": {"executed_lines": [233, 234, 235, 238, 240], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [245], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 13, 15, 16, 17, 20, 21, 23, 24, 39, 40, 41, 42, 46, 48, 49, 51, 52, 53, 54, 55, 56, 59, 60, 62, 63, 64, 65, 66, 67, 68, 70, 72, 75, 77, 78, 81, 82, 83, 84, 87, 88, 90, 91, 92, 93, 94, 95, 99, 101, 103, 104, 105, 106, 109, 110, 112, 113, 114, 116, 117, 118, 122, 123, 125, 128, 129, 130, 133, 134, 136, 137, 138, 141, 142, 144, 145, 146, 147, 148, 150, 152, 153, 154, 155, 156, 157, 158, 159, 160, 162, 163, 164, 165, 166, 167, 169, 170, 176, 179, 181, 182, 183, 186, 187, 189, 190, 191, 192, 193, 195, 197, 198, 199, 200, 201, 202, 203, 204, 206, 207, 213, 216, 218, 219, 220, 223, 224, 226, 227, 228, 229, 231, 232, 237, 244, 247, 248, 249, 250, 251, 252, 253, 254, 255, 257, 259, 260, 261, 263, 264, 266, 267, 268, 269, 272, 273, 275, 276, 277, 278, 279, 281, 283, 284, 285, 286, 287, 288, 289, 290, 291, 293, 297, 298, 304, 306, 307, 309, 310, 313, 314, 316, 317, 318, 319, 321, 322, 323, 324, 325, 326, 327, 328, 329, 331, 332, 333, 334, 335, 336, 338, 340, 346, 350, 354, 356, 357, 358, 359, 362, 363, 365, 366, 367, 368, 369, 371, 373, 374, 375, 376, 377, 378, 379, 380, 382, 384, 388, 390, 391, 393, 396, 397, 399, 400, 401, 402, 403, 405, 407, 408, 410, 412, 413, 414, 415, 416, 417, 418, 419, 421, 423, 427, 429, 430, 432], "summary": {"covered_lines": 266, "num_statements": 273, "percent_covered": 97.43589743589743, "percent_covered_display": "97", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [73, 351, 352, 385, 386, 424, 425], "excluded_lines": []}}}, "src/tests/test_legacy_migration_iterations.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 31, 32, 33, 35, 36, 37, 39, 41, 42, 43, 45, 46, 47, 49, 50, 52, 53, 54, 56, 58, 60, 62, 63, 64, 66, 67, 69, 70], "summary": {"covered_lines": 48, "num_statements": 48, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_setup_legacy_file": {"executed_lines": [23, 24, 25, 26, 27, 28], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migrate_iterations": {"executed_lines": [33, 35, 36, 37, 39, 41, 45, 46, 47, 49, 50, 52, 56, 58, 60, 62, 63, 64, 66, 67, 69, 70], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migrate_iterations.fake_prompt": {"executed_lines": [42, 43], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migrate_iterations.tracking_derive": {"executed_lines": [53, 54], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 17, 18, 19, 22, 31, 32], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 31, 32, 33, 35, 36, 37, 39, 41, 42, 43, 45, 46, 47, 49, 50, 52, 53, 54, 56, 58, 60, 62, 63, 64, 66, 67, 69, 70], "summary": {"covered_lines": 48, "num_statements": 48, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_legacy_migration_prompt.py": {"executed_lines": [1, 2, 3, 5, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 25, 26, 27, 28, 29, 30, 31, 34, 35, 36, 37, 38, 41, 42, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 55], "summary": {"covered_lines": 41, "num_statements": 41, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_setup_legacy_file": {"executed_lines": [15, 16, 17, 18, 19, 20, 21, 22], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_open_legacy_without_migrating": {"executed_lines": [26, 27, 28, 29, 30, 31, 34, 35, 36, 37, 38], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migrate_legacy_sets_flag": {"executed_lines": [42, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 55], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 9, 10, 11, 14, 25, 41], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 25, 26, 27, 28, 29, 30, 31, 34, 35, 36, 37, 38, 41, 42, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 55], "summary": {"covered_lines": 41, "num_statements": 41, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_legacy_migration_second_session.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 32, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 58, 59, 63, 64, 65], "summary": {"covered_lines": 45, "num_statements": 45, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [55, 56], "functions": {"test_legacy_migration_second_session": {"executed_lines": [18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 32, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 58, 59, 63, 64, 65], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [55]}, "test_legacy_migration_second_session.fail_prompt": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [56]}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 17], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 32, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 58, 59, 63, 64, 65], "summary": {"covered_lines": 45, "num_statements": 45, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [55, 56]}}}, "src/tests/test_list_entries_all_types.py": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 44, 45, 48, 49, 50, 51, 52, 54, 55, 63, 65, 66, 67, 68, 69, 70, 73, 74, 75, 76, 77, 79, 80, 82, 83, 84, 85], "summary": {"covered_lines": 62, "num_statements": 62, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_setup_manager": {"executed_lines": [19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_create_all_entries": {"executed_lines": [38, 39, 40, 41, 42, 43, 44, 45], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_list_all_types": {"executed_lines": [49, 50, 51, 52, 54, 63, 65, 66, 67, 68, 69, 70], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_list_all_types.fake_get_entry_service": {"executed_lines": [55], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_list_all_types": {"executed_lines": [74, 75, 76, 77, 79, 80, 82, 83, 84, 85], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 15, 18, 37, 48, 73], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 44, 45, 48, 49, 50, 51, 52, 54, 55, 63, 65, 66, 67, 68, 69, 70, 73, 74, 75, 76, 77, 79, 80, 82, 83, 84, 85], "summary": {"covered_lines": 62, "num_statements": 62, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_list_entries_sort_filter.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 47, 48, 54, 55, 56, 57, 58, 59, 60, 61], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_entry_manager": {"executed_lines": [16, 17, 18, 19], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sort_by_label": {"executed_lines": [23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sort_by_updated": {"executed_lines": [36, 37, 38, 39, 40, 42, 43, 44, 45, 47, 48], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_filter_by_type": {"executed_lines": [55, 56, 57, 58, 59, 60, 61], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 22, 35, 54], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 47, 48, 54, 55, 56, 57, 58, 59, 60, 61], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_load_global_config.py": {"executed_lines": [1, 3, 4, 6, 8, 11, 13, 14, 15, 16, 18, 20, 21, 23, 24], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_load_global_config_invalid_toml": {"executed_lines": [13, 14, 15, 16, 18, 20, 21, 23, 24], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 6, 8, 11], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 6, 8, 11, 13, 14, 15, 16, 18, 20, 21, 23, 24], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_managed_account.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 12, 13, 14, 17, 18, 19, 20, 21, 24, 25, 26, 27, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 46, 47, 48, 49, 50, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 78, 79, 80, 81, 83, 85, 86, 87], "summary": {"covered_lines": 69, "num_statements": 69, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_entry_manager": {"executed_lines": [18, 19, 20, 21], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_managed_account_fields_and_dir": {"executed_lines": [25, 26, 27, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_load_and_exit_managed_account": {"executed_lines": [47, 48, 49, 50, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 78, 79, 80, 81, 83, 85, 86, 87], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 12, 13, 14, 17, 24, 46], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 12, 13, 14, 17, 18, 19, 20, 21, 24, 25, 26, 27, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 46, 47, 48, 49, 50, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 78, 79, 80, 81, 83, 85, 86, 87], "summary": {"covered_lines": 69, "num_statements": 69, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_managed_account_entry.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 12, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 45, 47, 48, 49, 51, 52, 53, 54, 55, 58, 59, 60, 61, 62, 67, 68, 69, 70, 71, 72, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 105, 107, 108, 109, 110, 112, 114, 115, 116], "summary": {"covered_lines": 90, "num_statements": 90, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_mgr": {"executed_lines": [21, 22, 23, 24], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_and_get_managed_account_seed": {"executed_lines": [28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 45, 47, 48, 49, 51, 52, 53, 54, 55, 58, 59, 60, 61, 62, 67, 68, 69, 70, 71, 72], "summary": {"covered_lines": 34, "num_statements": 34, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_load_and_exit_managed_account": {"executed_lines": [76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 105, 107, 108, 109, 110, 112, 114, 115, 116], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 12, 13, 14, 15, 16, 17, 20, 27, 75], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 12, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 45, 47, 48, 49, 51, 52, 53, 54, 55, 58, 59, 60, 61, 62, 67, 68, 69, 70, 71, 72, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 105, 107, 108, 109, 110, 112, 114, 115, 116], "summary": {"covered_lines": 90, "num_statements": 90, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_add_password.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 13, 14, 15, 16, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 66, 67, 68, 70, 71, 73, 74, 76, 77, 90, 93, 94, 95, 96, 97, 98, 99, 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 136, 137, 138, 140, 141, 146, 147, 149, 150, 151, 154, 155, 156, 157, 158, 159, 160, 161, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 176, 186, 187, 188, 190, 191, 193, 194, 196, 197, 210, 213, 216, 217, 218, 219, 220, 221, 222, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 237, 249, 250, 251, 253, 254, 256, 257, 258, 259, 260, 261, 264, 267, 268, 269, 270, 271, 272, 273, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 288, 299, 300, 301, 303, 304, 306, 307, 308, 311, 312, 313, 314, 315, 316, 317, 318, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 333, 334, 335, 337, 338], "summary": {"covered_lines": 195, "num_statements": 195, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakePasswordGenerator.generate_password": {"executed_lines": [21], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_add_password": {"executed_lines": [25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 66, 67, 68, 70, 71, 73, 74, 76, 77, 90], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_add_password_secret_mode": {"executed_lines": [94, 95, 96, 97, 98, 99, 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 136, 137, 138, 140, 141, 146, 147, 149, 150, 151], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_add_password_quick_mode": {"executed_lines": [155, 156, 157, 158, 159, 160, 161, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 176, 186, 187, 188, 190, 191, 193, 194, 196, 197, 210], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_add_password_quick_mode_reprompts_invalid_length": {"executed_lines": [216, 217, 218, 219, 220, 221, 222, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 237, 249, 250, 251, 253, 254, 256, 257, 258, 259, 260, 261], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_add_password_reprompts_invalid_mode": {"executed_lines": [267, 268, 269, 270, 271, 272, 273, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 288, 299, 300, 301, 303, 304, 306, 307, 308], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_add_password_empty_mode_cancels": {"executed_lines": [312, 313, 314, 315, 316, 317, 318, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 333, 334, 335, 337, 338], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 13, 14, 15, 16, 19, 20, 24, 93, 154, 213, 264, 311], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakePasswordGenerator": {"executed_lines": [21], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 13, 14, 15, 16, 19, 20, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 66, 67, 68, 70, 71, 73, 74, 76, 77, 90, 93, 94, 95, 96, 97, 98, 99, 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 136, 137, 138, 140, 141, 146, 147, 149, 150, 151, 154, 155, 156, 157, 158, 159, 160, 161, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 176, 186, 187, 188, 190, 191, 193, 194, 196, 197, 210, 213, 216, 217, 218, 219, 220, 221, 222, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 237, 249, 250, 251, 253, 254, 256, 257, 258, 259, 260, 261, 264, 267, 268, 269, 270, 271, 272, 273, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 288, 299, 300, 301, 303, 304, 306, 307, 308, 311, 312, 313, 314, 315, 316, 317, 318, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 333, 334, 335, 337, 338], "summary": {"covered_lines": 194, "num_statements": 194, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_add_totp.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 18, 20, 21, 22, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 54, 55, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70], "summary": {"covered_lines": 47, "num_statements": 47, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakeNostrClient.__init__": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostrClient.publish_snapshot": {"executed_lines": [21, 22], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_add_totp": {"executed_lines": [26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 54, 55, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 20, 25], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeNostrClient": {"executed_lines": [18, 21, 22], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 20, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 54, 55, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70], "summary": {"covered_lines": 44, "num_statements": 44, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_checksum_backup.py": {"executed_lines": [1, 2, 4, 6, 7, 10, 11, 12, 14, 15, 17, 18, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 41, 42, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 56, 57, 59, 60, 61, 62, 63, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77], "summary": {"covered_lines": 59, "num_statements": 59, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakeBackupManager.__init__": {"executed_lines": [12], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeBackupManager.create_backup": {"executed_lines": [15], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeBackupManager.restore_latest_backup": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_make_pm": {"executed_lines": [22, 23, 24, 25], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_verify_checksum_success": {"executed_lines": [29, 30, 31, 32, 33, 34, 35, 36], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_verify_checksum_failure": {"executed_lines": [40, 41, 42, 43, 44, 45, 46, 47], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_verify_checksum_missing": {"executed_lines": [51, 52, 53, 54, 56, 59, 60, 61, 62, 63], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_verify_checksum_missing.raise_missing": {"executed_lines": [57], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_backup_and_restore_database": {"executed_lines": [67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 10, 11, 14, 17, 21, 28, 39, 50, 66], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeBackupManager": {"executed_lines": [12, 15, 18], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 10, 11, 14, 17, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 41, 42, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 56, 57, 59, 60, 61, 62, 63, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77], "summary": {"covered_lines": 56, "num_statements": 56, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_current_notification.py": {"executed_lines": [1, 3, 4, 6, 8, 9, 12, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 38, 39, 41, 42, 44, 45], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [13, 14, 15, 16, 17], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_notify_sets_current": {"executed_lines": [21, 22, 23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_current_notification_ttl": {"executed_lines": [33, 34, 35, 36, 38, 39, 41, 42, 44, 45], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 6, 8, 9, 12, 20, 32], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 6, 8, 9, 12, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 38, 39, 41, 42, 44, 45], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_display_totp_codes.py": {"executed_lines": [1, 2, 4, 6, 9, 10, 11, 13, 18, 19, 20, 22, 24, 28, 31, 36, 37, 38, 39, 40, 43, 44, 45, 47, 48, 49, 51, 55, 57, 62, 63, 64, 65], "summary": {"covered_lines": 33, "num_statements": 35, "percent_covered": 94.28571428571429, "percent_covered_display": "94", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [14, 15], "excluded_lines": [], "functions": {"FakeNostrClient.__init__": {"executed_lines": [11], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostrClient.publish_snapshot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [14, 15], "excluded_lines": []}, "test_handle_display_totp_codes": {"executed_lines": [19, 20, 22, 24, 28, 31, 36, 37, 38, 39, 40], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_display_totp_codes_excludes_archived": {"executed_lines": [44, 45, 47, 48, 49, 51, 55, 57, 62, 63, 64, 65], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 9, 10, 13, 18, 43], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeNostrClient": {"executed_lines": [11], "summary": {"covered_lines": 1, "num_statements": 3, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [14, 15], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 9, 10, 13, 18, 19, 20, 22, 24, 28, 31, 36, 37, 38, 39, 40, 43, 44, 45, 47, 48, 49, 51, 55, 57, 62, 63, 64, 65], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_edit_totp.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 19, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 46, 47, 48, 49, 52, 53, 55, 56, 57], "summary": {"covered_lines": 41, "num_statements": 43, "percent_covered": 95.34883720930233, "percent_covered_display": "95", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [20, 21], "excluded_lines": [], "functions": {"FakeNostrClient.__init__": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostrClient.publish_snapshot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [20, 21], "excluded_lines": []}, "test_edit_totp_period_from_retrieve": {"executed_lines": [25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 46, 47, 48, 49, 52, 53, 55, 56, 57], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 19, 24], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeNostrClient": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 3, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [20, 21], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 19, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 46, 47, 48, 49, 52, 53, 55, 56, 57], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_import_database.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 28, 31, 32, 36, 37, 38, 39, 42, 43, 45, 46, 48, 49, 53, 54, 55], "summary": {"covered_lines": 36, "num_statements": 37, "percent_covered": 97.29729729729729, "percent_covered_display": "97", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [29], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [12, 13, 14, 15, 16, 17, 18, 19, 20, 21], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_import_non_backup_file": {"executed_lines": [25, 26, 28, 31, 32, 36, 37, 38, 39], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_import_non_backup_file.fake_import": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [29], "excluded_lines": []}, "test_import_missing_file": {"executed_lines": [43, 45, 48, 49, 53, 54, 55], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_import_missing_file.raise_missing": {"executed_lines": [46], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 24, 42], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 28, 31, 32, 36, 37, 38, 39, 42, 43, 45, 46, 48, 49, 53, 54, 55], "summary": {"covered_lines": 36, "num_statements": 37, "percent_covered": 97.29729729729729, "percent_covered_display": "97", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [29], "excluded_lines": []}}}, "src/tests/test_manager_list_entries.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 47, 48, 49, 50, 51, 52, 55, 56, 57, 58, 59, 60, 61, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 78, 79, 82, 83, 88, 89, 91, 92, 93, 94, 95, 96, 99, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113, 114, 115, 116, 118, 120, 121, 126, 127, 132, 137, 138, 141, 142, 144, 146, 147, 150, 151, 152, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 169, 170, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 190, 192, 194, 195, 196, 197, 198, 199, 200, 203, 204, 205, 206, 207, 208, 209, 210, 211, 213, 215, 216, 217, 218, 219, 220, 221, 222, 225, 226, 227, 228, 229, 230, 232, 234, 235, 236, 237, 238, 239, 240, 241, 242, 245, 246, 247, 248, 249, 251, 253, 254, 255, 256, 257, 258, 261, 262, 263, 264, 265, 266, 268, 270, 271, 272, 273, 274, 275, 276, 277, 280, 293, 295, 296, 297, 298, 300, 303, 306, 307, 308, 311, 315, 317, 318, 320, 321, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 352, 355, 356, 357, 358, 360, 361, 363, 364, 365, 366, 367, 368, 371, 374, 376, 377, 378, 380, 381, 382, 383, 384, 385, 386, 390, 393, 395, 396, 398, 399, 400, 402, 403, 404, 405, 406], "summary": {"covered_lines": 282, "num_statements": 282, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_handle_list_entries": {"executed_lines": [21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 47, 48, 49, 50, 51, 52], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_list_entries_show_details": {"executed_lines": [56, 57, 58, 59, 60, 61, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 78, 79, 82, 83, 88, 89, 91, 92, 93, 94, 95, 96], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_entry_details_by_index": {"executed_lines": [101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113, 114, 115, 116, 118, 120, 121, 126, 127, 132, 137, 138, 141, 142, 144, 146, 147], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_setup_manager": {"executed_lines": [151, 152, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_detail_common": {"executed_lines": [170, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_seed_entry_details": {"executed_lines": [187, 188, 189, 190, 192, 194, 195, 196, 197, 198, 199, 200], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_ssh_entry_details": {"executed_lines": [204, 205, 206, 207, 208, 209, 210, 211, 213, 215, 216, 217, 218, 219, 220, 221, 222], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_pgp_entry_details": {"executed_lines": [226, 227, 228, 229, 230, 232, 234, 235, 236, 237, 238, 239, 240, 241, 242], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_nostr_entry_details": {"executed_lines": [246, 247, 248, 249, 251, 253, 254, 255, 256, 257, 258], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_managed_account_entry_details": {"executed_lines": [262, 263, 264, 265, 266, 268, 270, 271, 272, 273, 274, 275, 276, 277], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_entry_details_sensitive": {"executed_lines": [295, 296, 297, 298, 300, 303, 306, 307, 308, 311, 315, 317, 318, 320, 321, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 352, 355, 356, 357, 358, 360, 361, 363, 364, 365, 366, 367, 368], "summary": {"covered_lines": 52, "num_statements": 52, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_entry_details_with_enum_type": {"executed_lines": [376, 377, 378, 380, 381, 382, 383, 384, 385, 386, 390, 393, 395, 396, 398, 399, 400, 402, 403, 404, 405, 406], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 13, 14, 15, 16, 17, 20, 55, 99, 150, 169, 186, 203, 225, 245, 261, 280, 293, 371, 374], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 47, 48, 49, 50, 51, 52, 55, 56, 57, 58, 59, 60, 61, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 78, 79, 82, 83, 88, 89, 91, 92, 93, 94, 95, 96, 99, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113, 114, 115, 116, 118, 120, 121, 126, 127, 132, 137, 138, 141, 142, 144, 146, 147, 150, 151, 152, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 169, 170, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 190, 192, 194, 195, 196, 197, 198, 199, 200, 203, 204, 205, 206, 207, 208, 209, 210, 211, 213, 215, 216, 217, 218, 219, 220, 221, 222, 225, 226, 227, 228, 229, 230, 232, 234, 235, 236, 237, 238, 239, 240, 241, 242, 245, 246, 247, 248, 249, 251, 253, 254, 255, 256, 257, 258, 261, 262, 263, 264, 265, 266, 268, 270, 271, 272, 273, 274, 275, 276, 277, 280, 293, 295, 296, 297, 298, 300, 303, 306, 307, 308, 311, 315, 317, 318, 320, 321, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 352, 355, 356, 357, 358, 360, 361, 363, 364, 365, 366, 367, 368, 371, 374, 376, 377, 378, 380, 381, 382, 383, 384, 385, 386, 390, 393, 395, 396, 398, 399, 400, 402, 403, 404, 405, 406], "summary": {"covered_lines": 282, "num_statements": 282, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_retrieve_totp.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 19, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 46, 47, 48, 52, 55, 56, 61, 62, 63, 64], "summary": {"covered_lines": 42, "num_statements": 44, "percent_covered": 95.45454545454545, "percent_covered_display": "95", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [20, 21], "excluded_lines": [], "functions": {"FakeNostrClient.__init__": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostrClient.publish_snapshot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [20, 21], "excluded_lines": []}, "test_handle_retrieve_totp_entry": {"executed_lines": [25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 46, 47, 48, 52, 55, 56, 61, 62, 63, 64], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 19, 24], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeNostrClient": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 3, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [20, 21], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 19, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 46, 47, 48, 52, 55, 56, 61, 62, 63, 64], "summary": {"covered_lines": 41, "num_statements": 41, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_search_display.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 37, 38, 41, 42, 44, 45, 47, 48, 49, 50, 51], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_search_entries_prompt_for_details": {"executed_lines": [17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 37, 38, 41, 42, 44, 45, 47, 48, 49, 50, 51], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 37, 38, 41, 42, 44, 45, 47, 48, 49, 50, 51], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_seed_setup.py": {"executed_lines": [1, 2, 3, 4, 7, 8, 9, 10, 13, 14, 16, 19, 20, 21, 22, 25, 26, 27, 28, 29, 30, 35, 36, 38, 39, 41, 42, 45, 46, 47, 49, 51, 52, 53, 55, 56, 62, 63, 65, 66, 67, 70, 71, 72, 74, 76, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91], "summary": {"covered_lines": 56, "num_statements": 56, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_validate_bip85_seed_invalid_word": {"executed_lines": [8, 9, 10], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_validate_bip85_seed_checksum_failure": {"executed_lines": [14, 16, 19, 20, 21, 22], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_setup_existing_seed_words": {"executed_lines": [26, 27, 28, 29, 30, 35, 36, 38, 39, 41, 42], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_setup_existing_seed_paste": {"executed_lines": [46, 47, 49, 51, 55, 56, 62, 63, 65, 66, 67], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_setup_existing_seed_paste.fake_masked_input": {"executed_lines": [52, 53], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_setup_existing_seed_with_args": {"executed_lines": [71, 72, 74, 76, 81, 86, 87, 88, 89, 90, 91], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_setup_existing_seed_with_args.finalize": {"executed_lines": [82, 83, 84], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 7, 13, 25, 45, 70], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 7, 8, 9, 10, 13, 14, 16, 19, 20, 21, 22, 25, 26, 27, 28, 29, 30, 35, 36, 38, 39, 41, 42, 45, 46, 47, 49, 51, 52, 53, 55, 56, 62, 63, 65, 66, 67, 70, 71, 72, 74, 76, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91], "summary": {"covered_lines": 56, "num_statements": 56, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_warning_notifications.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 34, 35, 36, 39, 40, 42, 43, 44, 45], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_search_entries_no_query": {"executed_lines": [35, 36, 39, 40, 42, 43, 44, 45], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 34], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 34, 35, 36, 39, 40, 42, 43, 44, 45], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_workflow.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 16, 17, 20, 21, 22, 24, 25, 26, 29, 30, 31, 32, 33, 34, 35, 37, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 81, 83, 89, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111], "summary": {"covered_lines": 62, "num_statements": 62, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakePasswordGenerator.generate_password": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostrClient.__init__": {"executed_lines": [22], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostrClient.publish_snapshot": {"executed_lines": [25, 26], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_manager_workflow": {"executed_lines": [30, 31, 32, 33, 34, 35, 37, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 81, 83, 89, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 16, 20, 21, 24, 29], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakePasswordGenerator": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostrClient": {"executed_lines": [22, 25, 26], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 16, 20, 21, 24, 29, 30, 31, 32, 33, 34, 35, 37, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 81, 83, 89, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111], "summary": {"covered_lines": 58, "num_statements": 58, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manifest_id_privacy.py": {"executed_lines": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_published_events_no_fingerprint": {"executed_lines": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 4], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manifest_state_restore.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 68, 69, 70], "summary": {"covered_lines": 58, "num_statements": 58, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_init_pm": {"executed_lines": [15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_manifest_state_restored": {"executed_lines": [38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 68, 69, 70], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 14, 37], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 68, 69, 70], "summary": {"covered_lines": 58, "num_statements": 58, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_memory_protection.py": {"executed_lines": [1, 2, 4, 6, 8, 11, 12, 13, 14, 15, 18, 19, 20, 23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_inmemory_secret_round_trip_bytes_and_str": {"executed_lines": [12, 13, 14, 15], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_inmemory_secret_invalid_type": {"executed_lines": [19, 20], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_inmemory_secret_wipe_clears_attributes": {"executed_lines": [24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 8, 11, 18, 23], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 8, 11, 12, 13, 14, 15, 18, 19, 20, 23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_menu_navigation.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 38, 39, 40, 42, 43, 45, 46, 47, 48, 49], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_navigate_all_main_menu_options": {"executed_lines": [39, 40, 42, 43, 45, 46, 47, 48, 49], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 38], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 38, 39, 40, 42, 43, 45, 46, 47, 48, 49], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_menu_notifications.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 13, 14, 15, 16, 17, 42, 43, 44, 45, 53, 54, 55, 56, 57, 58, 61, 62, 63, 64, 65, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [14, 15, 16, 17], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_display_menu_prints_notifications": {"executed_lines": [43, 44, 45, 53, 54, 55, 56, 57, 58], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_display_menu_reuses_notification_line": {"executed_lines": [62, 63, 64, 65, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 13, 42, 61], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 13, 14, 15, 16, 17, 42, 43, 44, 45, 53, 54, 55, 56, 57, 58, 61, 62, 63, 64, 65, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_menu_options.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_totp_option": {"executed_lines": [33, 34, 35, 36, 37, 38, 39, 40], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_settings_option": {"executed_lines": [44, 45, 46, 47, 48, 49, 50, 51], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 32, 43], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_menu_search.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 29, 32, 33, 34, 35, 36, 37, 38, 39, 40], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [13, 29], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_search_option": {"executed_lines": [33, 34, 35, 36, 37, 38, 39, 40], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 32], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 29, 32, 33, 34, 35, 36, 37, 38, 39, 40], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_migrations.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 31, 34, 35, 36, 37, 38, 39, 40, 49, 52, 53, 54, 60, 61, 62, 63, 72, 75, 76, 77, 78, 79, 80, 83, 84, 85, 98, 99, 100, 101, 102, 104, 105, 106], "summary": {"covered_lines": 50, "num_statements": 50, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup": {"executed_lines": [12, 13], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migrate_v0_to_v4": {"executed_lines": [17, 18, 19, 20, 21, 22, 31], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migrate_v1_to_v4": {"executed_lines": [35, 36, 37, 38, 39, 40, 49], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migrate_v2_to_v4": {"executed_lines": [53, 54, 60, 61, 62, 63, 72], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_error_on_future_version": {"executed_lines": [76, 77, 78, 79, 80], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_schema_migration_persisted_once": {"executed_lines": [84, 85, 98, 99, 100, 101, 102, 104, 105, 106], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 16, 34, 52, 75, 83], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 31, 34, 35, 36, 37, 38, 39, 40, 49, 52, 53, 54, 60, 61, 62, 63, 72, 75, 76, 77, 78, 79, 80, 83, 84, 85, 98, 99, 100, 101, 102, 104, 105, 106], "summary": {"covered_lines": 50, "num_statements": 50, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_modify_ssh_managed_entries.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 24, 26, 27, 28, 30, 31, 32, 33, 36, 37, 38, 39, 41, 42, 50, 52, 53, 54, 55, 56], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_mgr": {"executed_lines": [15, 16, 17, 18], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_modify_ssh_entry": {"executed_lines": [22, 23, 24, 26, 27, 28, 30, 31, 32, 33], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_modify_managed_account_entry": {"executed_lines": [37, 38, 39, 41, 42, 50, 52, 53, 54, 55, 56], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 21, 36], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 24, 26, 27, 28, 30, 31, 32, 33, 36, 37, 38, 39, 41, 42, 50, 52, 53, 54, 55, 56], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_modify_totp_entry.py": {"executed_lines": [1, 2, 4, 5, 6, 9, 10, 11, 12, 13, 15, 16, 18, 19, 20, 21, 24, 25, 26, 27, 28, 30, 31, 32], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_modify_totp_entry_period_digits_and_archive": {"executed_lines": [10, 11, 12, 13, 15, 16, 18, 19, 20, 21], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_modify_totp_entry_invalid_field": {"executed_lines": [25, 26, 27, 28, 30, 31, 32], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 6, 9, 24], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 6, 9, 10, 11, 12, 13, 15, 16, 18, 19, 20, 21, 24, 25, 26, 27, 28, 30, 31, 32], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_multiple_deltas_sync.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 53, 54, 55, 57, 58, 59, 62, 63, 64, 65, 68, 69, 70, 71, 72, 73, 74, 75, 77, 78, 80, 81, 82, 84, 85, 86, 88, 89, 90, 93, 94, 95, 96], "summary": {"covered_lines": 71, "num_statements": 71, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_init_pm": {"executed_lines": [14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sync_applies_multiple_deltas": {"executed_lines": [33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 53, 54, 55, 57, 58, 59, 62, 63, 64, 65], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_initial_sync_applies_multiple_deltas": {"executed_lines": [69, 70, 71, 72, 73, 74, 75, 77, 78, 80, 81, 82, 84, 85, 86, 88, 89, 90, 93, 94, 95, 96], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 32, 68], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 53, 54, 55, 57, 58, 59, 62, 63, 64, 65, 68, 69, 70, 71, 72, 73, 74, 75, 77, 78, 80, 81, 82, 84, 85, 86, 88, 89, 90, 93, 94, 95, 96], "summary": {"covered_lines": 71, "num_statements": 71, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_multiple_fingerprint_prompt.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 11, 16, 17, 18, 19, 21, 22, 24, 25, 26, 28, 29, 31, 34, 39, 42, 45, 50, 54, 56, 57, 58, 60, 62, 63, 64], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_prompt_when_multiple_fingerprints": {"executed_lines": [17, 18, 19, 21, 22, 24, 25, 26, 28, 31, 34, 39, 42, 45, 50, 54, 56, 60, 62, 63, 64], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_prompt_when_multiple_fingerprints.init_fm": {"executed_lines": [29], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_prompt_when_multiple_fingerprints.fake_input": {"executed_lines": [57, 58], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 11, 16], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 11, 16, 17, 18, 19, 21, 22, 24, 25, 26, 28, 29, 31, 34, 39, 42, 45, 50, 54, 56, 57, 58, 60, 62, 63, 64], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_new_seed_profile_creation.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 13, 14, 15, 16, 17, 18, 19, 20, 24, 25, 26, 28, 29, 31, 32, 33, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 50, 52, 53, 54, 55], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_pm": {"executed_lines": [14, 15, 16, 17, 18, 19, 20, 24, 25, 28, 31, 32, 33, 36, 37, 38, 39, 40], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "setup_pm.DummyEnc.__init__": {"executed_lines": [26], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "setup_pm.DummyEnc.encrypt_parent_seed": {"executed_lines": [29], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_new_seed_creates_profile": {"executed_lines": [44, 45, 46, 47, 48, 50, 52, 53, 54, 55], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 13, 43], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"setup_pm.DummyEnc": {"executed_lines": [26, 29], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 13, 14, 15, 16, 17, 18, 19, 20, 24, 25, 28, 31, 32, 33, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 50, 52, 53, 54, 55], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nonce_uniqueness.py": {"executed_lines": [1, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_nonce_uniqueness": {"executed_lines": [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 8], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_noninteractive_init_unlock.py": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 28, 30, 32, 33, 34, 36, 39, 42, 46, 47, 50, 51, 52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 66, 67, 68, 69, 70, 72, 73, 75, 78, 81, 83, 84], "summary": {"covered_lines": 55, "num_statements": 55, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_init_with_password": {"executed_lines": [14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 28, 30, 32, 36, 39, 42, 46, 47], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_init_with_password.fake_setup": {"executed_lines": [33, 34], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_unlock_with_password": {"executed_lines": [51, 52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 66, 67, 68, 69, 70, 72, 75, 78, 81, 83, 84], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_unlock_with_password.fake_setup": {"executed_lines": [73], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 10, 13, 50], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 28, 30, 32, 33, 34, 36, 39, 42, 46, 47, 50, 51, 52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 66, 67, 68, 69, 70, 72, 73, 75, 78, 81, 83, 84], "summary": {"covered_lines": 55, "num_statements": 55, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_backup.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 30, 40, 41, 42, 44, 45], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_backup_and_publish_to_nostr": {"executed_lines": [18, 19, 20, 21, 22, 23, 26, 27, 28, 30, 40, 41, 42, 44, 45], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 17], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 30, 40, 41, 42, 44, 45], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_client.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 14, 15, 18, 19, 20, 21, 22, 24, 27, 28, 29, 31, 34, 35, 36, 37, 39, 40, 42, 43, 46, 47, 48, 49, 51, 52, 54, 55, 58, 59, 60, 62, 63, 65, 66, 68, 69, 71, 72, 73, 77, 78, 79, 81, 84, 85, 86, 87, 90, 91, 92, 93, 94, 95, 98, 99, 100, 101, 102, 103, 106, 107, 109, 111, 112, 113, 115, 116, 118, 119, 122, 123, 125, 127, 128, 130, 132, 134, 137, 138, 140, 142, 144, 145, 147, 149, 150, 152, 153, 154, 157, 158, 160, 161, 162, 163, 164, 165, 167, 169, 170, 172, 174, 175, 177, 179, 181, 182, 185, 186, 188, 189, 191, 192, 194, 195, 197, 198, 199, 201, 202, 203, 204, 205, 207], "summary": {"covered_lines": 136, "num_statements": 137, "percent_covered": 99.27007299270073, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [74], "excluded_lines": [], "functions": {"test_nostr_client_uses_custom_relays": {"executed_lines": [19, 20, 21, 22, 24, 27, 28, 29, 31], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeAddRelaysClient.__init__": {"executed_lines": [36, 37], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeAddRelaysClient.add_relays": {"executed_lines": [40], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeAddRelaysClient.connect": {"executed_lines": [43], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeAddRelayClient.__init__": {"executed_lines": [48, 49], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeAddRelayClient.add_relay": {"executed_lines": [52], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeAddRelayClient.connect": {"executed_lines": [55], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeWebSocket.__init__": {"executed_lines": [60], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeWebSocket.__aenter__": {"executed_lines": [63], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeWebSocket.__aexit__": {"executed_lines": [66], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeWebSocket.send": {"executed_lines": [69], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeWebSocket.recv": {"executed_lines": [72, 73], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [74], "excluded_lines": []}, "_setup_client": {"executed_lines": [78, 79, 81, 84, 85, 86, 87], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_initialize_client_pool_add_relays_used": {"executed_lines": [91, 92, 93, 94, 95], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_initialize_client_pool_add_relay_fallback": {"executed_lines": [99, 100, 101, 102, 103], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_check_relay_health_runs_async": {"executed_lines": [107, 109, 111, 115, 116, 118, 119], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_check_relay_health_runs_async.fake_check": {"executed_lines": [112, 113], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_ping_relay_accepts_eose": {"executed_lines": [123, 125, 127, 130, 132, 134], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_ping_relay_accepts_eose.fake_connect": {"executed_lines": [128], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_relays_reinitializes_pool": {"executed_lines": [138, 140, 142, 144, 147, 149, 150, 152, 153, 154], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_relays_reinitializes_pool.fake_init": {"executed_lines": [145], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_retrieve_json_sync_backoff": {"executed_lines": [158, 160, 161, 162, 163, 164, 165, 167, 169, 172, 174, 177, 179, 181, 182], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_retrieve_json_sync_backoff.fake_sleep": {"executed_lines": [170], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_retrieve_json_sync_backoff.fake_async": {"executed_lines": [175], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_client_methods_run_in_event_loop": {"executed_lines": [186, 188, 191, 194, 197, 198, 199, 201, 207], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_client_methods_run_in_event_loop.fake_init": {"executed_lines": [189], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_client_methods_run_in_event_loop.fake_send_event": {"executed_lines": [192], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_client_methods_run_in_event_loop.fake_retrieve": {"executed_lines": [195], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_client_methods_run_in_event_loop.run_all": {"executed_lines": [202, 203, 204, 205], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 14, 15, 18, 34, 35, 39, 42, 46, 47, 51, 54, 58, 59, 62, 65, 68, 71, 77, 90, 98, 106, 122, 137, 157, 185], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeAddRelaysClient": {"executed_lines": [36, 37, 40, 43], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeAddRelayClient": {"executed_lines": [48, 49, 52, 55], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeWebSocket": {"executed_lines": [60, 63, 66, 69, 72, 73], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [74], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 14, 15, 18, 19, 20, 21, 22, 24, 27, 28, 29, 31, 34, 35, 39, 42, 46, 47, 51, 54, 58, 59, 62, 65, 68, 71, 77, 78, 79, 81, 84, 85, 86, 87, 90, 91, 92, 93, 94, 95, 98, 99, 100, 101, 102, 103, 106, 107, 109, 111, 112, 113, 115, 116, 118, 119, 122, 123, 125, 127, 128, 130, 132, 134, 137, 138, 140, 142, 144, 145, 147, 149, 150, 152, 153, 154, 157, 158, 160, 161, 162, 163, 164, 165, 167, 169, 170, 172, 174, 175, 177, 179, 181, 182, 185, 186, 188, 189, 191, 192, 194, 195, 197, 198, 199, 201, 202, 203, 204, 205, 207], "summary": {"covered_lines": 122, "num_statements": 122, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_contract.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 15, 16, 17, 20, 21, 22, 23, 25, 26, 28, 31, 32, 34, 37, 38, 40, 41, 42, 44, 45, 46, 48, 50, 51, 52, 54, 55, 56, 58, 59, 61, 64, 65, 66, 68, 71, 72, 73, 74, 75, 78, 79, 80, 81, 82, 83, 84], "summary": {"covered_lines": 57, "num_statements": 59, "percent_covered": 96.61016949152543, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [29, 35], "excluded_lines": [], "functions": {"MockNostrServer.__init__": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.__init__": {"executed_lines": [22, 23], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.add_relays": {"executed_lines": [26], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [29], "excluded_lines": []}, "MockClient.connect": {"executed_lines": [32], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.disconnect": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [35], "excluded_lines": []}, "MockClient.send_event": {"executed_lines": [38, 40, 41, 44, 45, 48], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.send_event.FakeId.to_hex": {"executed_lines": [42], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.send_event.FakeOutput.__init__": {"executed_lines": [46], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.fetch_events": {"executed_lines": [51, 52, 54, 55, 58, 61], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.fetch_events.FakeEvents.__init__": {"executed_lines": [56], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.fetch_events.FakeEvents.to_vec": {"executed_lines": [59], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "setup_client": {"executed_lines": [65, 66, 68, 71, 72, 73, 74, 75], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_and_retrieve": {"executed_lines": [79, 80, 81, 82, 83, 84], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 15, 16, 20, 21, 25, 28, 31, 34, 37, 50, 64, 78], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"MockNostrServer": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient": {"executed_lines": [22, 23, 26, 32, 38, 40, 41, 44, 45, 48, 51, 52, 54, 55, 58, 61], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [29, 35], "excluded_lines": []}, "MockClient.send_event.FakeId": {"executed_lines": [42], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.send_event.FakeOutput": {"executed_lines": [46], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.fetch_events.FakeEvents": {"executed_lines": [56, 59], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 15, 16, 20, 21, 25, 28, 31, 34, 37, 50, 64, 65, 66, 68, 71, 72, 73, 74, 75, 78, 79, 80, 81, 82, 83, 84], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_dummy_client.py": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 34, 35, 37, 38, 39, 40, 41, 42, 43, 44, 45, 48, 49, 50, 51, 52, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 88, 90, 91, 93, 94, 96, 97, 98, 99, 101, 103, 105, 107, 116, 117, 120, 121, 122, 124, 126, 127, 130, 131, 133, 135, 137, 139, 144, 147, 148, 150, 151, 152, 154, 156, 157, 158, 160, 163, 164, 165, 167, 168, 169, 170, 172, 173, 174, 175, 176, 178, 179, 180, 182, 184, 185], "summary": {"covered_lines": 128, "num_statements": 129, "percent_covered": 99.2248062015504, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [161], "excluded_lines": [], "functions": {"test_manifest_generation": {"executed_lines": [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_retrieve_multi_chunk_snapshot": {"executed_lines": [35, 37, 38, 39, 40, 41, 42, 43, 44, 45, 48, 49, 50, 51, 52], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_and_fetch_deltas": {"executed_lines": [56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fetch_snapshot_fallback_on_missing_chunk": {"executed_lines": [73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 85, 88, 90, 91, 93, 94, 96, 97, 98, 99, 101, 103, 105, 107, 116, 117], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fetch_snapshot_fallback_on_missing_chunk.fake_sleep": {"executed_lines": [86], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fetch_snapshot_uses_event_ids": {"executed_lines": [121, 122, 124, 126, 127, 130, 131, 133, 135, 137, 139, 144], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_delta_aborts_if_outdated": {"executed_lines": [148, 150, 151, 152, 154, 156, 157, 160, 163, 164, 167, 168, 169, 170, 172, 173, 174, 175, 176, 178, 179, 180, 182, 184, 185], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_delta_aborts_if_outdated.DummyKeys.private_key_hex": {"executed_lines": [158], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_delta_aborts_if_outdated.DummyKeys.public_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [161], "excluded_lines": []}, "test_publish_delta_aborts_if_outdated.DummyKeyManager.__init__": {"executed_lines": [165], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 15, 34, 55, 72, 120, 147], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_publish_delta_aborts_if_outdated.DummyKeys": {"executed_lines": [158], "summary": {"covered_lines": 1, "num_statements": 2, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [161], "excluded_lines": []}, "test_publish_delta_aborts_if_outdated.DummyKeyManager": {"executed_lines": [165], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 34, 35, 37, 38, 39, 40, 41, 42, 43, 44, 45, 48, 49, 50, 51, 52, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 88, 90, 91, 93, 94, 96, 97, 98, 99, 101, 103, 105, 107, 116, 117, 120, 121, 122, 124, 126, 127, 130, 131, 133, 135, 137, 139, 144, 147, 148, 150, 151, 152, 154, 156, 157, 160, 163, 164, 167, 168, 169, 170, 172, 173, 174, 175, 176, 178, 179, 180, 182, 184, 185], "summary": {"covered_lines": 126, "num_statements": 126, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_entry.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 49, 50], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_nostr_key_determinism": {"executed_lines": [18, 19, 20, 21, 22, 23, 25, 26, 27, 37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 49, 50], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 17], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 49, 50], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_index_size.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 14, 16, 18, 19, 20, 21, 22, 23, 26, 27, 28], "summary": {"covered_lines": 22, "num_statements": 84, "percent_covered": 26.19047619047619, "percent_covered_display": "26", "missing_lines": 62, "excluded_lines": 0}, "missing_lines": [30, 34, 35, 36, 37, 38, 39, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 67, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 82, 83, 84, 85, 86, 87, 90, 91, 92, 93, 94, 96, 97, 99, 100, 101, 103, 105, 106, 107, 108, 109, 110, 111, 113, 114], "excluded_lines": [], "functions": {"test_nostr_index_size_limits": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 62, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 62, "excluded_lines": 0}, "missing_lines": [30, 34, 35, 36, 37, 38, 39, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 67, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 82, 83, 84, 85, 86, 87, 90, 91, 92, 93, 94, 96, 97, 99, 100, 101, 103, 105, 106, 107, 108, 109, 110, 111, 113, 114], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 14, 16, 18, 19, 20, 21, 22, 23, 26, 27, 28], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 14, 16, 18, 19, 20, 21, 22, 23, 26, 27, 28], "summary": {"covered_lines": 22, "num_statements": 84, "percent_covered": 26.19047619047619, "percent_covered_display": "26", "missing_lines": 62, "excluded_lines": 0}, "missing_lines": [30, 34, 35, 36, 37, 38, 39, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 67, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 82, 83, 84, 85, 86, 87, 90, 91, 92, 93, 94, 96, 97, 99, 100, 101, 103, 105, 106, 107, 108, 109, 110, 111, 113, 114], "excluded_lines": []}}}, "src/tests/test_nostr_legacy_decrypt_fallback.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 12, 13, 15, 16, 17, 18, 19, 22, 25, 29, 30, 31, 32, 34, 35, 36, 37, 38], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_legacy_password_only_fallback": {"executed_lines": [13, 15, 22, 25, 29, 30, 31, 32, 34, 35, 36, 37, 38], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_password_only_fallback._fast_legacy_key": {"executed_lines": [16, 17, 18, 19], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 12], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 12, 13, 15, 16, 17, 18, 19, 22, 25, 29, 30, 31, 32, 34, 35, 36, 37, 38], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_legacy_key_fallback.py": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 11, 12, 15, 17, 18, 19, 21, 24, 25, 26, 28, 32, 34, 35, 36, 37, 39, 41, 42, 43, 57, 58, 64, 66, 67, 68, 69, 70, 71, 72, 74, 76, 78, 79, 80, 81, 82, 83], "summary": {"covered_lines": 45, "num_statements": 46, "percent_covered": 97.82608695652173, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": [], "functions": {"test_fetch_snapshot_legacy_key_fallback": {"executed_lines": [12, 15, 17, 18, 21, 24, 28, 32, 34, 35, 39, 41, 42, 43, 57, 58, 64, 66, 76, 78, 79, 80, 81, 82, 83], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fetch_snapshot_legacy_key_fallback.LegacyKeys.private_key_hex": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fetch_snapshot_legacy_key_fallback.LegacyKeys.public_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": []}, "test_fetch_snapshot_legacy_key_fallback.fake_generate": {"executed_lines": [25, 26], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fetch_snapshot_legacy_key_fallback.RecordingFilter.author": {"executed_lines": [36, 37], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fetch_snapshot_legacy_key_fallback.fake_fetch_events": {"executed_lines": [67, 68, 69, 70, 71, 72, 74], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 11], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_fetch_snapshot_legacy_key_fallback.LegacyKeys": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 2, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": []}, "test_fetch_snapshot_legacy_key_fallback.RecordingFilter": {"executed_lines": [36, 37], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 11, 12, 15, 17, 18, 21, 24, 25, 26, 28, 32, 34, 35, 39, 41, 42, 43, 57, 58, 64, 66, 67, 68, 69, 70, 71, 72, 74, 76, 78, 79, 80, 81, 82, 83], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_qr.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 16, 17, 18, 20, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 45, 46, 48, 49, 50, 51, 56, 57, 60, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 81, 82, 84, 85, 86, 87, 92, 93, 94, 95, 98, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 119, 120, 123, 124, 125, 126, 127, 129, 130, 131, 132, 137, 138], "summary": {"covered_lines": 99, "num_statements": 101, "percent_covered": 98.01980198019803, "percent_covered_display": "98", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [21, 22], "excluded_lines": [], "functions": {"FakeNostrClient.__init__": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostrClient.publish_snapshot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [21, 22], "excluded_lines": []}, "test_show_qr_for_nostr_keys": {"executed_lines": [26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 45, 46, 48, 49, 50, 51, 56, 57], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_private_key_qr": {"executed_lines": [62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 81, 82, 84, 85, 86, 87, 92, 93, 94, 95], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_qr_menu_case_insensitive": {"executed_lines": [100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 119, 120, 123, 124, 125, 126, 127, 129, 130, 131, 132, 137, 138], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 16, 17, 20, 25, 60, 98], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeNostrClient": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 3, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [21, 22], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 16, 17, 20, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 45, 46, 48, 49, 50, 51, 56, 57, 60, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 81, 82, 84, 85, 86, 87, 92, 93, 94, 95, 98, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 119, 120, 123, 124, 125, 126, 127, 129, 130, 131, 132, 137, 138], "summary": {"covered_lines": 98, "num_statements": 98, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_real.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 14, 16, 17, 20, 21, 22], "summary": {"covered_lines": 17, "num_statements": 29, "percent_covered": 58.62068965517241, "percent_covered_display": "59", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [23, 27, 28, 31, 32, 37, 38, 39, 40, 41, 42, 43], "excluded_lines": [], "functions": {"test_nostr_publish_and_retrieve": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [23, 27, 28, 31, 32, 37, 38, 39, 40, 41, 42, 43], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 14, 16, 17, 20, 21, 22], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 14, 16, 17, 20, 21, 22], "summary": {"covered_lines": 17, "num_statements": 29, "percent_covered": 58.62068965517241, "percent_covered_display": "59", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [23, 27, 28, 31, 32, 37, 38, 39, 40, 41, 42, 43], "excluded_lines": []}}}, "src/tests/test_nostr_restore_flow.py": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, 32, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 46, 48, 49], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_init_pm": {"executed_lines": [12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_restore_flow_from_snapshot": {"executed_lines": [32, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 46, 48, 49], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 11, 31], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, 32, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 46, 48, 49], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_sdk_workflow.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 30, 31, 32, 33, 35, 38, 39, 40, 41, 43, 45, 46, 47, 49, 51, 52, 57, 58, 59, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71], "summary": {"covered_lines": 52, "num_statements": 52, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakeRelay.__init__": {"executed_lines": [14], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeRelay.handler": {"executed_lines": [17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "run_relay": {"executed_lines": [31, 35], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "run_relay.main": {"executed_lines": [32, 33], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_nostr_sdk_send_receive": {"executed_lines": [39, 40, 41, 43, 45, 46, 47, 49, 51, 52, 57, 58, 59, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 12, 13, 16, 30, 38], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeRelay": {"executed_lines": [14, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 12, 13, 16, 30, 31, 32, 33, 35, 38, 39, 40, 41, 43, 45, 46, 47, 49, 51, 52, 57, 58, 59, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_snapshot.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 30, 31, 34, 35, 36, 37, 39, 40, 42, 45, 46, 48, 51, 54, 55, 56, 58, 59, 60, 62, 63, 65, 68, 69, 70, 71, 72, 73, 81, 85, 86, 87, 90, 95, 96, 97, 98, 99, 101, 102, 103], "summary": {"covered_lines": 64, "num_statements": 67, "percent_covered": 95.5223880597015, "percent_covered_display": "96", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [43, 49, 52], "excluded_lines": [], "functions": {"test_prepare_snapshot_roundtrip": {"executed_lines": [16, 17, 18, 19, 20, 21, 22, 23], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEvent.__init__": {"executed_lines": [28], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEvent.content": {"executed_lines": [31], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyClient.__init__": {"executed_lines": [36, 37], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyClient.add_relays": {"executed_lines": [40], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyClient.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [43], "excluded_lines": []}, "DummyClient.connect": {"executed_lines": [46], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyClient.disconnect": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [49], "excluded_lines": []}, "DummyClient.send_event": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [52], "excluded_lines": []}, "DummyClient.fetch_events": {"executed_lines": [55, 56, 58, 59, 62, 65], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyClient.fetch_events.E.__init__": {"executed_lines": [60], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyClient.fetch_events.E.to_vec": {"executed_lines": [63], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fetch_latest_snapshot": {"executed_lines": [69, 70, 71, 72, 73, 81, 85, 86, 87, 90, 95, 96, 97, 98, 99, 101, 102, 103], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 26, 27, 30, 34, 35, 39, 42, 45, 48, 51, 54, 68], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEvent": {"executed_lines": [28, 31], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyClient": {"executed_lines": [36, 37, 40, 46, 55, 56, 58, 59, 62, 65], "summary": {"covered_lines": 10, "num_statements": 13, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [43, 49, 52], "excluded_lines": []}, "DummyClient.fetch_events.E": {"executed_lines": [60, 63], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 26, 27, 30, 34, 35, 39, 42, 45, 48, 51, 54, 68, 69, 70, 71, 72, 73, 81, 85, 86, 87, 90, 95, 96, 97, 98, 99, 101, 102, 103], "summary": {"covered_lines": 50, "num_statements": 50, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_offline_mode_behavior.py": {"executed_lines": [1, 2, 4, 7, 8, 9, 10, 11, 12, 15, 16, 17, 20, 21, 22, 23, 24, 25, 26, 27], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_sync_vault_skips_network": {"executed_lines": [8, 9, 10, 11, 12, 15, 16, 17], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_sync_offline": {"executed_lines": [21, 22, 23, 24, 25, 26, 27], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 7, 20], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 7, 8, 9, 10, 11, 12, 15, 16, 17, 20, 21, 22, 23, 24, 25, 26, 27], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_offline_mode_default_enabled.py": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_offline_mode_default_enabled": {"executed_lines": [9, 10, 11, 12, 13, 14], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_offline_mode_profile_creation.py": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29, 30, 31, 32], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_toggle_offline_mode_after_profile_creation": {"executed_lines": [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29, 30, 31, 32], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29, 30, 31, 32], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_parent_seed_backup.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 27, 28, 31, 33, 34, 36, 37, 39, 40, 42, 43, 44, 47, 48, 50, 51, 52, 56, 57, 59, 60, 63, 64, 65, 66, 67, 68], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [14, 15, 16, 17, 18, 19, 20, 21], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_backup_reveal_parent_seed_confirm": {"executed_lines": [25, 27, 28, 31, 33, 36, 37, 39, 40, 42, 43, 44], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_backup_reveal_parent_seed_confirm.fake_save": {"executed_lines": [34], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_backup_reveal_parent_seed_cancel": {"executed_lines": [48, 50, 51, 52, 56, 57, 59, 60], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_is_valid_filename": {"executed_lines": [64, 65, 66, 67, 68], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 13, 24, 47, 63], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 27, 28, 31, 33, 34, 36, 37, 39, 40, 42, 43, 44, 47, 48, 50, 51, 52, 56, 57, 59, 60, 63, 64, 65, 66, 67, 68], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_change.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 45], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_change_password_triggers_nostr_backup": {"executed_lines": [19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 45], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 15, 18], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 45], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_generation_policy.py": {"executed_lines": [1, 2, 3, 5, 7, 10, 11, 15, 16, 17, 20, 21, 22, 23, 24, 25, 28, 29, 37, 38, 39, 40, 41, 42, 43, 46, 47, 50, 51, 52, 53, 54, 55, 56, 57, 58, 61, 62, 65, 66, 67, 68], "summary": {"covered_lines": 42, "num_statements": 43, "percent_covered": 97.67441860465117, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [12], "excluded_lines": [], "functions": {"DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [12], "excluded_lines": []}, "DummyBIP85.derive_entropy": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_generator": {"executed_lines": [21, 22, 23, 24, 25], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "count_types": {"executed_lines": [29], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_zero_policy_preserves_length": {"executed_lines": [38, 39, 40, 41, 42, 43], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_custom_policy_applied": {"executed_lines": [47, 50, 51, 52, 53, 54, 55, 56, 57, 58], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_respects_policy": {"executed_lines": [62, 65, 66, 67, 68], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 10, 11, 15, 16, 20, 28, 37, 46, 61], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEnc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [12], "excluded_lines": []}, "DummyBIP85": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 10, 11, 15, 16, 20, 21, 22, 23, 24, 25, 28, 29, 37, 38, 39, 40, 41, 42, 43, 46, 47, 50, 51, 52, 53, 54, 55, 56, 57, 58, 61, 62, 65, 66, 67, 68], "summary": {"covered_lines": 41, "num_statements": 41, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_helpers.py": {"executed_lines": [1, 2, 5, 6, 10, 11, 12, 15, 16, 17, 18, 19, 20, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 40, 41, 42, 43, 44, 45, 46, 47, 48, 51, 52, 53, 54, 55, 56], "summary": {"covered_lines": 41, "num_statements": 42, "percent_covered": 97.61904761904762, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [7], "excluded_lines": [], "functions": {"DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [7], "excluded_lines": []}, "DummyBIP85.derive_entropy": {"executed_lines": [12], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_generator": {"executed_lines": [16, 17, 18, 19, 20], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_derive_password_entropy_length": {"executed_lines": [24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_map_entropy_to_chars_only_uses_alphabet": {"executed_lines": [33, 34, 35, 36, 37], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_enforce_complexity_minimum_counts": {"executed_lines": [41, 42, 43, 44, 45, 46, 47, 48], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_shuffle_deterministically_repeatable": {"executed_lines": [52, 53, 54, 55, 56], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 10, 11, 15, 23, 32, 40, 51], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEnc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [7], "excluded_lines": []}, "DummyBIP85": {"executed_lines": [12], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 10, 11, 15, 16, 17, 18, 19, 20, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 40, 41, 42, 43, 44, 45, 46, 47, 48, 51, 52, 53, 54, 55, 56], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_length_constraints.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 16, 17, 21, 22, 23, 24, 25, 26, 29, 30, 31, 32], "summary": {"covered_lines": 20, "num_statements": 22, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [13, 18], "excluded_lines": [], "functions": {"DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [13], "excluded_lines": []}, "DummyBIP85.derive_entropy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [18], "excluded_lines": []}, "make_generator": {"executed_lines": [22, 23, 24, 25, 26], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_too_short_raises": {"executed_lines": [30, 31, 32], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 16, 17, 21, 29], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEnc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [13], "excluded_lines": []}, "DummyBIP85": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [18], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 16, 17, 21, 22, 23, 24, 25, 26, 29, 30, 31, 32], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_notes_display.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 38, 41, 42, 44, 45, 46, 48, 49, 50, 51, 52], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_password_notes_shown": {"executed_lines": [17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 38, 41, 42, 44, 45, 46, 48, 49, 50, 51, 52], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 38, 41, 42, 44, 45, 46, 48, 49, 50, 51, 52], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_prompt.py": {"executed_lines": [1, 2, 4, 5, 7, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 31, 32, 33, 34, 35], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_prompt_new_password": {"executed_lines": [11, 12, 13, 14], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_prompt_new_password_retry": {"executed_lines": [18, 19, 20, 21, 22, 23], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_prompt_existing_password": {"executed_lines": [27, 28], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_confirm_action_yes_no": {"executed_lines": [32, 33, 34, 35], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 7, 10, 17, 26, 31], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 7, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 31, 32, 33, 34, 35], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_properties.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 12, 13, 17, 18, 19, 22, 23, 24, 25, 26, 27, 30, 34, 35, 36, 37, 38, 39, 40, 42, 43, 45, 46, 47, 48, 49], "summary": {"covered_lines": 33, "num_statements": 34, "percent_covered": 97.05882352941177, "percent_covered_display": "97", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [14], "excluded_lines": [], "functions": {"DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [14], "excluded_lines": []}, "DummyBIP85.derive_entropy": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_generator": {"executed_lines": [23, 24, 25, 26, 27], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_password_properties": {"executed_lines": [36, 37, 38, 39, 40, 42, 43, 45, 46, 47, 48, 49], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 12, 13, 17, 18, 22, 30, 34, 35], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEnc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [14], "excluded_lines": []}, "DummyBIP85": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 12, 13, 17, 18, 22, 23, 24, 25, 26, 27, 30, 34, 35, 36, 37, 38, 39, 40, 42, 43, 45, 46, 47, 48, 49], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_shuffle_consistency.py": {"executed_lines": [1, 2, 4, 6, 9, 10, 14, 15, 16, 19, 20, 21, 22, 23, 24, 27, 28, 29, 30, 32], "summary": {"covered_lines": 20, "num_statements": 21, "percent_covered": 95.23809523809524, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [11], "excluded_lines": [], "functions": {"DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [11], "excluded_lines": []}, "DummyBIP85.derive_entropy": {"executed_lines": [16], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_generator": {"executed_lines": [20, 21, 22, 23, 24], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_password_generation_consistent_output": {"executed_lines": [28, 29, 30, 32], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 9, 10, 14, 15, 19, 27], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEnc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [11], "excluded_lines": []}, "DummyBIP85": {"executed_lines": [16], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 9, 10, 14, 15, 19, 20, 21, 22, 23, 24, 27, 28, 29, 30, 32], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_special_chars.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 12, 13, 17, 18, 19, 22, 23, 24, 25, 26, 27, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 58, 59], "summary": {"covered_lines": 41, "num_statements": 42, "percent_covered": 97.61904761904762, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [14], "excluded_lines": [], "functions": {"DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [14], "excluded_lines": []}, "DummyBIP85.derive_entropy": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_generator": {"executed_lines": [23, 24, 25, 26, 27], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_no_special_chars": {"executed_lines": [31, 32, 33, 34], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_allowed_special_chars_only": {"executed_lines": [38, 39, 40, 41, 42, 43], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_exclude_ambiguous_chars": {"executed_lines": [47, 48, 49, 50, 51], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_safe_special_chars_mode": {"executed_lines": [55, 56, 57, 58, 59], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 12, 13, 17, 18, 22, 30, 37, 46, 54], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEnc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [14], "excluded_lines": []}, "DummyBIP85": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 12, 13, 17, 18, 22, 23, 24, 25, 26, 27, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 58, 59], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_special_modes.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 16, 17, 18, 21, 22, 23, 24, 25, 26, 29, 30, 31, 32, 33, 36, 37, 38, 39, 40, 41, 44, 45, 46, 47, 48, 49, 50, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62], "summary": {"covered_lines": 45, "num_statements": 46, "percent_covered": 97.82608695652173, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [13], "excluded_lines": [], "functions": {"DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [13], "excluded_lines": []}, "DummyBIP85.derive_entropy": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_generator": {"executed_lines": [22, 23, 24, 25, 26], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_include_special_chars_false": {"executed_lines": [30, 31, 32, 33], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_safe_mode_uses_safe_chars": {"executed_lines": [37, 38, 39, 40, 41], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_allowed_chars_override_special_mode": {"executed_lines": [45, 46, 47, 48, 49, 50], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_enforce_complexity_min_special_zero": {"executed_lines": [54, 55, 56, 57, 58, 59, 60, 61, 62], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 16, 17, 21, 29, 36, 44, 53], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEnc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [13], "excluded_lines": []}, "DummyBIP85": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 16, 17, 21, 22, 23, 24, 25, 26, 29, 30, 31, 32, 33, 36, 37, 38, 39, 40, 41, 44, 45, 46, 47, 48, 49, 50, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62], "summary": {"covered_lines": 44, "num_statements": 44, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_unlock_after_change.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 14, 15, 16, 17, 19, 22, 23, 24, 25, 26, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 50, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 65, 67, 70, 71, 78, 79, 81, 84, 85, 86, 88, 90, 91, 92], "summary": {"covered_lines": 58, "num_statements": 58, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_password_change_and_unlock": {"executed_lines": [23, 24, 25, 26, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 50, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 65, 67, 70, 71, 78, 79, 81, 84, 85, 86, 88, 90, 91, 92], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 14, 15, 16, 17, 19, 22], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 14, 15, 16, 17, 19, 22, 23, 24, 25, 26, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 50, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 65, 67, 70, 71, 78, 79, 81, 84, 85, 86, 88, 90, 91, 92], "summary": {"covered_lines": 58, "num_statements": 58, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_pgp_entry.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 22, 25, 26, 28, 29, 32, 34, 35, 38, 39, 40, 41, 44, 47, 48, 49, 50, 51, 52, 54, 55, 56, 58, 59], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_pgp_key_determinism": {"executed_lines": [15, 16, 17, 18, 19, 20, 22, 25, 26, 28, 29, 32, 34, 35, 38, 39, 40, 41], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_pgp_rsa_key_determinism": {"executed_lines": [47, 48, 49, 50, 51, 52, 54, 55, 56, 58, 59], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 44], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 22, 25, 26, 28, 29, 32, 34, 35, 38, 39, 40, 41, 44, 47, 48, 49, 50, 51, 52, 54, 55, 56, 58, 59], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_portable_backup.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 52, 53, 54, 57, 58, 59, 60, 61, 62, 64, 65, 66, 68, 69, 70, 73, 76, 77, 78, 79, 80, 81, 83, 85, 86, 87, 88, 89, 91, 94, 97, 101, 102, 105, 106, 107, 108, 109, 111, 113, 114, 115, 116, 119, 120, 121, 122, 123, 125, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 142, 144, 145, 146, 147, 149, 150, 151, 152, 155, 156, 157, 159, 160, 161, 162, 164, 165, 166, 167, 168, 169, 171, 173, 174, 176, 177, 179, 180, 181], "summary": {"covered_lines": 131, "num_statements": 132, "percent_covered": 99.24242424242425, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [92], "excluded_lines": [], "functions": {"setup_vault": {"executed_lines": [27, 28, 29, 30, 32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_round_trip": {"executed_lines": [41, 42, 43, 44, 45, 47, 48, 49, 50, 52, 53, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_round_trip_unencrypted": {"executed_lines": [58, 59, 60, 61, 62, 64, 65, 66, 68, 69, 70], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_corruption_detection": {"executed_lines": [78, 79, 80, 81, 83, 85, 86, 87, 88, 89, 91, 94, 97, 101, 102], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_corruption_detection._fast_legacy_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [92], "excluded_lines": []}, "test_import_over_existing": {"executed_lines": [106, 107, 108, 109, 111, 113, 114, 115, 116], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_checksum_mismatch_detection": {"executed_lines": [120, 121, 122, 123, 125, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_export_import_seed_encrypted_with_different_key": {"executed_lines": [144, 145, 146, 147, 149, 150, 151, 152], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_export_creates_additional_backup_and_import": {"executed_lines": [156, 157, 159, 160, 161, 162, 164, 165, 166, 167, 168, 169, 171, 173, 174, 176, 177, 179, 180, 181], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 26, 40, 57, 73, 76, 77, 105, 119, 142, 155], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 52, 53, 54, 57, 58, 59, 60, 61, 62, 64, 65, 66, 68, 69, 70, 73, 76, 77, 78, 79, 80, 81, 83, 85, 86, 87, 88, 89, 91, 94, 97, 101, 102, 105, 106, 107, 108, 109, 111, 113, 114, 115, 116, 119, 120, 121, 122, 123, 125, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 142, 144, 145, 146, 147, 149, 150, 151, 152, 155, 156, 157, 159, 160, 161, 162, 164, 165, 166, 167, 168, 169, 171, 173, 174, 176, 177, 179, 180, 181], "summary": {"covered_lines": 131, "num_statements": 132, "percent_covered": 99.24242424242425, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [92], "excluded_lines": []}}}, "src/tests/test_post_sync_messages.py": {"executed_lines": [1, 2, 3, 5, 7, 10, 11, 18, 19, 20, 21, 22, 25, 26, 29, 30, 31, 34, 35, 42, 43, 44, 51, 52], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_handle_post_success": {"executed_lines": [11, 18, 19, 20, 21, 22], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_post_failure": {"executed_lines": [26, 29, 30, 31], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_post_prints_all_ids": {"executed_lines": [35, 42, 43, 44, 51, 52], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 10, 25, 34], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 10, 11, 18, 19, 20, 21, 22, 25, 26, 29, 30, 31, 34, 35, 42, 43, 44, 51, 52], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_profile_cleanup.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 12, 13, 14, 16, 17, 19, 20, 21, 22, 23, 24, 27, 28, 29, 30, 32, 34, 35, 40, 41, 44, 45, 46, 47, 48, 49, 50], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_pm": {"executed_lines": [13, 14, 16, 17, 19, 20, 21, 22, 23, 24], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_seed_cleanup_on_failure": {"executed_lines": [28, 29, 30, 32, 34, 35, 40, 41, 44, 45, 46, 47, 48, 49, 50], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 12, 27], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 12, 13, 14, 16, 17, 19, 20, 21, 22, 23, 24, 27, 28, 29, 30, 32, 34, 35, 40, 41, 44, 45, 46, 47, 48, 49, 50], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_profile_deletion_sync.py": {"executed_lines": [1, 2, 4, 5, 6, 8, 9, 10, 11, 14, 15, 16, 18, 20, 21, 23, 24, 25, 27, 45, 46, 48, 49, 51, 52, 53, 54, 55], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_profile_deletion_stops_sync": {"executed_lines": [15, 16, 18, 20, 23, 24, 25, 27, 45, 46, 48, 49, 51, 52, 53, 54, 55], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_profile_deletion_stops_sync.fake_post": {"executed_lines": [21], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 6, 8, 9, 10, 11, 14], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 6, 8, 9, 10, 11, 14, 15, 16, 18, 20, 21, 23, 24, 25, 27, 45, 46, 48, 49, 51, 52, 53, 54, 55], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_profile_export_import.py": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 11, 15, 16, 17, 18, 20, 21, 22, 23, 25, 26, 28, 29, 30, 32, 33], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_profile_export_import_round_trip": {"executed_lines": [9, 10, 11, 15, 16, 17, 18, 20, 21, 22, 23, 25, 28, 29, 30, 32, 33], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_profile_export_import_round_trip.sync": {"executed_lines": [26], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 11, 15, 16, 17, 18, 20, 21, 22, 23, 25, 26, 28, 29, 30, 32, 33], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_profile_init_integration.py": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, 25, 27, 29, 30, 31, 32, 33, 35, 39, 40, 42, 43, 45, 46, 47, 48], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"load_script": {"executed_lines": [10, 13, 14, 15, 16, 17], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_initialize_profile_and_manager": {"executed_lines": [21, 22, 23, 25, 27, 29, 30, 31, 32, 33, 35, 39, 40, 42, 43, 45, 46, 47, 48], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 9, 20], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, 25, 27, 29, 30, 31, 32, 33, 35, 39, 40, 42, 43, 45, 46, 47, 48], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_profile_management.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 43, 44, 46, 48, 49, 50, 52, 53, 55, 56, 57, 58, 60, 61, 62, 64, 65, 67, 68, 75, 76, 77, 83, 85, 86], "summary": {"covered_lines": 56, "num_statements": 56, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_add_and_delete_entry": {"executed_lines": [23, 24, 25, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 43, 44, 46, 48, 49, 50, 52, 53, 55, 56, 57, 58, 60, 61, 62, 64, 65, 67, 68, 75, 76, 77, 83, 85, 86], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 14, 15, 16, 17, 18, 19, 22], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 43, 44, 46, 48, 49, 50, 52, 53, 55, 56, 57, 58, 60, 61, 62, 64, 65, 67, 68, 75, 76, 77, 83, 85, 86], "summary": {"covered_lines": 56, "num_statements": 56, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_profiles.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 13, 16, 17, 18, 19, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 33, 34, 39, 40, 41, 42, 45, 49, 50, 51, 52, 55, 56, 57, 58, 59, 61, 62, 63, 64, 65, 67, 73, 78, 80, 81, 82, 83, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 99, 101, 102, 103, 104], "summary": {"covered_lines": 67, "num_statements": 67, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_add_and_switch_fingerprint": {"executed_lines": [17, 18, 19, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 33, 34, 39, 40, 41, 42, 45, 49, 50, 51, 52], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sync_index_missing_bad_data": {"executed_lines": [56, 57, 58, 59, 61, 62, 63, 64, 65, 67, 73, 78, 80, 81, 82, 83], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_attempt_initial_sync_incomplete_data": {"executed_lines": [87, 88, 89, 90, 92, 93, 94, 95, 96, 99, 101, 102, 103, 104], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 13, 16, 55, 86], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 13, 16, 17, 18, 19, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 33, 34, 39, 40, 41, 42, 45, 49, 50, 51, 52, 55, 56, 57, 58, 59, 61, 62, 63, 64, 65, 67, 73, 78, 80, 81, 82, 83, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 99, 101, 102, 103, 104], "summary": {"covered_lines": 67, "num_statements": 67, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_publish_json_result.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 16, 17, 18, 20, 25, 26, 27, 28, 29, 32, 33, 34, 35, 37, 40, 44, 45, 46, 48, 49, 52, 53, 54, 56, 57, 59, 60, 63, 64, 65, 68, 69, 70, 73, 74, 77, 79, 80, 82, 85, 86, 87, 88, 89, 90, 93, 94, 97, 99, 100, 102, 103, 104], "summary": {"covered_lines": 64, "num_statements": 66, "percent_covered": 96.96969696969697, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [38, 41], "excluded_lines": [], "functions": {"setup_client": {"executed_lines": [17, 18, 20, 25, 26, 27, 28, 29], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEvent.__init__": {"executed_lines": [34, 35], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEvent.id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [38], "excluded_lines": []}, "FakeEvent.content": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [41], "excluded_lines": []}, "FakeUnsignedEvent.__init__": {"executed_lines": [46], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeUnsignedEvent.sign_with_keys": {"executed_lines": [49], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeBuilder.__init__": {"executed_lines": [54], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeBuilder.tags": {"executed_lines": [57], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeBuilder.build": {"executed_lines": [60], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEventId.to_hex": {"executed_lines": [65], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeSendEventOutput.__init__": {"executed_lines": [70], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_snapshot_success": {"executed_lines": [74, 77, 79, 82, 85, 86, 87, 88, 89, 90], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_snapshot_success.fake_send": {"executed_lines": [80], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_snapshot_failure": {"executed_lines": [94, 97, 99, 102, 103, 104], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_snapshot_failure.boom": {"executed_lines": [100], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 16, 32, 33, 37, 40, 44, 45, 48, 52, 53, 56, 59, 63, 64, 68, 69, 73, 93], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeEvent": {"executed_lines": [34, 35], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [38, 41], "excluded_lines": []}, "FakeUnsignedEvent": {"executed_lines": [46, 49], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeBuilder": {"executed_lines": [54, 57, 60], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEventId": {"executed_lines": [65], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeSendEventOutput": {"executed_lines": [70], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 16, 17, 18, 20, 25, 26, 27, 28, 29, 32, 33, 37, 40, 44, 45, 48, 52, 53, 56, 59, 63, 64, 68, 69, 73, 74, 77, 79, 80, 82, 85, 86, 87, 88, 89, 90, 93, 94, 97, 99, 100, 102, 103, 104], "summary": {"covered_lines": 55, "num_statements": 55, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_pubsub.py": {"executed_lines": [1, 4, 5, 6, 8, 9, 11, 12, 14, 17, 18, 19, 21, 24, 25, 26, 28], "summary": {"covered_lines": 17, "num_statements": 18, "percent_covered": 94.44444444444444, "percent_covered_display": "94", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": [], "functions": {"test_subscribe_and_publish": {"executed_lines": [5, 6, 8, 11, 12, 14], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_subscribe_and_publish.handler": {"executed_lines": [9], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_unsubscribe": {"executed_lines": [18, 19, 21, 24, 25, 26, 28], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_unsubscribe.handler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": []}, "": {"executed_lines": [1, 4, 17], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 4, 5, 6, 8, 9, 11, 12, 14, 17, 18, 19, 21, 24, 25, 26, 28], "summary": {"covered_lines": 17, "num_statements": 18, "percent_covered": 94.44444444444444, "percent_covered_display": "94", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": []}}}, "src/tests/test_quick_unlock_default.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 32, 34], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_quick_unlock_default_off": {"executed_lines": [16, 17, 18], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_quick_unlock_logs_event": {"executed_lines": [22, 23, 24, 25, 26, 27, 28, 29, 31, 32, 34], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 15, 21], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 32, 34], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_quick_unlock_profile_creation.py": {"executed_lines": [1, 2, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27, 28], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_toggle_quick_unlock_after_profile_creation": {"executed_lines": [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27, 28], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 6, 7, 10], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27, 28], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_restore_from_nostr_setup.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, 34, 36, 37, 38, 39, 41, 42, 43, 44, 46, 47, 48, 49, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 69, 70, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 93, 94, 95, 97, 99, 100, 101, 103, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 120, 121, 123, 124, 126, 127, 128, 129, 130, 131, 134, 135, 138, 141, 142, 144, 145, 146, 148, 149, 150, 152, 153, 154, 157, 160, 161, 163, 164, 165, 166, 168, 170, 173, 174, 176, 177, 178, 179, 180], "summary": {"covered_lines": 132, "num_statements": 133, "percent_covered": 99.24812030075188, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [171], "excluded_lines": [], "functions": {"_init_pm": {"executed_lines": [12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_new_seed_setup_restore_from_nostr": {"executed_lines": [34, 36, 37, 38, 39, 41, 42, 43, 44, 46, 47, 48, 49, 51, 66, 67, 69, 70, 72, 73, 74, 75, 76], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_new_seed_setup_restore_from_nostr.finalize": {"executed_lines": [52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_new_seed_setup_restore_from_local_backup": {"executed_lines": [80, 81, 82, 83, 85, 86, 87, 88, 89, 93, 94, 95, 97, 99, 103, 105, 120, 121, 123, 124, 126, 127, 128, 129, 130, 131], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_new_seed_setup_restore_from_local_backup.init_fp_mgr": {"executed_lines": [100, 101], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_new_seed_setup_restore_from_local_backup.finalize": {"executed_lines": [106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_no_snapshot": {"executed_lines": [135], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_restore_from_nostr_warns": {"executed_lines": [141, 142, 144, 145, 146, 148, 149, 150, 152, 153, 154], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_restore_from_nostr_abort": {"executed_lines": [160, 161, 163, 164, 165, 166, 168, 170, 173, 174, 176, 177, 178, 179, 180], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_restore_from_nostr_abort.finalize": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [171], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 11, 31, 79, 134, 138, 157], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 6, 7, 8, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, 34, 36, 37, 38, 39, 41, 42, 43, 44, 46, 47, 48, 49, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 69, 70, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 93, 94, 95, 97, 99, 100, 101, 103, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 120, 121, 123, 124, 126, 127, 128, 129, 130, 131, 134, 135, 138, 141, 142, 144, 145, 146, 148, 149, 150, 152, 153, 154, 157, 160, 161, 163, 164, 165, 166, 168, 170, 173, 174, 176, 177, 178, 179, 180], "summary": {"covered_lines": 132, "num_statements": 133, "percent_covered": 99.24812030075188, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [171], "excluded_lines": []}}}, "src/tests/test_retrieve_pause_sensitive_entries.py": {"executed_lines": [1, 2, 4, 6, 8, 11, 20, 23, 25, 27, 28, 31, 32, 33, 34, 38, 39], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_pause_before_entry_actions": {"executed_lines": [23, 25, 27, 28, 31, 32, 33, 34, 38, 39], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 8, 11, 20], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 8, 11, 20, 23, 25, 27, 28, 31, 32, 33, 34, 38, 39], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_search_entries.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 27, 28, 30, 31, 34, 35, 36, 37, 39, 40, 42, 43, 46, 47, 48, 49, 51, 52, 54, 55, 60, 61, 62, 63, 65, 66, 67, 68, 71, 72, 74, 75, 78, 79, 80, 81, 83, 87, 89, 90, 93, 94, 95, 96, 98, 100, 101, 104, 105, 106, 107, 109, 110, 111, 114, 115, 116, 117, 119, 121, 122, 125, 126, 127, 128, 130, 131, 133, 134, 137, 138, 139, 140, 142, 143, 144, 146, 149, 151, 152], "summary": {"covered_lines": 98, "num_statements": 98, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_entry_manager": {"executed_lines": [16, 17, 18, 19], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_by_website": {"executed_lines": [23, 24, 25, 27, 28, 30, 31], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_by_username": {"executed_lines": [35, 36, 37, 39, 40, 42, 43], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_by_url": {"executed_lines": [47, 48, 49, 51, 52, 54, 55], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_by_notes_and_totp": {"executed_lines": [61, 62, 63, 65, 66, 67, 68, 71, 72, 74, 75], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_by_custom_field": {"executed_lines": [79, 80, 81, 83, 87, 89, 90], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_key_value_value": {"executed_lines": [94, 95, 96, 98, 100, 101], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_no_results": {"executed_lines": [105, 106, 107, 109, 110, 111], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_by_tag_password": {"executed_lines": [115, 116, 117, 119, 121, 122], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_by_tag_totp": {"executed_lines": [126, 127, 128, 130, 131, 133, 134], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_with_kind_filter": {"executed_lines": [138, 139, 140, 142, 143, 144, 146, 149, 151, 152], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 22, 34, 46, 60, 78, 93, 104, 114, 125, 137], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 27, 28, 30, 31, 34, 35, 36, 37, 39, 40, 42, 43, 46, 47, 48, 49, 51, 52, 54, 55, 60, 61, 62, 63, 65, 66, 67, 68, 71, 72, 74, 75, 78, 79, 80, 81, 83, 87, 89, 90, 93, 94, 95, 96, 98, 100, 101, 104, 105, 106, 107, 109, 110, 111, 114, 115, 116, 117, 119, 121, 122, 125, 126, 127, 128, 130, 131, 133, 134, 137, 138, 139, 140, 142, 143, 144, 146, 149, 151, 152], "summary": {"covered_lines": 98, "num_statements": 98, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_secret_mode.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 38, 39, 40, 41, 42, 44, 45, 46, 47, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 65, 69, 72, 76, 77, 82, 83, 84, 85, 86, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 104, 105, 106, 107, 108, 111, 112, 113, 114, 115, 116, 118, 122, 125, 129, 130, 135, 136, 137, 138, 139], "summary": {"covered_lines": 89, "num_statements": 89, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_pm": {"executed_lines": [18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_password_retrieve_secret_mode": {"executed_lines": [39, 40, 41, 42, 44, 45, 46, 47, 52, 53, 54, 55, 56], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_totp_display_secret_mode": {"executed_lines": [60, 61, 62, 63, 65, 69, 72, 76, 77, 82, 83, 84, 85, 86], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_password_retrieve_no_secret_mode": {"executed_lines": [90, 91, 92, 93, 94, 96, 97, 98, 99, 104, 105, 106, 107, 108], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_totp_display_no_secret_mode": {"executed_lines": [112, 113, 114, 115, 116, 118, 122, 125, 129, 130, 135, 136, 137, 138, 139], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 17, 38, 59, 89, 111], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 38, 39, 40, 41, 42, 44, 45, 46, 47, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 65, 69, 72, 76, 77, 82, 83, 84, 85, 86, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 104, 105, 106, 107, 108, 111, 112, 113, 114, 115, 116, 118, 122, 125, 129, 130, 135, 136, 137, 138, 139], "summary": {"covered_lines": 89, "num_statements": 89, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_secret_mode_profile_creation.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 26, 27, 30, 31, 32, 33, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 52, 54, 55, 56, 57, 58, 59], "summary": {"covered_lines": 47, "num_statements": 47, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_add_new_fingerprint_initializes_managers": {"executed_lines": [14, 15, 16, 17, 19, 26, 27, 30, 31, 32, 33], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_new_fingerprint_initializes_managers.fake_setup_existing_seed": {"executed_lines": [20, 21, 22, 23, 24], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_toggle_secret_mode_after_profile_creation": {"executed_lines": [37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 52, 54, 55, 56, 57, 58, 59], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 36], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 26, 27, 30, 31, 32, 33, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 52, 54, 55, 56, 57, 58, 59], "summary": {"covered_lines": 47, "num_statements": 47, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_seed_entry.py": {"executed_lines": [1, 2, 3, 5, 6, 8, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 31, 32, 34, 35, 37, 48, 59, 60, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74], "summary": {"covered_lines": 43, "num_statements": 43, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_seed_phrase_determinism": {"executed_lines": [19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 31, 32, 34, 35, 37, 48, 59, 60, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 8, 10, 11, 12, 13, 14, 15, 18], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 8, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 31, 32, 34, 35, 37, 48, 59, 60, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74], "summary": {"covered_lines": 43, "num_statements": 43, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_seed_generation.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 10, 12, 13, 16, 17, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 33, 35, 36, 38, 39, 41, 42, 43], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_password_manager": {"executed_lines": [12, 13, 16, 17, 19, 20, 21, 22, 23, 24, 25], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_bip85_and_new_seed": {"executed_lines": [29, 30, 31, 33, 35, 36, 38, 39, 41, 42, 43], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 10, 28], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 10, 12, 13, 16, 17, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 33, 35, 36, 38, 39, 41, 42, 43], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_seed_import.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_seed_encryption_round_trip": {"executed_lines": [16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 15], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_seed_migration.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 11, 13, 16, 17, 18, 19, 20, 21, 22, 24, 25, 27, 29, 31, 32, 33, 34], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_parent_seed_migrates_from_fernet": {"executed_lines": [17, 18, 19, 20, 21, 22, 24, 25, 27, 29, 31, 32, 33, 34], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 11, 13, 16], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 11, 13, 16, 17, 18, 19, 20, 21, 22, 24, 25, 27, 29, 31, 32, 33, 34], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_seed_prompt.py": {"executed_lines": [1, 2, 3, 6, 7, 8, 9, 11, 19, 20, 22, 26, 28, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 50, 51, 52, 53, 55, 56, 61, 62, 63, 64, 66, 67, 68, 71, 72, 73, 74, 75, 77, 78, 81, 82, 84, 85, 86, 88, 89, 90, 92, 93, 96, 97, 99, 100, 101, 103, 104, 105, 107, 108], "summary": {"covered_lines": 68, "num_statements": 72, "percent_covered": 94.44444444444444, "percent_covered_display": "94", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [12, 17, 23, 24], "excluded_lines": [], "functions": {"test_masked_input_posix_backspace": {"executed_lines": [7, 8, 9, 11, 19, 20, 22, 26, 28, 30, 31, 32, 33, 34], "summary": {"covered_lines": 14, "num_statements": 18, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [12, 17, 23, 24], "excluded_lines": []}, "test_masked_input_windows_space": {"executed_lines": [38, 39, 40, 41, 43, 44, 45, 46, 47], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_masked_input_posix_ctrl_c": {"executed_lines": [51, 52, 53, 55, 56, 61, 62, 63, 64, 66, 67, 68], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_masked_input_windows_ctrl_c": {"executed_lines": [72, 73, 74, 75, 77, 78], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_prompt_seed_words_valid": {"executed_lines": [82, 84, 85, 86, 88, 89, 90, 92, 93], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_prompt_seed_words_invalid_word": {"executed_lines": [97, 99, 100, 101, 103, 104, 105, 107, 108], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 6, 37, 50, 71, 81, 96], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 6, 7, 8, 9, 11, 19, 20, 22, 26, 28, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 50, 51, 52, 53, 55, 56, 61, 62, 63, 64, 66, 67, 68, 71, 72, 73, 74, 75, 77, 78, 81, 82, 84, 85, 86, 88, 89, 90, 92, 93, 96, 97, 99, 100, 101, 103, 104, 105, 107, 108], "summary": {"covered_lines": 68, "num_statements": 72, "percent_covered": 94.44444444444444, "percent_covered_display": "94", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [12, 17, 23, 24], "excluded_lines": []}}}, "src/tests/test_seed_word_by_word_flow.py": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 13, 14, 15, 16, 18, 19, 20, 21, 23, 24, 27, 28, 29, 30, 31, 33, 34, 35, 36, 38, 39, 42, 43, 44, 45, 47, 48, 49, 50, 52, 53, 54, 55, 57, 59, 60, 61, 62, 64, 68, 70, 71, 72, 73, 76, 77, 78, 79, 81, 82, 83, 85, 86, 87, 88, 90, 91, 93, 94], "summary": {"covered_lines": 67, "num_statements": 67, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_prompt_seed_words_confirmation_loop": {"executed_lines": [13, 14, 15, 16, 18, 19, 20, 21, 23, 24], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_prompt_seed_words_invalid_word": {"executed_lines": [28, 29, 30, 31, 33, 34, 35, 36, 38, 39], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_new_fingerprint_words_flow_success": {"executed_lines": [43, 44, 45, 47, 48, 49, 50, 52, 53, 54, 55, 57, 59, 64, 68, 70, 71, 72, 73], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_new_fingerprint_words_flow_success.finalize": {"executed_lines": [60, 61, 62], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_new_fingerprint_words_flow_invalid_phrase": {"executed_lines": [77, 78, 79, 81, 82, 83, 85, 86, 87, 88, 90, 91, 93, 94], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 27, 42, 76], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 13, 14, 15, 16, 18, 19, 20, 21, 23, 24, 27, 28, 29, 30, 31, 33, 34, 35, 36, 38, 39, 42, 43, 44, 45, 47, 48, 49, 50, 52, 53, 54, 55, 57, 59, 60, 61, 62, 64, 68, 70, 71, 72, 73, 76, 77, 78, 79, 81, 82, 83, 85, 86, 87, 88, 90, 91, 93, 94], "summary": {"covered_lines": 67, "num_statements": 67, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_seedqr_encoding.py": {"executed_lines": [1, 2, 4, 6, 9, 10, 14, 15], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_seedqr_standard_example": {"executed_lines": [10, 14, 15], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 9], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 9, 10, 14, 15], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_service_classes.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 19, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 68, 69, 70, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 96, 97, 98, 100, 101, 102, 103, 104, 105, 106, 109, 110, 111, 112, 113, 115, 116, 118, 119, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 140, 143, 147, 148], "summary": {"covered_lines": 102, "num_statements": 102, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakePasswordGenerator.generate_password": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_setup_pm": {"executed_lines": [23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_service_add_password": {"executed_lines": [44, 45, 46, 47, 48, 68, 69, 70, 72, 73, 74, 75, 76], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_handler_list_entries": {"executed_lines": [80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_handler_list_entries_shows_empty_message": {"executed_lines": [97, 98, 100, 101, 102, 103, 104, 105, 106], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_profile_service_switch": {"executed_lines": [110, 111, 115, 118, 121, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 140, 143, 147, 148], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_profile_service_switch.DummyFingerprintManager.__init__": {"executed_lines": [112, 113], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_profile_service_switch.DummyFingerprintManager.list_fingerprints": {"executed_lines": [116], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_profile_service_switch.DummyFingerprintManager.display_name": {"executed_lines": [119], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_profile_service_switch.DummyFingerprintManager.get_current_fingerprint_dir": {"executed_lines": [122], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 22, 43, 79, 96, 109], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakePasswordGenerator": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_profile_service_switch.DummyFingerprintManager": {"executed_lines": [112, 113, 116, 119, 122], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 68, 69, 70, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 96, 97, 98, 100, 101, 102, 103, 104, 105, 106, 109, 110, 111, 115, 118, 121, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 140, 143, 147, 148], "summary": {"covered_lines": 96, "num_statements": 96, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_settings_menu.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 17, 18, 19, 20, 21, 24, 25, 26, 28, 29, 31, 32, 33, 34, 35, 37, 45, 50, 53, 54, 55, 56, 59, 62, 67, 70, 71, 72, 75, 76, 79, 80, 81, 84, 85, 86, 87, 90, 91, 92, 93, 96, 97, 98, 99, 101, 102, 103, 104, 105, 108, 109, 110, 111, 112, 113, 115, 116, 117, 118, 120, 121, 123, 126, 127, 128, 129, 131, 132, 134, 135, 136, 137, 138, 140, 141, 143, 144, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 164, 165, 166, 168, 169, 171, 172], "summary": {"covered_lines": 113, "num_statements": 113, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_pm": {"executed_lines": [25, 26, 28, 29, 31, 32, 33, 34, 35, 37, 45, 50], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_relay_and_profile_actions": {"executed_lines": [54, 55, 56, 59, 62, 67, 70, 71, 72, 75, 76, 79, 80, 81, 84, 85, 86, 87, 90, 91, 92, 93], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_settings_menu_additional_backup": {"executed_lines": [97, 98, 99, 101, 102, 103, 104, 105], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_settings_menu_change_password": {"executed_lines": [109, 110, 111, 112, 113, 115, 116, 117, 118, 120, 121, 123], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_settings_menu_change_password_incorrect": {"executed_lines": [127, 128, 129, 131, 134, 135, 136, 137, 138, 140, 141, 143, 144], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_settings_menu_change_password_incorrect.fail_change": {"executed_lines": [132], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_settings_menu_without_nostr_client": {"executed_lines": [148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 164, 165, 166, 168, 169, 171, 172], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 17, 18, 19, 20, 21, 24, 53, 96, 108, 126, 147], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 17, 18, 19, 20, 21, 24, 25, 26, 28, 29, 31, 32, 33, 34, 35, 37, 45, 50, 53, 54, 55, 56, 59, 62, 67, 70, 71, 72, 75, 76, 79, 80, 81, 84, 85, 86, 87, 90, 91, 92, 93, 96, 97, 98, 99, 101, 102, 103, 104, 105, 108, 109, 110, 111, 112, 113, 115, 116, 117, 118, 120, 121, 123, 126, 127, 128, 129, 131, 132, 134, 135, 136, 137, 138, 140, 141, 143, 144, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 164, 165, 166, 168, 169, 171, 172], "summary": {"covered_lines": 113, "num_statements": 113, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_ssh_entry.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 35, 36, 37, 38], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_add_and_retrieve_ssh_key_pair": {"executed_lines": [16, 17, 18, 19, 20, 21, 23, 24, 25, 35, 36, 37, 38], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 35, 36, 37, 38], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_ssh_entry_valid.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 24, 25, 27, 31, 40], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_ssh_private_key_corresponds_to_public": {"executed_lines": [17, 18, 19, 20, 21, 22, 24, 25, 27, 31, 40], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 16], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 24, 25, 27, 31, 40], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_state_manager.py": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_state_manager_round_trip": {"executed_lines": [9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_stats_screen.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 20, 21, 22, 23, 28, 29, 30, 33, 34, 35, 36, 41, 42, 43, 46, 47, 49, 50, 52, 53, 59, 61, 64, 65, 66, 68, 70, 73, 74, 75, 76, 79, 80, 81, 82, 87, 88, 89, 90, 93, 94, 96, 97, 98, 100, 101, 103, 104, 106, 108], "summary": {"covered_lines": 59, "num_statements": 60, "percent_covered": 98.33333333333333, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [71], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_live_stats_shows_message": {"executed_lines": [21, 22, 23, 28, 29, 30], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_live_stats_shows_notification": {"executed_lines": [34, 35, 36, 41, 42, 43], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_live_stats_triggers_background_sync": {"executed_lines": [47, 49, 50, 52, 53, 59, 61], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_stats_display_only_once": {"executed_lines": [65, 66, 68, 70, 73, 74, 75, 76], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_stats_display_only_once.fake_input": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [71], "excluded_lines": []}, "test_stats_display_resets_after_exit": {"executed_lines": [80, 81, 82, 87, 88, 89, 90], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_stats_screen_breaks_on_enter": {"executed_lines": [94, 96, 100, 101, 103, 104, 106, 108], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_stats_screen_breaks_on_enter.display": {"executed_lines": [97, 98], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 20, 33, 46, 64, 79, 93], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 20, 21, 22, 23, 28, 29, 30, 33, 34, 35, 36, 41, 42, 43, 46, 47, 49, 50, 52, 53, 59, 61, 64, 65, 66, 68, 70, 73, 74, 75, 76, 79, 80, 81, 82, 87, 88, 89, 90, 93, 94, 96, 97, 98, 100, 101, 103, 104, 106, 108], "summary": {"covered_lines": 59, "num_statements": 60, "percent_covered": 98.33333333333333, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [71], "excluded_lines": []}}}, "src/tests/test_sync_race_conditions.py": {"executed_lines": [1, 2, 3, 6, 8, 9, 10, 11, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 34, 35, 37, 38, 39, 40, 42, 44, 45, 46, 48, 51, 52, 53, 55, 56, 57, 59, 60, 61, 62, 64, 65, 67, 68, 69, 70, 72, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 93, 95, 96, 97, 98], "summary": {"covered_lines": 75, "num_statements": 76, "percent_covered": 98.6842105263158, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [49], "excluded_lines": [], "functions": {"_init_pm": {"executed_lines": [15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sync_race_conditions": {"executed_lines": [35, 37, 38, 39, 40, 42, 44, 45, 48, 51, 52, 55, 56, 57, 59, 60, 61, 62, 64, 65, 67, 68, 69, 70, 72, 74, 86, 87, 88, 89, 90, 91, 93, 95, 96, 97, 98], "summary": {"covered_lines": 37, "num_statements": 37, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sync_race_conditions.DummyKeys.private_key_hex": {"executed_lines": [46], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sync_race_conditions.DummyKeys.public_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [49], "excluded_lines": []}, "test_sync_race_conditions.DummyKeyManager.__init__": {"executed_lines": [53], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sync_race_conditions.publish": {"executed_lines": [75, 76, 77, 78, 79, 80, 81, 82, 83, 84], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 6, 8, 9, 10, 11, 14, 34], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_sync_race_conditions.DummyKeys": {"executed_lines": [46], "summary": {"covered_lines": 1, "num_statements": 2, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [49], "excluded_lines": []}, "test_sync_race_conditions.DummyKeyManager": {"executed_lines": [53], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 6, 8, 9, 10, 11, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 34, 35, 37, 38, 39, 40, 42, 44, 45, 48, 51, 52, 55, 56, 57, 59, 60, 61, 62, 64, 65, 67, 68, 69, 70, 72, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 93, 95, 96, 97, 98], "summary": {"covered_lines": 73, "num_statements": 73, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_tag_persistence.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 27, 30, 32, 33, 36, 37, 38, 39, 41, 42, 45, 50, 51, 52], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_entry_manager": {"executed_lines": [16, 17, 18, 19], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_tags_persist_on_new_entry": {"executed_lines": [23, 24, 25, 27, 30, 32, 33], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_tags_persist_after_modify": {"executed_lines": [37, 38, 39, 41, 42, 45, 50, 51, 52], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 22, 36], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 27, 30, 32, 33, 36, 37, 38, 39, 41, 42, 45, 50, 51, 52], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_terminal_utils_failure_handling.py": {"executed_lines": [1, 3, 4, 6, 12, 13, 14, 17, 18, 20, 21, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 4}, "missing_lines": [], "excluded_lines": [13, 14, 20, 21], "functions": {"ErrorFingerprintManager.get_name": {"executed_lines": [14], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [14]}, "ErrorPM.get_current_notification": {"executed_lines": [21], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [21]}, "test_format_profile_reraises": {"executed_lines": [25, 26, 27, 28, 29], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_clear_header_with_notification_reraises": {"executed_lines": [33, 34, 35, 36, 37], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 6, 12, 13, 17, 18, 20, 24, 32], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [13, 20]}}, "classes": {"ErrorFingerprintManager": {"executed_lines": [14], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [14]}, "ErrorPM": {"executed_lines": [21], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [21]}, "": {"executed_lines": [1, 3, 4, 6, 12, 13, 17, 18, 20, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [13, 20]}}}, "src/tests/test_totp.py": {"executed_lines": [1, 2, 4, 5, 7, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 25, 26, 27, 28, 29, 30], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_current_code_matches_pyotp": {"executed_lines": [15, 16, 17], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_time_remaining": {"executed_lines": [22], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_print_progress_bar_terminates": {"executed_lines": [26, 27, 28, 29, 30], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 7, 9, 10, 13, 14, 20, 21, 25], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 7, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 25, 26, 27, 28, 29, 30], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_totp_entry.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 25, 27, 28, 30, 31, 32, 34, 36, 37, 40, 41, 42, 45, 46, 47, 48, 49, 50, 52, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 73, 74, 75, 76, 77, 79, 80, 81, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 96, 97, 98, 100, 101], "summary": {"covered_lines": 75, "num_statements": 75, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_add_totp_and_get_code": {"executed_lines": [21, 22, 23, 24, 25, 27, 28, 30, 31, 32, 34, 36, 37, 40, 41, 42], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_totp_time_remaining": {"executed_lines": [46, 47, 48, 49, 50, 52, 54, 55, 56], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_totp_imported": {"executed_lines": [60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_totp_with_notes": {"executed_lines": [74, 75, 76, 77, 79, 80, 81], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_deterministic_entry": {"executed_lines": [85, 86, 87, 88, 90, 91, 92, 93, 94, 96, 97, 98, 100, 101], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 13, 14, 15, 16, 17, 20, 45, 59, 73, 84], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 25, 27, 28, 30, 31, 32, 34, 36, 37, 40, 41, 42, 45, 46, 47, 48, 49, 50, 52, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 73, 74, 75, 76, 77, 79, 80, 81, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 96, 97, 98, 100, 101], "summary": {"covered_lines": 75, "num_statements": 75, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_totp_uri.py": {"executed_lines": [1, 2, 4, 6, 8, 13, 14, 15, 16, 17, 18, 19, 25, 26, 27, 33, 34, 35, 36, 42, 43, 44, 45, 46, 47], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_parse_otpauth_normal": {"executed_lines": [14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_parse_otpauth_missing_prefix": {"executed_lines": [26, 27], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_parse_otpauth_missing_secret": {"executed_lines": [34, 35, 36], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_make_otpauth_uri_roundtrip": {"executed_lines": [43, 44, 45, 46, 47], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 8, 13, 25, 33, 42], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 8, 13, 14, 15, 16, 17, 18, 19, 25, 26, 27, 33, 34, 35, 36, 42, 43, 44, 45, 46, 47], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_typer_cli.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 15, 18, 19, 21, 22, 23, 25, 29, 30, 31, 32, 33, 36, 37, 45, 46, 47, 48, 51, 52, 53, 55, 56, 66, 67, 68, 69, 72, 73, 75, 76, 77, 79, 80, 81, 82, 83, 84, 85, 88, 89, 91, 92, 94, 95, 96, 97, 98, 99, 100, 103, 104, 106, 107, 108, 110, 111, 113, 114, 117, 118, 119, 120, 121, 122, 125, 126, 128, 129, 131, 132, 133, 134, 135, 138, 139, 141, 142, 143, 145, 152, 153, 154, 155, 156, 159, 160, 162, 163, 164, 166, 173, 174, 175, 176, 177, 180, 181, 183, 184, 186, 189, 190, 191, 196, 197, 200, 201, 207, 208, 209, 210, 213, 214, 218, 219, 220, 221, 224, 225, 227, 228, 230, 235, 236, 237, 238, 241, 242, 244, 245, 247, 251, 252, 253, 254, 257, 258, 260, 261, 263, 266, 267, 268, 269, 272, 273, 279, 280, 281, 282, 285, 286, 288, 289, 291, 295, 296, 297, 298, 299, 302, 303, 306, 307, 308, 309, 312, 313, 315, 316, 317, 323, 324, 325, 326, 327, 328, 329, 330, 333, 334, 336, 337, 338, 339, 341, 346, 351, 374, 375, 376, 386, 389, 391, 393, 394, 395, 397, 398, 400, 401, 402, 405, 407, 409, 410, 411, 412, 414, 415, 416, 417, 420, 421, 423, 424, 425, 426, 428, 433, 434, 462, 463, 464, 465, 477, 478, 480, 483, 485, 490, 491, 492, 493, 496, 497, 498, 500, 505, 506, 507, 508, 511, 512, 514, 515, 517, 522, 523, 524, 525, 526, 529, 530, 532, 533, 535, 540, 541, 542, 543, 544, 547, 548, 550, 558, 560, 561, 562, 563, 564, 567, 568, 570, 574, 575, 576, 577, 580, 581, 583, 588, 589, 590, 591, 594, 595, 597, 602, 603, 604, 605, 608, 610, 612, 613, 614, 616, 617, 621, 622, 623, 626, 627, 629, 630, 632, 637, 638, 639, 640, 643, 646, 648, 649, 650, 653, 656, 658, 659, 660, 662, 664, 666, 667, 669, 671, 673, 674, 676, 682, 683, 684, 685], "summary": {"covered_lines": 345, "num_statements": 345, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_entry_list": {"executed_lines": [19, 21, 25, 29, 30, 31, 32, 33], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_list.list_entries": {"executed_lines": [22, 23], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_search": {"executed_lines": [37, 45, 46, 47, 48], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_get_password": {"executed_lines": [52, 55, 56, 66, 67, 68, 69], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_get_password.search": {"executed_lines": [53], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_export": {"executed_lines": [73, 75, 79, 80, 81, 82, 83, 84, 85], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_export.export_profile": {"executed_lines": [76, 77], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import": {"executed_lines": [89, 91, 94, 95, 96, 97, 98, 99, 100], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import.import_profile": {"executed_lines": [92], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_triggers_sync": {"executed_lines": [104, 106, 110, 113, 114, 117, 118, 119, 120, 121, 122], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_triggers_sync.import_profile": {"executed_lines": [107, 108], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_triggers_sync.sync_vault": {"executed_lines": [111], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_change_password": {"executed_lines": [126, 128, 131, 132, 133, 134, 135], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_change_password.change_pw": {"executed_lines": [129], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_lock": {"executed_lines": [139, 141, 145, 152, 153, 154, 155, 156], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_lock.lock": {"executed_lines": [142, 143], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_root_lock": {"executed_lines": [160, 162, 166, 173, 174, 175, 176, 177], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_root_lock.lock": {"executed_lines": [163, 164], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_reveal_parent_seed": {"executed_lines": [181, 183, 186, 189, 190, 191, 196, 197], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_reveal_parent_seed.reveal": {"executed_lines": [184], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_nostr_get_pubkey": {"executed_lines": [201, 207, 208, 209, 210], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fingerprint_list": {"executed_lines": [214, 218, 219, 220, 221], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fingerprint_add": {"executed_lines": [225, 227, 230, 235, 236, 237, 238], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fingerprint_add.add": {"executed_lines": [228], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fingerprint_remove": {"executed_lines": [242, 244, 247, 251, 252, 253, 254], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fingerprint_remove.remove": {"executed_lines": [245], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fingerprint_switch": {"executed_lines": [258, 260, 263, 266, 267, 268, 269], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fingerprint_switch.switch": {"executed_lines": [261], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_config_get": {"executed_lines": [273, 279, 280, 281, 282], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_config_set": {"executed_lines": [286, 288, 291, 295, 296, 297, 298, 299], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_config_set.set_timeout": {"executed_lines": [289], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_config_set_unknown_key": {"executed_lines": [303, 306, 307, 308, 309], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_nostr_sync": {"executed_lines": [313, 315, 323, 324, 325, 326, 327, 328, 329, 330], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_nostr_sync.sync_vault": {"executed_lines": [316, 317], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password": {"executed_lines": [334, 336, 341, 346, 351, 374, 375, 376, 386], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password.gen_pw": {"executed_lines": [337, 338, 339], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_api_start_passes_fingerprint": {"executed_lines": [391, 393, 397, 398, 400, 401, 402], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_api_start_passes_fingerprint.fake_start": {"executed_lines": [394, 395], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_list_passes_fingerprint": {"executed_lines": [407, 409, 410, 414, 415, 416, 417], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_list_passes_fingerprint.PM.__init__": {"executed_lines": [411, 412], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_add": {"executed_lines": [421, 423, 428, 433, 434, 462, 463, 464, 465], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_add.add_entry": {"executed_lines": [424, 425, 426], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_modify": {"executed_lines": [478, 480, 485, 490, 491, 492, 493], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_modify.modify_entry": {"executed_lines": [483], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_modify_invalid": {"executed_lines": [497, 500, 505, 506, 507, 508], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_modify_invalid.modify_entry": {"executed_lines": [498], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_archive": {"executed_lines": [512, 514, 517, 522, 523, 524, 525, 526], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_archive.archive_entry": {"executed_lines": [515], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_unarchive": {"executed_lines": [530, 532, 535, 540, 541, 542, 543, 544], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_unarchive.restore_entry": {"executed_lines": [533], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_export_totp": {"executed_lines": [548, 550, 558, 560, 561, 562, 563, 564], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_totp_codes": {"executed_lines": [568, 570, 574, 575, 576, 577], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_verify_checksum_command": {"executed_lines": [581, 583, 588, 589, 590, 591], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_checksum_command": {"executed_lines": [595, 597, 602, 603, 604, 605], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_tui_forward_fingerprint": {"executed_lines": [610, 612, 616, 617, 621, 622, 623], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_tui_forward_fingerprint.fake_main": {"executed_lines": [613, 614], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_gui_command": {"executed_lines": [627, 629, 632, 637, 638, 639, 640], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_gui_command.fake_main": {"executed_lines": [630], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_gui_command_no_backend": {"executed_lines": [646, 648, 649, 650], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_gui_command_install_backend": {"executed_lines": [656, 658, 662, 664, 666, 669, 671, 673, 676, 682, 683, 684, 685], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_gui_command_install_backend.backend_available": {"executed_lines": [659, 660], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_gui_command_install_backend.fake_check_call": {"executed_lines": [667], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_gui_command_install_backend.fake_main": {"executed_lines": [674], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 15, 18, 36, 51, 72, 88, 103, 125, 138, 159, 180, 200, 213, 224, 241, 257, 272, 285, 302, 312, 333, 389, 405, 420, 477, 496, 511, 529, 547, 567, 580, 594, 608, 626, 643, 653], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_entry_list_passes_fingerprint.PM": {"executed_lines": [411, 412], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 15, 18, 19, 21, 22, 23, 25, 29, 30, 31, 32, 33, 36, 37, 45, 46, 47, 48, 51, 52, 53, 55, 56, 66, 67, 68, 69, 72, 73, 75, 76, 77, 79, 80, 81, 82, 83, 84, 85, 88, 89, 91, 92, 94, 95, 96, 97, 98, 99, 100, 103, 104, 106, 107, 108, 110, 111, 113, 114, 117, 118, 119, 120, 121, 122, 125, 126, 128, 129, 131, 132, 133, 134, 135, 138, 139, 141, 142, 143, 145, 152, 153, 154, 155, 156, 159, 160, 162, 163, 164, 166, 173, 174, 175, 176, 177, 180, 181, 183, 184, 186, 189, 190, 191, 196, 197, 200, 201, 207, 208, 209, 210, 213, 214, 218, 219, 220, 221, 224, 225, 227, 228, 230, 235, 236, 237, 238, 241, 242, 244, 245, 247, 251, 252, 253, 254, 257, 258, 260, 261, 263, 266, 267, 268, 269, 272, 273, 279, 280, 281, 282, 285, 286, 288, 289, 291, 295, 296, 297, 298, 299, 302, 303, 306, 307, 308, 309, 312, 313, 315, 316, 317, 323, 324, 325, 326, 327, 328, 329, 330, 333, 334, 336, 337, 338, 339, 341, 346, 351, 374, 375, 376, 386, 389, 391, 393, 394, 395, 397, 398, 400, 401, 402, 405, 407, 409, 410, 414, 415, 416, 417, 420, 421, 423, 424, 425, 426, 428, 433, 434, 462, 463, 464, 465, 477, 478, 480, 483, 485, 490, 491, 492, 493, 496, 497, 498, 500, 505, 506, 507, 508, 511, 512, 514, 515, 517, 522, 523, 524, 525, 526, 529, 530, 532, 533, 535, 540, 541, 542, 543, 544, 547, 548, 550, 558, 560, 561, 562, 563, 564, 567, 568, 570, 574, 575, 576, 577, 580, 581, 583, 588, 589, 590, 591, 594, 595, 597, 602, 603, 604, 605, 608, 610, 612, 613, 614, 616, 617, 621, 622, 623, 626, 627, 629, 630, 632, 637, 638, 639, 640, 643, 646, 648, 649, 650, 653, 656, 658, 659, 660, 662, 664, 666, 667, 669, 671, 673, 674, 676, 682, 683, 684, 685], "summary": {"covered_lines": 343, "num_statements": 343, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_unlock_sync.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 26, 28, 29, 30, 31, 33, 36, 37, 38, 39, 41, 42, 45, 47, 48, 49, 51, 53, 54, 56, 58, 60, 63, 64, 65, 66, 67, 69, 70, 72, 73, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87], "summary": {"covered_lines": 61, "num_statements": 61, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_unlock_triggers_sync": {"executed_lines": [15, 16, 17, 18, 19, 20, 21, 23, 26, 28, 29, 30, 31, 33], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_unlock_triggers_sync.fake_sync": {"executed_lines": [24], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_quick_unlock_background_sync": {"executed_lines": [37, 38, 39, 41, 42, 45, 47, 48, 49, 51, 53, 56, 58, 60], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_quick_unlock_background_sync.fake_bg": {"executed_lines": [54], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_sync_running_loop": {"executed_lines": [64, 65, 66, 67, 69, 72, 75, 76, 78, 85, 86, 87], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_sync_running_loop.fake_attempt": {"executed_lines": [70], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_sync_running_loop.fake_sync": {"executed_lines": [73], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_sync_running_loop.runner": {"executed_lines": [79, 80, 81, 82, 83], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 14, 36, 63], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 26, 28, 29, 30, 31, 33, 36, 37, 38, 39, 41, 42, 45, 47, 48, 49, 51, 53, 54, 56, 58, 60, 63, 64, 65, 66, 67, 69, 70, 72, 73, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87], "summary": {"covered_lines": 61, "num_statements": 61, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_v2_prefix_fallback.py": {"executed_lines": [1, 2, 3, 5, 6, 8, 9, 10, 13, 14, 15, 17, 18, 19, 21, 22, 24, 25, 28, 29, 30, 32, 34, 35, 36, 38], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_v2_prefix_fernet_fallback": {"executed_lines": [14, 15, 17, 18, 19, 21, 22, 24, 25], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_aesgcm_payload_too_short": {"executed_lines": [29, 30, 32, 34, 35, 36, 38], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 8, 9, 10, 13, 28], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 8, 9, 10, 13, 14, 15, 17, 18, 19, 21, 22, 24, 25, 28, 29, 30, 32, 34, 35, 36, 38], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_vault_initialization.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 11, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 28, 30, 31], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_save_and_encrypt_seed_initializes_vault": {"executed_lines": [15, 16, 17, 18, 19, 20, 21, 23, 24, 28, 30, 31], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 11, 14], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 11, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 28, 30, 31], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_vault_lock_event.py": {"executed_lines": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 23, 24, 25, 27, 28], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_lock_vault_publishes_event": {"executed_lines": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 23, 24, 25, 27, 28], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_lock_vault_publishes_event.handler": {"executed_lines": [21], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 23, 24, 25, 27, 28], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_vault_lock_flag.py": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 12, 13, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 30, 31, 32, 33, 34, 35, 36, 37, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"DummyEntryManager.__init__": {"executed_lines": [10], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEntryManager.clear_cache": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_lock_vault_sets_flag_and_keeps_objects": {"executed_lines": [17, 18, 19, 20, 21, 22, 23, 24, 25, 26], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_service_requires_unlocked": {"executed_lines": [30, 31, 32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_unlock_vault_clears_locked_flag": {"executed_lines": [41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8, 9, 12, 16, 29, 40], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEntryManager": {"executed_lines": [10, 13], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8, 9, 12, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 30, 31, 32, 33, 34, 35, 36, 37, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_verbose_timing.py": {"executed_lines": [1, 2, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_unlock_vault_logs_time": {"executed_lines": [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_snapshot_logs_time": {"executed_lines": [23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 7, 22], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/utils/__init__.py": {"executed_lines": [3, 5, 7, 9, 10, 19, 27, 28, 29, 30, 31, 37, 40, 41, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 10}, "missing_lines": [], "excluded_lines": [40, 41, 42, 43, 45, 46, 48, 49, 50, 51], "functions": {"": {"executed_lines": [3, 5, 7, 9, 10, 19, 27, 28, 29, 30, 31, 37, 40, 41, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 10}, "missing_lines": [], "excluded_lines": [40, 41, 42, 43, 45, 46, 48, 49, 50, 51]}}, "classes": {"": {"executed_lines": [3, 5, 7, 9, 10, 19, 27, 28, 29, 30, 31, 37, 40, 41, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 10}, "missing_lines": [], "excluded_lines": [40, 41, 42, 43, 45, 46, 48, 49, 50, 51]}}}, "src/utils/atomic_write.py": {"executed_lines": [1, 14, 16, 17, 18, 19, 22, 44, 45, 47, 48, 49, 50, 51, 52, 53, 62], "summary": {"covered_lines": 16, "num_statements": 22, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [54, 55, 56, 57, 58, 59], "excluded_lines": [], "functions": {"atomic_write": {"executed_lines": [44, 45, 47, 48, 49, 50, 51, 52, 53], "summary": {"covered_lines": 9, "num_statements": 15, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [54, 55, 56, 57, 58, 59], "excluded_lines": []}, "": {"executed_lines": [1, 14, 16, 17, 18, 19, 22, 62], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 14, 16, 17, 18, 19, 22, 44, 45, 47, 48, 49, 50, 51, 52, 53, 62], "summary": {"covered_lines": 16, "num_statements": 22, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [54, 55, 56, 57, 58, 59], "excluded_lines": []}}}, "src/utils/checksum.py": {"executed_lines": [3, 13, 14, 15, 16, 17, 18, 20, 22, 23, 26, 29, 31, 34, 36, 37, 40, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 65, 78, 89, 90, 91, 101, 102, 103, 105, 106, 109, 120, 121, 122, 123, 124, 125, 126, 140, 151, 152, 155, 156, 157, 158, 160, 161, 162, 165, 176, 177, 180, 181, 182, 185, 186, 201], "summary": {"covered_lines": 64, "num_statements": 95, "percent_covered": 67.36842105263158, "percent_covered_display": "67", "missing_lines": 31, "excluded_lines": 0}, "missing_lines": [66, 67, 70, 75, 92, 93, 94, 95, 96, 99, 127, 128, 131, 137, 153, 178, 187, 188, 192, 198, 203, 204, 205, 206, 207, 208, 211, 212, 213, 217, 223], "excluded_lines": [], "functions": {"canonical_json_dumps": {"executed_lines": [31], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "json_checksum": {"executed_lines": [36, 37], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "calculate_checksum": {"executed_lines": [50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 65], "summary": {"covered_lines": 12, "num_statements": 16, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [66, 67, 70, 75], "excluded_lines": []}, "verify_checksum": {"executed_lines": [89, 90, 91, 101, 102, 103, 105, 106], "summary": {"covered_lines": 8, "num_statements": 14, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [92, 93, 94, 95, 96, 99], "excluded_lines": []}, "update_checksum": {"executed_lines": [120, 121, 122, 123, 124, 125, 126], "summary": {"covered_lines": 7, "num_statements": 11, "percent_covered": 63.63636363636363, "percent_covered_display": "64", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [127, 128, 131, 137], "excluded_lines": []}, "verify_and_update_checksum": {"executed_lines": [151, 152, 155, 156, 157, 158, 160, 161, 162], "summary": {"covered_lines": 9, "num_statements": 10, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [153], "excluded_lines": []}, "initialize_checksum": {"executed_lines": [176, 177, 180, 181, 182, 185, 186], "summary": {"covered_lines": 7, "num_statements": 12, "percent_covered": 58.333333333333336, "percent_covered_display": "58", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [178, 187, 188, 192, 198], "excluded_lines": []}, "update_checksum_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [203, 204, 205, 206, 207, 208, 211, 212, 213, 217, 223], "excluded_lines": []}, "": {"executed_lines": [3, 13, 14, 15, 16, 17, 18, 20, 22, 23, 26, 29, 34, 40, 78, 109, 140, 165, 201], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 13, 14, 15, 16, 17, 18, 20, 22, 23, 26, 29, 31, 34, 36, 37, 40, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 65, 78, 89, 90, 91, 101, 102, 103, 105, 106, 109, 120, 121, 122, 123, 124, 125, 126, 140, 151, 152, 155, 156, 157, 158, 160, 161, 162, 165, 176, 177, 180, 181, 182, 185, 186, 201], "summary": {"covered_lines": 64, "num_statements": 95, "percent_covered": 67.36842105263158, "percent_covered_display": "67", "missing_lines": 31, "excluded_lines": 0}, "missing_lines": [66, 67, 70, 75, 92, 93, 94, 95, 96, 99, 127, 128, 131, 137, 153, 178, 187, 188, 192, 198, 203, 204, 205, 206, 207, 208, 211, 212, 213, 217, 223], "excluded_lines": []}}}, "src/utils/clipboard.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 11, 12, 15, 18, 20, 21, 22, 23, 24, 25, 35, 38, 40, 42, 43, 44, 46, 47, 48, 49, 52], "summary": {"covered_lines": 25, "num_statements": 26, "percent_covered": 96.15384615384616, "percent_covered_display": "96", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [29], "excluded_lines": [], "functions": {"_ensure_clipboard": {"executed_lines": [20, 21, 22, 23, 24, 25], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [29], "excluded_lines": []}, "copy_to_clipboard": {"executed_lines": [38, 40, 42, 46, 47, 48, 49], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "copy_to_clipboard.clear_clipboard": {"executed_lines": [43, 44], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 11, 12, 15, 18, 35, 52], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"ClipboardUnavailableError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 11, 12, 15, 18, 20, 21, 22, 23, 24, 25, 35, 38, 40, 42, 43, 44, 46, 47, 48, 49, 52], "summary": {"covered_lines": 25, "num_statements": 26, "percent_covered": 96.15384615384616, "percent_covered_display": "96", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [29], "excluded_lines": []}}}, "src/utils/color_scheme.py": {"executed_lines": [1, 3, 6, 7, 10, 12, 16, 29, 31, 32, 33, 34, 35], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_apply_orange": {"executed_lines": [12], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "color_text": {"executed_lines": [31, 32, 33, 34, 35], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 10, 16, 29], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 6, 7, 10, 12, 16, 29, 31, 32, 33, 34, 35], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/utils/file_lock.py": {"executed_lines": [1, 3, 4, 5, 6, 7, 10, 11, 21, 22, 23, 24, 25, 26, 38, 39, 42, 43, 53, 54, 55, 56, 57, 69, 70, 71], "summary": {"covered_lines": 25, "num_statements": 27, "percent_covered": 92.5925925925926, "percent_covered_display": "93", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [32, 63], "excluded_lines": [], "functions": {"exclusive_lock": {"executed_lines": [21, 22, 23, 24, 25, 26, 38, 39], "summary": {"covered_lines": 8, "num_statements": 9, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [32], "excluded_lines": []}, "shared_lock": {"executed_lines": [53, 54, 55, 56, 57, 69, 70, 71], "summary": {"covered_lines": 8, "num_statements": 9, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [63], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 7, 10, 11, 42, 43], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 6, 7, 10, 11, 21, 22, 23, 24, 25, 26, 38, 39, 42, 43, 53, 54, 55, 56, 57, 69, 70, 71], "summary": {"covered_lines": 25, "num_statements": 27, "percent_covered": 92.5925925925926, "percent_covered_display": "93", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [32, 63], "excluded_lines": []}}}, "src/utils/fingerprint.py": {"executed_lines": [3, 11, 12, 13, 16, 19, 30, 32, 33, 36, 37, 40, 41, 43], "summary": {"covered_lines": 13, "num_statements": 16, "percent_covered": 81.25, "percent_covered_display": "81", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [44, 45, 46], "excluded_lines": [], "functions": {"generate_fingerprint": {"executed_lines": [30, 32, 33, 36, 37, 40, 41, 43], "summary": {"covered_lines": 8, "num_statements": 11, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [44, 45, 46], "excluded_lines": []}, "": {"executed_lines": [3, 11, 12, 13, 16, 19], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 11, 12, 13, 16, 19, 30, 32, 33, 36, 37, 40, 41, 43], "summary": {"covered_lines": 13, "num_statements": 16, "percent_covered": 81.25, "percent_covered_display": "81", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [44, 45, 46], "excluded_lines": []}}}, "src/utils/fingerprint_manager.py": {"executed_lines": [3, 4, 5, 6, 7, 9, 11, 12, 15, 18, 19, 27, 34, 35, 36, 37, 43, 50, 51, 56, 60, 61, 62, 69, 71, 72, 73, 74, 75, 76, 77, 78, 81, 82, 85, 90, 94, 95, 100, 104, 111, 122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 141, 154, 155, 156, 157, 158, 159, 162, 164, 165, 166, 167, 168, 171, 172, 173, 174, 175, 176, 182, 183, 185, 192, 193, 195, 205, 206, 207, 208, 209, 214, 225, 227, 229, 231, 232, 234, 244, 245, 246], "summary": {"covered_lines": 94, "num_statements": 122, "percent_covered": 77.04918032786885, "percent_covered_display": "77", "missing_lines": 28, "excluded_lines": 0}, "missing_lines": [53, 54, 63, 64, 67, 86, 87, 88, 107, 108, 109, 138, 139, 169, 170, 177, 180, 211, 212, 216, 217, 218, 219, 221, 222, 223, 248, 249], "excluded_lines": [], "functions": {"FingerprintManager.__init__": {"executed_lines": [34, 35, 36, 37], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FingerprintManager.get_current_fingerprint_dir": {"executed_lines": [50, 51], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [53, 54], "excluded_lines": []}, "FingerprintManager._ensure_app_directory": {"executed_lines": [60, 61, 62], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [63, 64, 67], "excluded_lines": []}, "FingerprintManager._load_fingerprints": {"executed_lines": [71, 72, 73, 74, 75, 76, 77, 78, 81, 82, 85], "summary": {"covered_lines": 11, "num_statements": 14, "percent_covered": 78.57142857142857, "percent_covered_display": "79", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [86, 87, 88], "excluded_lines": []}, "FingerprintManager._save_fingerprints": {"executed_lines": [94, 95, 100, 104], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [107, 108, 109], "excluded_lines": []}, "FingerprintManager.add_fingerprint": {"executed_lines": [122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136], "summary": {"covered_lines": 14, "num_statements": 16, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [138, 139], "excluded_lines": []}, "FingerprintManager.remove_fingerprint": {"executed_lines": [154, 155, 156, 157, 158, 159, 162, 164, 165, 166, 167, 168, 171, 172, 173, 174, 175, 176, 182, 183], "summary": {"covered_lines": 20, "num_statements": 24, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [169, 170, 177, 180], "excluded_lines": []}, "FingerprintManager.list_fingerprints": {"executed_lines": [192, 193], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FingerprintManager.select_fingerprint": {"executed_lines": [205, 206, 207, 208, 209], "summary": {"covered_lines": 5, "num_statements": 7, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [211, 212], "excluded_lines": []}, "FingerprintManager.set_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [216, 217, 218, 219, 221, 222, 223], "excluded_lines": []}, "FingerprintManager.get_name": {"executed_lines": [227], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FingerprintManager.display_name": {"executed_lines": [231, 232], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FingerprintManager.get_fingerprint_directory": {"executed_lines": [244, 245, 246], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [248, 249], "excluded_lines": []}, "": {"executed_lines": [3, 4, 5, 6, 7, 9, 11, 12, 15, 18, 19, 27, 43, 56, 69, 90, 111, 141, 185, 195, 214, 225, 229, 234], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FingerprintManager": {"executed_lines": [34, 35, 36, 37, 50, 51, 60, 61, 62, 71, 72, 73, 74, 75, 76, 77, 78, 81, 82, 85, 94, 95, 100, 104, 122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 154, 155, 156, 157, 158, 159, 162, 164, 165, 166, 167, 168, 171, 172, 173, 174, 175, 176, 182, 183, 192, 193, 205, 206, 207, 208, 209, 227, 231, 232, 244, 245, 246], "summary": {"covered_lines": 71, "num_statements": 99, "percent_covered": 71.71717171717172, "percent_covered_display": "72", "missing_lines": 28, "excluded_lines": 0}, "missing_lines": [53, 54, 63, 64, 67, 86, 87, 88, 107, 108, 109, 138, 139, 169, 170, 177, 180, 211, 212, 216, 217, 218, 219, 221, 222, 223, 248, 249], "excluded_lines": []}, "": {"executed_lines": [3, 4, 5, 6, 7, 9, 11, 12, 15, 18, 19, 27, 43, 56, 69, 90, 111, 141, 185, 195, 214, 225, 229, 234], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/utils/imghdr_stub.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 77, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 77, "excluded_lines": 39}, "missing_lines": [7, 9, 10, 12, 14, 25, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 51, 54, 56, 57, 58, 59, 62, 65, 67, 68, 71, 74, 76, 77, 80, 83, 85, 86, 89, 92, 94, 95, 98, 101, 103, 104, 107, 110, 112, 113, 116, 119, 121, 122, 125, 128, 130, 131, 134, 137, 139, 140, 143, 146, 148, 149, 152, 155, 157, 158, 161, 164, 166, 167, 170], "excluded_lines": [178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 219, 220], "functions": {"what": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44], "excluded_lines": []}, "test_jpeg": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [56, 57, 58, 59], "excluded_lines": []}, "test_png": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [67, 68], "excluded_lines": []}, "test_gif": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [76, 77], "excluded_lines": []}, "test_tiff": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [85, 86], "excluded_lines": []}, "test_rgb": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [94, 95], "excluded_lines": []}, "test_pbm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [103, 104], "excluded_lines": []}, "test_pgm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [112, 113], "excluded_lines": []}, "test_ppm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [121, 122], "excluded_lines": []}, "test_rast": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [130, 131], "excluded_lines": []}, "test_xbm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [139, 140], "excluded_lines": []}, "test_bmp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [148, 149], "excluded_lines": []}, "test_webp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [157, 158], "excluded_lines": []}, "test_exr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [166, 167], "excluded_lines": []}, "test": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 14}, "missing_lines": [], "excluded_lines": [179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192]}, "testall": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 21}, "missing_lines": [], "excluded_lines": [196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216]}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 4}, "missing_lines": [7, 9, 10, 12, 14, 25, 51, 54, 62, 65, 71, 74, 80, 83, 89, 92, 98, 101, 107, 110, 116, 119, 125, 128, 134, 137, 143, 146, 152, 155, 161, 164, 170], "excluded_lines": [178, 195, 219, 220]}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 77, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 77, "excluded_lines": 39}, "missing_lines": [7, 9, 10, 12, 14, 25, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 51, 54, 56, 57, 58, 59, 62, 65, 67, 68, 71, 74, 76, 77, 80, 83, 85, 86, 89, 92, 94, 95, 98, 101, 103, 104, 107, 110, 112, 113, 116, 119, 121, 122, 125, 128, 130, 131, 134, 137, 139, 140, 143, 146, 148, 149, 152, 155, 157, 158, 161, 164, 166, 167, 170], "excluded_lines": [178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 219, 220]}}}, "src/utils/input_utils.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 13, 25, 48], "summary": {"covered_lines": 10, "num_statements": 40, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 30, "excluded_lines": 4}, "missing_lines": [15, 16, 17, 18, 19, 20, 21, 22, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 50, 51, 52, 54, 55, 58], "excluded_lines": [9, 10, 27, 28], "functions": {"_timed_input_posix": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [15, 16, 17, 18, 19, 20, 21, 22], "excluded_lines": []}, "_timed_input_windows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 2}, "missing_lines": [29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45], "excluded_lines": [27, 28]}, "timed_input": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [50, 51, 52, 54, 55, 58], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 13, 25, 48], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [9, 10]}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 13, 25, 48], "summary": {"covered_lines": 10, "num_statements": 40, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 30, "excluded_lines": 4}, "missing_lines": [15, 16, 17, 18, 19, 20, 21, 22, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 50, 51, 52, 54, 55, 58], "excluded_lines": [9, 10, 27, 28]}}}, "src/utils/key_derivation.py": {"executed_lines": [3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 30, 31, 32, 35, 38, 39, 41, 44, 47, 49, 53, 54, 55, 57, 58, 59, 66, 71, 74, 96, 97, 98, 100, 101, 104, 105, 108, 111, 113, 115, 116, 123, 126, 127, 129, 136, 147, 151, 152, 153, 155, 156, 157, 166, 172, 214, 216, 217, 218, 219, 222, 224, 227, 229, 230, 233, 234, 236, 237, 238, 239, 240, 242, 243, 244, 245, 251], "summary": {"covered_lines": 77, "num_statements": 117, "percent_covered": 65.8119658119658, "percent_covered_display": "66", "missing_lines": 40, "excluded_lines": 5}, "missing_lines": [109, 131, 132, 133, 148, 149, 181, 183, 186, 188, 189, 191, 194, 201, 203, 204, 208, 209, 210, 211, 231, 246, 247, 248, 279, 280, 281, 282, 283, 284, 285, 289, 290, 291, 292, 293, 295, 296, 297, 298], "excluded_lines": [49, 50, 167, 168, 169], "functions": {"derive_key_from_password": {"executed_lines": [96, 97, 98, 100, 101, 104, 105, 108, 111, 113, 115, 116, 123, 126, 127, 129], "summary": {"covered_lines": 16, "num_statements": 20, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [109, 131, 132, 133], "excluded_lines": []}, "derive_key_from_password_argon2": {"executed_lines": [147, 151, 152, 153, 155, 156, 157, 166], "summary": {"covered_lines": 8, "num_statements": 10, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 2, "excluded_lines": 3}, "missing_lines": [148, 149], "excluded_lines": [167, 168, 169]}, "derive_key_from_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [181, 183, 186, 188, 189, 191, 194, 201, 203, 204, 208, 209, 210, 211], "excluded_lines": []}, "derive_index_key_seed_only": {"executed_lines": [216, 217, 218, 219], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "derive_index_key": {"executed_lines": [224], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "derive_totp_secret": {"executed_lines": [229, 230, 233, 234, 236, 237, 238, 239, 240, 242, 243, 244, 245], "summary": {"covered_lines": 13, "num_statements": 17, "percent_covered": 76.47058823529412, "percent_covered_display": "76", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [231, 246, 247, 248], "excluded_lines": []}, "calibrate_argon2_time_cost": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [279, 280, 281, 282, 283, 284, 285, 289, 290, 291, 292, 293, 295, 296, 297, 298], "excluded_lines": []}, "": {"executed_lines": [3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 30, 31, 32, 35, 38, 39, 41, 44, 47, 49, 53, 54, 55, 57, 58, 59, 66, 71, 74, 136, 172, 214, 222, 227, 251], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [49, 50]}}, "classes": {"EncryptionMode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "KdfConfig": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 30, 31, 32, 35, 38, 39, 41, 44, 47, 49, 53, 54, 55, 57, 58, 59, 66, 71, 74, 96, 97, 98, 100, 101, 104, 105, 108, 111, 113, 115, 116, 123, 126, 127, 129, 136, 147, 151, 152, 153, 155, 156, 157, 166, 172, 214, 216, 217, 218, 219, 222, 224, 227, 229, 230, 233, 234, 236, 237, 238, 239, 240, 242, 243, 244, 245, 251], "summary": {"covered_lines": 77, "num_statements": 117, "percent_covered": 65.8119658119658, "percent_covered_display": "66", "missing_lines": 40, "excluded_lines": 5}, "missing_lines": [109, 131, 132, 133, 148, 149, 181, 183, 186, 188, 189, 191, 194, 201, 203, 204, 208, 209, 210, 211, 231, 246, 247, 248, 279, 280, 281, 282, 283, 284, 285, 289, 290, 291, 292, 293, 295, 296, 297, 298], "excluded_lines": [49, 50, 167, 168, 169]}}}, "src/utils/key_hierarchy.py": {"executed_lines": [1, 3, 4, 5, 8, 21, 28], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"kd": {"executed_lines": [21, 28], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 8], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 8, 21, 28], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/utils/key_validation.py": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 10, 13, 15, 16, 17, 18, 19, 20, 23, 25, 26, 27, 35, 41, 43, 44, 45, 51, 53, 54, 55, 56, 57, 63, 65, 66], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 15}, "missing_lines": [], "excluded_lines": [18, 19, 20, 36, 37, 38, 46, 47, 48, 58, 59, 60, 67, 68, 69], "functions": {"validate_totp_secret": {"executed_lines": [15, 16, 17, 18, 19, 20], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [18, 19, 20]}, "validate_ssh_key_pair": {"executed_lines": [25, 26, 27, 35], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [36, 37, 38]}, "validate_pgp_private_key": {"executed_lines": [43, 44, 45], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [46, 47, 48]}, "validate_nostr_keys": {"executed_lines": [53, 54, 55, 56, 57], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [58, 59, 60]}, "validate_seed_phrase": {"executed_lines": [65, 66], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [67, 68, 69]}, "": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 10, 13, 23, 41, 51, 63], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 10, 13, 15, 16, 17, 18, 19, 20, 23, 25, 26, 27, 35, 41, 43, 44, 45, 51, 53, 54, 55, 56, 57, 63, 65, 66], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 15}, "missing_lines": [], "excluded_lines": [18, 19, 20, 36, 37, 38, 46, 47, 48, 58, 59, 60, 67, 68, 69]}}}, "src/utils/logging_utils.py": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 12, 15, 18, 19, 21, 24, 25, 26, 32, 35, 38, 41, 44, 45, 47, 48, 49, 51, 54, 57, 58, 59, 60, 62], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 13}, "missing_lines": [], "excluded_lines": [12, 13, 14, 15, 21, 22, 23, 24, 25, 26, 27, 28, 29], "functions": {"ConsolePauseFilter.filter": {"executed_lines": [15], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [15]}, "ChecksumWarningFilter.filter": {"executed_lines": [24, 25, 26], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [24, 25, 26, 27, 28, 29]}, "pause_console_logging": {"executed_lines": [35], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "resume_console_logging": {"executed_lines": [41], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "console_logging_paused": {"executed_lines": [47, 48, 49, 51], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pause_logging_for_ui": {"executed_lines": [57, 58, 62], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pause_logging_for_ui.wrapper": {"executed_lines": [59, 60], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 12, 18, 19, 21, 32, 38, 44, 45, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [12, 13, 14, 21, 22, 23]}}, "classes": {"ConsolePauseFilter": {"executed_lines": [15], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [15]}, "ChecksumWarningFilter": {"executed_lines": [24, 25, 26], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [24, 25, 26, 27, 28, 29]}, "": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 12, 18, 19, 21, 32, 35, 38, 41, 44, 45, 47, 48, 49, 51, 54, 57, 58, 59, 60, 62], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [12, 13, 14, 21, 22, 23]}}}, "src/utils/memory_protection.py": {"executed_lines": [1, 3, 4, 10, 11, 17, 18, 19, 20, 21, 22, 23, 25, 27, 29, 31, 32, 33, 34, 36, 38], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"InMemorySecret.__init__": {"executed_lines": [18, 19, 20, 21, 22, 23], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "InMemorySecret.get_bytes": {"executed_lines": [27], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "InMemorySecret.wipe": {"executed_lines": [31, 32, 33, 34], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "InMemorySecret.get_str": {"executed_lines": [38], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 10, 11, 17, 25, 29, 36], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"InMemorySecret": {"executed_lines": [18, 19, 20, 21, 22, 23, 27, 31, 32, 33, 34, 38], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 10, 11, 17, 25, 29, 36], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/utils/password_prompt.py": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 22, 24, 27, 30, 33, 36, 39, 42, 45, 47, 48, 53, 56, 59, 61, 62, 65, 66, 68, 71, 89, 90, 96, 97, 99, 100, 101, 102, 104, 113, 114, 120, 123, 124, 125, 127, 137, 138, 139, 158, 180, 181, 184, 185, 186, 187, 188, 190, 199, 200, 201, 219, 235, 236, 237, 238, 239, 240, 241, 242, 243, 259], "summary": {"covered_lines": 68, "num_statements": 126, "percent_covered": 53.96825396825397, "percent_covered_display": "54", "missing_lines": 58, "excluded_lines": 0}, "missing_lines": [46, 49, 50, 51, 52, 60, 91, 92, 93, 94, 105, 108, 109, 110, 111, 128, 131, 132, 133, 134, 141, 142, 143, 144, 145, 146, 149, 150, 151, 153, 154, 155, 182, 191, 194, 195, 196, 197, 203, 204, 205, 206, 207, 208, 212, 213, 214, 216, 245, 247, 248, 249, 250, 251, 252, 255, 256, 268], "excluded_lines": [], "functions": {"_env_password": {"executed_lines": [39], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_get_max_attempts": {"executed_lines": [45, 47, 48, 53], "summary": {"covered_lines": 4, "num_statements": 9, "percent_covered": 44.44444444444444, "percent_covered_display": "44", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [46, 49, 50, 51, 52], "excluded_lines": []}, "_apply_backoff": {"executed_lines": [59, 61, 62], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [60], "excluded_lines": []}, "prompt_new_password": {"executed_lines": [89, 90, 96, 97, 99, 100, 101, 102, 104, 113, 114, 120, 123, 124, 125, 127, 137, 138, 139], "summary": {"covered_lines": 19, "num_statements": 45, "percent_covered": 42.22222222222222, "percent_covered_display": "42", "missing_lines": 26, "excluded_lines": 0}, "missing_lines": [91, 92, 93, 94, 105, 108, 109, 110, 111, 128, 131, 132, 133, 134, 141, 142, 143, 144, 145, 146, 149, 150, 151, 153, 154, 155], "excluded_lines": []}, "prompt_existing_password": {"executed_lines": [180, 181, 184, 185, 186, 187, 188, 190, 199, 200, 201], "summary": {"covered_lines": 11, "num_statements": 27, "percent_covered": 40.74074074074074, "percent_covered_display": "41", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [182, 191, 194, 195, 196, 197, 203, 204, 205, 206, 207, 208, 212, 213, 214, 216], "excluded_lines": []}, "confirm_action": {"executed_lines": [235, 236, 237, 238, 239, 240, 241, 242, 243], "summary": {"covered_lines": 9, "num_statements": 18, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [245, 247, 248, 249, 250, 251, 252, 255, 256], "excluded_lines": []}, "prompt_for_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [268], "excluded_lines": []}, "": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 22, 24, 27, 30, 33, 36, 42, 56, 65, 66, 68, 71, 158, 219, 259], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"PasswordPromptError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 22, 24, 27, 30, 33, 36, 39, 42, 45, 47, 48, 53, 56, 59, 61, 62, 65, 66, 68, 71, 89, 90, 96, 97, 99, 100, 101, 102, 104, 113, 114, 120, 123, 124, 125, 127, 137, 138, 139, 158, 180, 181, 184, 185, 186, 187, 188, 190, 199, 200, 201, 219, 235, 236, 237, 238, 239, 240, 241, 242, 243, 259], "summary": {"covered_lines": 68, "num_statements": 126, "percent_covered": 53.96825396825397, "percent_covered_display": "54", "missing_lines": 58, "excluded_lines": 0}, "missing_lines": [46, 49, 50, 51, 52, 60, 91, 92, 93, 94, 105, 108, 109, 110, 111, 128, 131, 132, 133, 134, 141, 142, 143, 144, 145, 146, 149, 150, 151, 153, 154, 155, 182, 191, 194, 195, 196, 197, 203, 204, 205, 206, 207, 208, 212, 213, 214, 216, 245, 247, 248, 249, 250, 251, 252, 255, 256, 268], "excluded_lines": []}}}, "src/utils/seed_prompt.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 17, 18, 20, 23, 31, 33, 34, 39, 42, 45, 47, 48, 51, 53, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 71, 72, 73, 76, 78, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 102, 104, 107, 109, 110, 111, 112, 113, 114, 118, 121, 150, 152, 153, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 184, 185, 186, 187, 188, 189, 190, 191, 194, 195, 196, 211, 212, 213, 214], "summary": {"covered_lines": 107, "num_statements": 128, "percent_covered": 83.59375, "percent_covered_display": "84", "missing_lines": 21, "excluded_lines": 11}, "missing_lines": [32, 35, 36, 37, 38, 46, 67, 68, 69, 168, 197, 198, 199, 200, 201, 204, 205, 206, 207, 208, 209], "excluded_lines": [7, 8, 13, 14, 15, 53, 54, 78, 79, 115, 116], "functions": {"_get_max_attempts": {"executed_lines": [31, 33, 34, 39], "summary": {"covered_lines": 4, "num_statements": 9, "percent_covered": 44.44444444444444, "percent_covered_display": "44", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [32, 35, 36, 37, 38], "excluded_lines": []}, "_apply_backoff": {"executed_lines": [45, 47, 48], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [46], "excluded_lines": []}, "_masked_input_windows": {"executed_lines": [53, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 71, 72, 73], "summary": {"covered_lines": 14, "num_statements": 17, "percent_covered": 82.3529411764706, "percent_covered_display": "82", "missing_lines": 3, "excluded_lines": 2}, "missing_lines": [67, 68, 69], "excluded_lines": [53, 54]}, "_masked_input_posix": {"executed_lines": [78, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 102, 104], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [78, 79]}, "masked_input": {"executed_lines": [109, 110, 111, 112, 113, 114, 118], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [115, 116]}, "prompt_seed_words": {"executed_lines": [150, 152, 153, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 184, 185, 186, 187, 188, 189, 190, 191, 194, 195, 196, 211, 212, 213, 214], "summary": {"covered_lines": 40, "num_statements": 52, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [168, 197, 198, 199, 200, 201, 204, 205, 206, 207, 208, 209], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 17, 18, 20, 23, 42, 51, 76, 107, 121], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 5}, "missing_lines": [], "excluded_lines": [7, 8, 13, 14, 15]}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 17, 18, 20, 23, 31, 33, 34, 39, 42, 45, 47, 48, 51, 53, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 71, 72, 73, 76, 78, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 102, 104, 107, 109, 110, 111, 112, 113, 114, 118, 121, 150, 152, 153, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 184, 185, 186, 187, 188, 189, 190, 191, 194, 195, 196, 211, 212, 213, 214], "summary": {"covered_lines": 107, "num_statements": 128, "percent_covered": 83.59375, "percent_covered_display": "84", "missing_lines": 21, "excluded_lines": 11}, "missing_lines": [32, 35, 36, 37, 38, 46, 67, 68, 69, 168, 197, 198, 199, 200, 201, 204, 205, 206, 207, 208, 209], "excluded_lines": [7, 8, 13, 14, 15, 53, 54, 78, 79, 115, 116]}}}, "src/utils/terminal_utils.py": {"executed_lines": [1, 3, 4, 5, 7, 9, 12, 14, 16, 17, 18, 21, 22, 25, 26, 29, 31, 34, 57, 73, 82, 83, 84, 86, 87, 88, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 106, 107, 108, 109, 111, 113, 116, 118, 119], "summary": {"covered_lines": 42, "num_statements": 75, "percent_covered": 56.0, "percent_covered_display": "56", "missing_lines": 33, "excluded_lines": 6}, "missing_lines": [15, 19, 20, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 85, 89, 110, 120, 121, 122, 123], "excluded_lines": [21, 22, 25, 102, 103, 104], "functions": {"format_profile": {"executed_lines": [14, 16, 17, 18, 21, 22, 25, 26], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 3}, "missing_lines": [15, 19, 20], "excluded_lines": [21, 22, 25]}, "clear_screen": {"executed_lines": [31], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "clear_and_print_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54], "excluded_lines": []}, "clear_and_print_profile_chain": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [61, 62, 63, 64, 65, 66, 67, 68, 69, 70], "excluded_lines": []}, "clear_header_with_notification": {"executed_lines": [82, 83, 84, 86, 87, 88, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 106, 107, 108, 109, 111, 113], "summary": {"covered_lines": 23, "num_statements": 26, "percent_covered": 88.46153846153847, "percent_covered_display": "88", "missing_lines": 3, "excluded_lines": 3}, "missing_lines": [85, 89, 110], "excluded_lines": [102, 103, 104]}, "pause": {"executed_lines": [118, 119], "summary": {"covered_lines": 2, "num_statements": 6, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [120, 121, 122, 123], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 12, 29, 34, 57, 73, 116], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 7, 9, 12, 14, 16, 17, 18, 21, 22, 25, 26, 29, 31, 34, 57, 73, 82, 83, 84, 86, 87, 88, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 106, 107, 108, 109, 111, 113, 116, 118, 119], "summary": {"covered_lines": 42, "num_statements": 75, "percent_covered": 56.0, "percent_covered_display": "56", "missing_lines": 33, "excluded_lines": 6}, "missing_lines": [15, 19, 20, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 85, 89, 110, 120, 121, 122, 123], "excluded_lines": [21, 22, 25, 102, 103, 104]}}}}, "totals": {"covered_lines": 17094, "num_statements": 19933, "percent_covered": 85.75728691115236, "percent_covered_display": "86", "missing_lines": 2839, "excluded_lines": 290}} \ No newline at end of file diff --git a/artifacts/coverage/coverage.full.json b/artifacts/coverage/coverage.full.json new file mode 100644 index 00000000..4ebafd6f --- /dev/null +++ b/artifacts/coverage/coverage.full.json @@ -0,0 +1 @@ +{"meta": {"format": 3, "version": "7.10.1", "timestamp": "2026-02-23T15:17:26.323310", "branch_coverage": false, "show_contexts": false}, "files": {"src/constants.py": {"executed_lines": [3, 4, 7, 15, 16, 17, 22, 23, 28, 33, 35, 36, 37, 45, 46, 47, 50, 53, 56, 62], "summary": {"covered_lines": 20, "num_statements": 22, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [38, 39], "excluded_lines": [], "functions": {"initialize_app": {"executed_lines": [35, 36, 37], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [38, 39], "excluded_lines": []}, "": {"executed_lines": [3, 4, 7, 15, 16, 17, 22, 23, 28, 33, 45, 46, 47, 50, 53, 56, 62], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 4, 7, 15, 16, 17, 22, 23, 28, 33, 35, 36, 37, 45, 46, 47, 50, 53, 56, 62], "summary": {"covered_lines": 20, "num_statements": 22, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [38, 39], "excluded_lines": []}}}, "src/local_bip85/__init__.py": {"executed_lines": [3, 5, 7, 8, 15], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [9, 10, 11], "excluded_lines": [], "functions": {"": {"executed_lines": [3, 5, 7, 8, 15], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [9, 10, 11], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 5, 7, 8, 15], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [9, 10, 11], "excluded_lines": []}}}, "src/local_bip85/bip85.py": {"executed_lines": [3, 16, 17, 18, 19, 20, 21, 23, 25, 27, 28, 29, 32, 35, 36, 38, 41, 42, 50, 51, 52, 54, 55, 61, 86, 87, 88, 89, 90, 91, 94, 96, 97, 98, 99, 101, 102, 103, 105, 107, 118, 119, 120, 121, 122, 123, 125, 126, 127, 128, 129, 130, 132, 138, 139, 142, 143, 149, 151, 152, 153, 154], "summary": {"covered_lines": 60, "num_statements": 75, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [56, 57, 58, 59, 108, 111, 114, 144, 145, 146, 147, 155, 156, 157, 158], "excluded_lines": [], "functions": {"BIP85.__init__": {"executed_lines": [50, 51, 52, 54, 55], "summary": {"covered_lines": 5, "num_statements": 9, "percent_covered": 55.55555555555556, "percent_covered_display": "56", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [56, 57, 58, 59], "excluded_lines": []}, "BIP85.derive_entropy": {"executed_lines": [86, 87, 88, 89, 90, 91, 94, 96, 97, 98, 99, 101, 102, 103, 105, 107, 118, 119, 120, 121, 122, 123], "summary": {"covered_lines": 22, "num_statements": 25, "percent_covered": 88.0, "percent_covered_display": "88", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [108, 111, 114], "excluded_lines": []}, "BIP85.derive_mnemonic": {"executed_lines": [126, 127, 128, 129, 130, 132, 138, 139, 142, 143], "summary": {"covered_lines": 10, "num_statements": 14, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [144, 145, 146, 147], "excluded_lines": []}, "BIP85.derive_symmetric_key": {"executed_lines": [151, 152, 153, 154], "summary": {"covered_lines": 4, "num_statements": 8, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [155, 156, 157, 158], "excluded_lines": []}, "": {"executed_lines": [3, 16, 17, 18, 19, 20, 21, 23, 25, 27, 28, 29, 32, 35, 36, 38, 41, 42, 61, 125, 149], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"Bip85Error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BIP85": {"executed_lines": [50, 51, 52, 54, 55, 86, 87, 88, 89, 90, 91, 94, 96, 97, 98, 99, 101, 102, 103, 105, 107, 118, 119, 120, 121, 122, 123, 126, 127, 128, 129, 130, 132, 138, 139, 142, 143, 151, 152, 153, 154], "summary": {"covered_lines": 41, "num_statements": 56, "percent_covered": 73.21428571428571, "percent_covered_display": "73", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [56, 57, 58, 59, 108, 111, 114, 144, 145, 146, 147, 155, 156, 157, 158], "excluded_lines": []}, "": {"executed_lines": [3, 16, 17, 18, 19, 20, 21, 23, 25, 27, 28, 29, 32, 35, 36, 38, 41, 42, 61, 125, 149], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/main.py": {"executed_lines": [2, 3, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 33, 40, 41, 42, 47, 49, 51, 58, 60, 61, 62, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 84, 87, 88, 90, 91, 92, 93, 95, 96, 98, 101, 102, 104, 105, 106, 107, 108, 110, 112, 113, 116, 117, 134, 149, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 162, 165, 166, 172, 173, 174, 183, 184, 185, 186, 188, 189, 193, 194, 195, 200, 210, 223, 225, 226, 227, 231, 232, 233, 234, 236, 237, 241, 242, 245, 247, 248, 249, 250, 251, 252, 254, 271, 276, 282, 283, 284, 288, 289, 290, 291, 292, 298, 316, 324, 325, 326, 327, 328, 330, 331, 332, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 363, 372, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 389, 391, 393, 395, 398, 399, 400, 401, 402, 404, 405, 408, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 426, 427, 432, 435, 437, 438, 439, 449, 450, 457, 458, 459, 465, 470, 473, 490, 492, 493, 494, 495, 496, 501, 514, 516, 517, 520, 521, 524, 525, 526, 527, 530, 531, 532, 533, 534, 535, 542, 545, 547, 548, 551, 552, 553, 554, 557, 558, 559, 560, 563, 571, 572, 573, 574, 579, 582, 584, 585, 588, 590, 591, 592, 593, 598, 601, 635, 637, 638, 640, 641, 644, 651, 652, 657, 658, 659, 660, 661, 662, 663, 666, 672, 673, 676, 677, 678, 684, 733, 752, 754, 755, 756, 757, 758, 759, 760, 768, 769, 770, 775, 776, 777, 778, 781, 782, 783, 784, 785, 791, 792, 793, 794, 795, 796, 797, 803, 805, 806, 807, 808, 809, 810, 811, 819, 820, 825, 826, 827, 828, 831, 832, 833, 834, 840, 842, 843, 844, 845, 846, 847, 848, 856, 857, 862, 863, 864, 865, 868, 869, 870, 871, 872, 878, 917, 971, 973, 974, 979, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1006, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1019, 1020, 1023, 1026, 1029, 1032, 1037, 1040, 1041, 1042, 1043, 1046, 1049, 1056, 1058, 1061, 1064, 1067, 1068, 1073, 1081, 1092, 1093, 1094, 1095, 1096, 1097, 1102, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1117, 1118, 1119, 1123, 1124, 1126, 1129, 1130, 1131, 1132, 1133, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1165, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1183, 1184, 1187, 1190, 1193, 1196, 1199, 1202, 1205, 1208, 1209, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1234, 1237, 1247, 1248, 1249, 1250, 1251, 1253, 1254, 1255, 1256, 1260, 1265, 1270, 1276, 1278, 1279, 1280, 1286, 1287, 1289, 1290, 1292, 1293, 1295, 1296, 1298, 1300, 1301, 1302, 1310, 1311, 1312, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1327, 1328, 1329, 1335, 1338, 1339, 1340, 1350, 1352, 1355, 1356, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1368, 1369, 1370, 1371, 1372, 1373, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1403, 1404, 1405, 1406, 1407, 1416, 1418, 1430, 1431, 1433, 1434, 1470, 1473], "summary": {"covered_lines": 578, "num_statements": 1067, "percent_covered": 54.170571696344894, "percent_covered_display": "54", "missing_lines": 489, "excluded_lines": 5}, "missing_lines": [8, 63, 64, 124, 125, 126, 127, 128, 129, 131, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 161, 175, 181, 190, 191, 201, 202, 204, 205, 206, 207, 216, 217, 218, 219, 220, 228, 229, 238, 239, 257, 260, 261, 268, 270, 272, 273, 285, 286, 293, 294, 295, 302, 303, 304, 305, 306, 308, 309, 310, 311, 312, 313, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 365, 366, 388, 390, 392, 394, 396, 403, 428, 429, 430, 440, 446, 447, 453, 454, 455, 456, 466, 467, 468, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 497, 498, 503, 504, 505, 506, 507, 508, 509, 510, 511, 518, 519, 522, 523, 528, 529, 536, 537, 538, 539, 540, 549, 550, 555, 556, 561, 562, 564, 570, 575, 576, 577, 586, 587, 594, 595, 596, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 642, 643, 653, 654, 655, 656, 664, 665, 667, 668, 669, 670, 671, 674, 675, 679, 680, 681, 686, 687, 688, 689, 690, 691, 692, 693, 695, 696, 697, 698, 699, 701, 704, 705, 706, 707, 708, 709, 710, 711, 713, 714, 715, 716, 717, 718, 719, 720, 721, 723, 724, 725, 726, 727, 728, 729, 730, 735, 736, 737, 738, 739, 740, 741, 743, 744, 745, 746, 747, 749, 761, 762, 763, 764, 766, 767, 771, 772, 773, 774, 779, 780, 786, 787, 788, 789, 790, 798, 799, 800, 812, 813, 814, 815, 817, 818, 821, 822, 823, 824, 829, 830, 835, 836, 837, 849, 850, 851, 852, 854, 855, 858, 859, 860, 861, 866, 867, 873, 874, 875, 880, 881, 886, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 914, 919, 920, 921, 922, 923, 924, 925, 926, 927, 929, 930, 935, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 968, 1005, 1007, 1015, 1016, 1017, 1018, 1021, 1022, 1024, 1025, 1027, 1028, 1030, 1031, 1033, 1034, 1035, 1036, 1038, 1039, 1044, 1045, 1047, 1048, 1050, 1051, 1052, 1053, 1054, 1055, 1057, 1059, 1060, 1062, 1063, 1065, 1066, 1070, 1147, 1148, 1185, 1186, 1188, 1189, 1191, 1192, 1194, 1195, 1197, 1198, 1200, 1201, 1203, 1204, 1206, 1207, 1303, 1309, 1313, 1314, 1315, 1316, 1326, 1330, 1331, 1332, 1333, 1336, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1351, 1353, 1374, 1391, 1408, 1409, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1474], "excluded_lines": [333, 334, 367, 368, 369], "functions": {"_warn_missing_optional_dependencies": {"executed_lines": [60, 61, 62], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [63, 64], "excluded_lines": []}, "load_global_config": {"executed_lines": [73, 74, 75, 76, 77, 78, 79, 80, 81], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "configure_logging": {"executed_lines": [87, 88, 90, 91, 92, 93, 95, 96, 98, 101, 102, 104, 105, 106, 107, 108, 110, 112, 113], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "confirm_action": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [124, 125, 126, 127, 128, 129, 131], "excluded_lines": []}, "drain_notifications": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146], "excluded_lines": []}, "get_notification_text": {"executed_lines": [151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 162], "summary": {"covered_lines": 11, "num_statements": 12, "percent_covered": 91.66666666666667, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [161], "excluded_lines": []}, "handle_switch_fingerprint": {"executed_lines": [172, 173, 174, 183, 184, 185, 186, 188, 189, 193, 194, 195, 200], "summary": {"covered_lines": 13, "num_statements": 23, "percent_covered": 56.52173913043478, "percent_covered_display": "57", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [175, 181, 190, 191, 201, 202, 204, 205, 206, 207], "excluded_lines": []}, "handle_add_new_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [216, 217, 218, 219, 220], "excluded_lines": []}, "handle_remove_fingerprint": {"executed_lines": [225, 226, 227, 231, 232, 233, 234, 236, 237, 241, 242, 245, 247, 254, 271], "summary": {"covered_lines": 15, "num_statements": 26, "percent_covered": 57.69230769230769, "percent_covered_display": "58", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [228, 229, 238, 239, 257, 260, 261, 268, 270, 272, 273], "excluded_lines": []}, "handle_remove_fingerprint._cleanup_and_exit": {"executed_lines": [248, 249, 250, 251, 252], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "handle_list_fingerprints": {"executed_lines": [282, 283, 284, 288, 289, 290, 291, 292], "summary": {"covered_lines": 8, "num_statements": 13, "percent_covered": 61.53846153846154, "percent_covered_display": "62", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [285, 286, 293, 294, 295], "excluded_lines": []}, "handle_display_npub": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [302, 303, 304, 305, 306, 308, 309, 310, 311, 312, 313], "excluded_lines": []}, "_display_live_stats": {"executed_lines": [324, 325, 326, 327, 328, 330, 331, 332, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346], "summary": {"covered_lines": 19, "num_statements": 32, "percent_covered": 59.375, "percent_covered_display": "59", "missing_lines": 13, "excluded_lines": 2}, "missing_lines": [348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360], "excluded_lines": [333, 334]}, "handle_display_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 3}, "missing_lines": [365, 366], "excluded_lines": [367, 368, 369]}, "print_matches": {"executed_lines": [377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 389, 391, 393, 395, 398, 399, 400, 401, 402, 404, 405], "summary": {"covered_lines": 22, "num_statements": 28, "percent_covered": 78.57142857142857, "percent_covered_display": "79", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [388, 390, 392, 394, 396, 403], "excluded_lines": []}, "handle_post_to_nostr": {"executed_lines": [414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 426, 427, 432], "summary": {"covered_lines": 14, "num_statements": 17, "percent_covered": 82.3529411764706, "percent_covered_display": "82", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [428, 429, 430], "excluded_lines": []}, "handle_retrieve_from_nostr": {"executed_lines": [437, 438, 439, 449, 450, 457, 458, 459, 465, 470], "summary": {"covered_lines": 10, "num_statements": 20, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [440, 446, 447, 453, 454, 455, 456, 466, 467, 468], "excluded_lines": []}, "handle_view_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487], "excluded_lines": []}, "_safe_close_client_pool": {"executed_lines": [492, 493, 494, 495, 496], "summary": {"covered_lines": 5, "num_statements": 7, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [497, 498], "excluded_lines": []}, "_reload_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [503, 504, 505, 506, 507, 508, 509, 510, 511], "excluded_lines": []}, "handle_add_relay": {"executed_lines": [516, 517, 520, 521, 524, 525, 526, 527, 530, 531, 532, 533, 534, 535, 542], "summary": {"covered_lines": 15, "num_statements": 26, "percent_covered": 57.69230769230769, "percent_covered_display": "58", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [518, 519, 522, 523, 528, 529, 536, 537, 538, 539, 540], "excluded_lines": []}, "handle_remove_relay": {"executed_lines": [547, 548, 551, 552, 553, 554, 557, 558, 559, 560, 563, 571, 572, 573, 574, 579], "summary": {"covered_lines": 16, "num_statements": 27, "percent_covered": 59.25925925925926, "percent_covered_display": "59", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [549, 550, 555, 556, 561, 562, 564, 570, 575, 576, 577], "excluded_lines": []}, "handle_reset_relays": {"executed_lines": [584, 585, 588, 590, 591, 592, 593, 598], "summary": {"covered_lines": 8, "num_statements": 13, "percent_covered": 61.53846153846154, "percent_covered_display": "62", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [586, 587, 594, 595, 596], "excluded_lines": []}, "handle_set_inactivity_timeout": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 30, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 30, "excluded_lines": 0}, "missing_lines": [603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632], "excluded_lines": []}, "handle_set_kdf_iterations": {"executed_lines": [637, 638, 640, 641, 644, 651, 652, 657, 658, 659, 660, 661, 662, 663, 666, 672, 673, 676, 677, 678], "summary": {"covered_lines": 20, "num_statements": 38, "percent_covered": 52.63157894736842, "percent_covered_display": "53", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [642, 643, 653, 654, 655, 656, 664, 665, 667, 668, 669, 670, 671, 674, 675, 679, 680, 681], "excluded_lines": []}, "handle_set_additional_backup_location": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 39, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 39, "excluded_lines": 0}, "missing_lines": [686, 687, 688, 689, 690, 691, 692, 693, 695, 696, 697, 698, 699, 701, 704, 705, 706, 707, 708, 709, 710, 711, 713, 714, 715, 716, 717, 718, 719, 720, 721, 723, 724, 725, 726, 727, 728, 729, 730], "excluded_lines": []}, "handle_set_profile_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [735, 736, 737, 738, 739, 740, 741, 743, 744, 745, 746, 747, 749], "excluded_lines": []}, "handle_toggle_secret_mode": {"executed_lines": [754, 755, 756, 757, 758, 759, 760, 768, 769, 770, 775, 776, 777, 778, 781, 782, 783, 784, 785, 791, 792, 793, 794, 795, 796, 797], "summary": {"covered_lines": 26, "num_statements": 46, "percent_covered": 56.52173913043478, "percent_covered_display": "57", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [761, 762, 763, 764, 766, 767, 771, 772, 773, 774, 779, 780, 786, 787, 788, 789, 790, 798, 799, 800], "excluded_lines": []}, "handle_toggle_quick_unlock": {"executed_lines": [805, 806, 807, 808, 809, 810, 811, 819, 820, 825, 826, 827, 828, 831, 832, 833, 834], "summary": {"covered_lines": 17, "num_statements": 32, "percent_covered": 53.125, "percent_covered_display": "53", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [812, 813, 814, 815, 817, 818, 821, 822, 823, 824, 829, 830, 835, 836, 837], "excluded_lines": []}, "handle_toggle_offline_mode": {"executed_lines": [842, 843, 844, 845, 846, 847, 848, 856, 857, 862, 863, 864, 865, 868, 869, 870, 871, 872], "summary": {"covered_lines": 18, "num_statements": 33, "percent_covered": 54.54545454545455, "percent_covered_display": "55", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [849, 850, 851, 852, 854, 855, 858, 859, 860, 861, 866, 867, 873, 874, 875], "excluded_lines": []}, "handle_profiles_menu": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [880, 881, 886, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 914], "excluded_lines": []}, "handle_nostr_menu": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 39, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 39, "excluded_lines": 0}, "missing_lines": [919, 920, 921, 922, 923, 924, 925, 926, 927, 929, 930, 935, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 968], "excluded_lines": []}, "handle_settings": {"executed_lines": [973, 974, 979, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1006, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1019, 1020, 1023, 1026, 1029, 1032, 1037, 1040, 1041, 1042, 1043, 1046, 1049, 1056, 1058, 1061, 1064, 1067, 1068], "summary": {"covered_lines": 50, "num_statements": 88, "percent_covered": 56.81818181818182, "percent_covered_display": "57", "missing_lines": 38, "excluded_lines": 0}, "missing_lines": [1005, 1007, 1015, 1016, 1017, 1018, 1021, 1022, 1024, 1025, 1027, 1028, 1030, 1031, 1033, 1034, 1035, 1036, 1038, 1039, 1044, 1045, 1047, 1048, 1050, 1051, 1052, 1053, 1054, 1055, 1057, 1059, 1060, 1062, 1063, 1065, 1066, 1070], "excluded_lines": []}, "display_menu": {"executed_lines": [1081, 1092, 1093, 1094, 1095, 1096, 1097, 1102, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1117, 1118, 1119, 1123, 1124, 1126, 1129, 1130, 1131, 1132, 1133, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1165, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1183, 1184, 1187, 1190, 1193, 1196, 1199, 1202, 1205, 1208, 1209, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1234], "summary": {"covered_lines": 89, "num_statements": 107, "percent_covered": 83.17757009345794, "percent_covered_display": "83", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [1147, 1148, 1185, 1186, 1188, 1189, 1191, 1192, 1194, 1195, 1197, 1198, 1200, 1201, 1203, 1204, 1206, 1207], "excluded_lines": []}, "main": {"executed_lines": [1247, 1248, 1249, 1250, 1251, 1253, 1254, 1255, 1256, 1260, 1265, 1270, 1276, 1278, 1279, 1280, 1286, 1287, 1289, 1290, 1292, 1293, 1295, 1296, 1298, 1300, 1301, 1302, 1310, 1311, 1312, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1327, 1328, 1329, 1335, 1338, 1339, 1340, 1350, 1352, 1355, 1356, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1368, 1369, 1370, 1371, 1372, 1373, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1403, 1404, 1405, 1406, 1407, 1416, 1418, 1430, 1431, 1433, 1434, 1470], "summary": {"covered_lines": 100, "num_statements": 159, "percent_covered": 62.893081761006286, "percent_covered_display": "63", "missing_lines": 59, "excluded_lines": 0}, "missing_lines": [1303, 1309, 1313, 1314, 1315, 1316, 1326, 1330, 1331, 1332, 1333, 1336, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1351, 1353, 1374, 1391, 1408, 1409, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469], "excluded_lines": []}, "main.signal_handler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428], "excluded_lines": []}, "": {"executed_lines": [2, 3, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 33, 40, 41, 42, 47, 49, 51, 58, 71, 84, 116, 117, 134, 149, 165, 166, 210, 223, 276, 298, 316, 363, 372, 408, 435, 473, 490, 501, 514, 545, 582, 601, 635, 684, 733, 752, 803, 840, 878, 917, 971, 1073, 1237, 1473], "summary": {"covered_lines": 66, "num_statements": 68, "percent_covered": 97.05882352941177, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [8, 1474], "excluded_lines": []}}, "classes": {"": {"executed_lines": [2, 3, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 33, 40, 41, 42, 47, 49, 51, 58, 60, 61, 62, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 84, 87, 88, 90, 91, 92, 93, 95, 96, 98, 101, 102, 104, 105, 106, 107, 108, 110, 112, 113, 116, 117, 134, 149, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 162, 165, 166, 172, 173, 174, 183, 184, 185, 186, 188, 189, 193, 194, 195, 200, 210, 223, 225, 226, 227, 231, 232, 233, 234, 236, 237, 241, 242, 245, 247, 248, 249, 250, 251, 252, 254, 271, 276, 282, 283, 284, 288, 289, 290, 291, 292, 298, 316, 324, 325, 326, 327, 328, 330, 331, 332, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 363, 372, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 389, 391, 393, 395, 398, 399, 400, 401, 402, 404, 405, 408, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 426, 427, 432, 435, 437, 438, 439, 449, 450, 457, 458, 459, 465, 470, 473, 490, 492, 493, 494, 495, 496, 501, 514, 516, 517, 520, 521, 524, 525, 526, 527, 530, 531, 532, 533, 534, 535, 542, 545, 547, 548, 551, 552, 553, 554, 557, 558, 559, 560, 563, 571, 572, 573, 574, 579, 582, 584, 585, 588, 590, 591, 592, 593, 598, 601, 635, 637, 638, 640, 641, 644, 651, 652, 657, 658, 659, 660, 661, 662, 663, 666, 672, 673, 676, 677, 678, 684, 733, 752, 754, 755, 756, 757, 758, 759, 760, 768, 769, 770, 775, 776, 777, 778, 781, 782, 783, 784, 785, 791, 792, 793, 794, 795, 796, 797, 803, 805, 806, 807, 808, 809, 810, 811, 819, 820, 825, 826, 827, 828, 831, 832, 833, 834, 840, 842, 843, 844, 845, 846, 847, 848, 856, 857, 862, 863, 864, 865, 868, 869, 870, 871, 872, 878, 917, 971, 973, 974, 979, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1006, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1019, 1020, 1023, 1026, 1029, 1032, 1037, 1040, 1041, 1042, 1043, 1046, 1049, 1056, 1058, 1061, 1064, 1067, 1068, 1073, 1081, 1092, 1093, 1094, 1095, 1096, 1097, 1102, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1117, 1118, 1119, 1123, 1124, 1126, 1129, 1130, 1131, 1132, 1133, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1165, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1183, 1184, 1187, 1190, 1193, 1196, 1199, 1202, 1205, 1208, 1209, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1234, 1237, 1247, 1248, 1249, 1250, 1251, 1253, 1254, 1255, 1256, 1260, 1265, 1270, 1276, 1278, 1279, 1280, 1286, 1287, 1289, 1290, 1292, 1293, 1295, 1296, 1298, 1300, 1301, 1302, 1310, 1311, 1312, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1327, 1328, 1329, 1335, 1338, 1339, 1340, 1350, 1352, 1355, 1356, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1368, 1369, 1370, 1371, 1372, 1373, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1403, 1404, 1405, 1406, 1407, 1416, 1418, 1430, 1431, 1433, 1434, 1470, 1473], "summary": {"covered_lines": 578, "num_statements": 1067, "percent_covered": 54.170571696344894, "percent_covered_display": "54", "missing_lines": 489, "excluded_lines": 5}, "missing_lines": [8, 63, 64, 124, 125, 126, 127, 128, 129, 131, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 161, 175, 181, 190, 191, 201, 202, 204, 205, 206, 207, 216, 217, 218, 219, 220, 228, 229, 238, 239, 257, 260, 261, 268, 270, 272, 273, 285, 286, 293, 294, 295, 302, 303, 304, 305, 306, 308, 309, 310, 311, 312, 313, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 365, 366, 388, 390, 392, 394, 396, 403, 428, 429, 430, 440, 446, 447, 453, 454, 455, 456, 466, 467, 468, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 497, 498, 503, 504, 505, 506, 507, 508, 509, 510, 511, 518, 519, 522, 523, 528, 529, 536, 537, 538, 539, 540, 549, 550, 555, 556, 561, 562, 564, 570, 575, 576, 577, 586, 587, 594, 595, 596, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 642, 643, 653, 654, 655, 656, 664, 665, 667, 668, 669, 670, 671, 674, 675, 679, 680, 681, 686, 687, 688, 689, 690, 691, 692, 693, 695, 696, 697, 698, 699, 701, 704, 705, 706, 707, 708, 709, 710, 711, 713, 714, 715, 716, 717, 718, 719, 720, 721, 723, 724, 725, 726, 727, 728, 729, 730, 735, 736, 737, 738, 739, 740, 741, 743, 744, 745, 746, 747, 749, 761, 762, 763, 764, 766, 767, 771, 772, 773, 774, 779, 780, 786, 787, 788, 789, 790, 798, 799, 800, 812, 813, 814, 815, 817, 818, 821, 822, 823, 824, 829, 830, 835, 836, 837, 849, 850, 851, 852, 854, 855, 858, 859, 860, 861, 866, 867, 873, 874, 875, 880, 881, 886, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 914, 919, 920, 921, 922, 923, 924, 925, 926, 927, 929, 930, 935, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 968, 1005, 1007, 1015, 1016, 1017, 1018, 1021, 1022, 1024, 1025, 1027, 1028, 1030, 1031, 1033, 1034, 1035, 1036, 1038, 1039, 1044, 1045, 1047, 1048, 1050, 1051, 1052, 1053, 1054, 1055, 1057, 1059, 1060, 1062, 1063, 1065, 1066, 1070, 1147, 1148, 1185, 1186, 1188, 1189, 1191, 1192, 1194, 1195, 1197, 1198, 1200, 1201, 1203, 1204, 1206, 1207, 1303, 1309, 1313, 1314, 1315, 1316, 1326, 1330, 1331, 1332, 1333, 1336, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1351, 1353, 1374, 1391, 1408, 1409, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1474], "excluded_lines": [333, 334, 367, 368, 369]}}}, "src/nostr/__init__.py": {"executed_lines": [3, 5, 6, 8, 16, 18, 29, 30, 31, 32, 33, 34], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"__getattr__": {"executed_lines": [30, 31, 32, 33, 34], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [3, 5, 6, 8, 16, 18, 29], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 5, 6, 8, 16, 18, 29, 30, 31, 32, 33, 34], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/backup_models.py": {"executed_lines": [1, 2, 5, 6, 7, 10, 11, 12, 14, 15, 16, 17, 20, 21, 22, 24, 25, 26, 27, 28], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [1, 2, 5, 6, 7, 10, 11, 12, 14, 15, 16, 17, 20, 21, 22, 24, 25, 26, 27, 28], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"ChunkMeta": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Manifest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 7, 10, 11, 12, 14, 15, 16, 17, 20, 21, 22, 24, 25, 26, 27, 28], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/client.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 22, 24, 25, 27, 34, 35, 36, 38, 42, 43, 45, 46, 49, 50, 52, 63, 64, 65, 66, 67, 69, 70, 73, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 88, 90, 91, 92, 97, 99, 100, 101, 102, 103, 104, 107, 108, 110, 113], "summary": {"covered_lines": 56, "num_statements": 58, "percent_covered": 96.55172413793103, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 2}, "missing_lines": [93, 94], "excluded_lines": [38, 39], "functions": {"NostrClient.__init__": {"executed_lines": [63, 64, 65, 66, 67, 69, 70, 73, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 88, 90, 91, 92, 97, 99, 100, 101, 102, 103, 104, 107, 108, 110], "summary": {"covered_lines": 32, "num_statements": 34, "percent_covered": 94.11764705882354, "percent_covered_display": "94", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [93, 94], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 22, 24, 25, 27, 34, 35, 36, 38, 42, 43, 45, 46, 49, 50, 52, 113], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [38, 39]}}, "classes": {"NostrClient": {"executed_lines": [63, 64, 65, 66, 67, 69, 70, 73, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 88, 90, 91, 92, 97, 99, 100, 101, 102, 103, 104, 107, 108, 110], "summary": {"covered_lines": 32, "num_statements": 34, "percent_covered": 94.11764705882354, "percent_covered_display": "94", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [93, 94], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 22, 24, 25, 27, 34, 35, 36, 38, 42, 43, 45, 46, 49, 50, 52, 113], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [38, 39]}}}, "src/nostr/coincurve_keys.py": {"executed_lines": [1, 3, 4, 7, 8, 10, 11, 12, 14, 15, 20, 21, 26, 28, 29, 31, 32, 34, 35, 36, 37, 39, 40, 42, 43, 45, 46], "summary": {"covered_lines": 26, "num_statements": 33, "percent_covered": 78.78787878787878, "percent_covered_display": "79", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [13, 17, 18, 22, 23, 24, 38], "excluded_lines": [], "functions": {"Keys.__init__": {"executed_lines": [11, 12, 14, 15, 20, 21, 26], "summary": {"covered_lines": 7, "num_statements": 13, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [13, 17, 18, 22, 23, 24], "excluded_lines": []}, "Keys.hex_to_bech32": {"executed_lines": [31, 32], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Keys.bech32_to_hex": {"executed_lines": [36, 37, 39, 40], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [38], "excluded_lines": []}, "Keys.private_key_hex": {"executed_lines": [43], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Keys.public_key_hex": {"executed_lines": [46], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 7, 8, 10, 28, 29, 34, 35, 42, 45], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"Keys": {"executed_lines": [11, 12, 14, 15, 20, 21, 26, 31, 32, 36, 37, 39, 40, 43, 46], "summary": {"covered_lines": 15, "num_statements": 22, "percent_covered": 68.18181818181819, "percent_covered_display": "68", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [13, 17, 18, 22, 23, 24, 38], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 7, 8, 10, 28, 29, 34, 35, 42, 45], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/connection.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 15, 22, 23, 25, 27, 29, 30, 32, 38, 40, 42, 43, 45, 46, 49, 50, 51, 52, 53, 59, 60, 62, 63, 65, 66, 67, 69, 71, 72, 73, 80, 81, 84, 85, 86, 87, 88, 89, 93, 103, 105, 107, 109, 148, 150, 152, 153, 155, 157, 158, 159, 160, 161, 162, 164, 168, 171, 172, 173, 174, 176, 182, 183, 184, 186, 187, 188, 189, 190, 191, 192, 196, 197, 198, 199, 201, 225, 227, 228, 231, 232], "summary": {"covered_lines": 91, "num_statements": 155, "percent_covered": 58.70967741935484, "percent_covered_display": "59", "missing_lines": 64, "excluded_lines": 0}, "missing_lines": [28, 34, 35, 36, 41, 47, 54, 55, 57, 90, 91, 94, 95, 96, 97, 98, 101, 106, 116, 117, 118, 119, 120, 121, 123, 124, 125, 129, 130, 131, 132, 133, 135, 140, 141, 143, 144, 145, 146, 151, 169, 181, 193, 194, 195, 202, 203, 204, 205, 206, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 229, 230], "excluded_lines": [], "functions": {"ConnectionHandler.connect": {"executed_lines": [27, 29, 30], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [28], "excluded_lines": []}, "ConnectionHandler.initialize_client_pool": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [34, 35, 36], "excluded_lines": []}, "ConnectionHandler._connect_async": {"executed_lines": [40, 42, 43], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [41], "excluded_lines": []}, "ConnectionHandler._initialize_client_pool": {"executed_lines": [46, 49, 50, 51, 52, 53, 59, 60, 62, 63, 65, 66, 67], "summary": {"covered_lines": 13, "num_statements": 17, "percent_covered": 76.47058823529412, "percent_covered_display": "76", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [47, 54, 55, 57], "excluded_lines": []}, "ConnectionHandler._ping_relay": {"executed_lines": [71, 72, 73, 80, 81, 84, 85, 86, 87, 88, 89], "summary": {"covered_lines": 11, "num_statements": 13, "percent_covered": 84.61538461538461, "percent_covered_display": "85", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [90, 91], "excluded_lines": []}, "ConnectionHandler._check_relay_health": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [94, 95, 96, 97, 98, 101], "excluded_lines": []}, "ConnectionHandler.check_relay_health": {"executed_lines": [105, 107], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [106], "excluded_lines": []}, "ConnectionHandler.publish_json_to_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [116, 117, 118, 119, 120, 121, 123, 124, 125, 129, 130, 131, 132, 133, 135, 140, 141, 143, 144, 145, 146], "excluded_lines": []}, "ConnectionHandler.publish_event": {"executed_lines": [150, 152, 153], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [151], "excluded_lines": []}, "ConnectionHandler.update_relays": {"executed_lines": [157, 158, 159, 160, 161, 162], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConnectionHandler.retrieve_json_from_nostr": {"executed_lines": [168, 171, 172, 173, 174, 176, 182, 183, 184, 186, 187, 188, 189, 190, 191, 192, 196, 197, 198, 199], "summary": {"covered_lines": 20, "num_statements": 25, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [169, 181, 193, 194, 195], "excluded_lines": []}, "ConnectionHandler._retrieve_json_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [202, 203, 204, 205, 206, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223], "excluded_lines": []}, "ConnectionHandler.close_client_pool": {"executed_lines": [227, 228, 231, 232], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [229, 230], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 15, 22, 23, 25, 32, 38, 45, 69, 93, 103, 109, 148, 155, 164, 201, 225], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"ConnectionHandler": {"executed_lines": [27, 29, 30, 40, 42, 43, 46, 49, 50, 51, 52, 53, 59, 60, 62, 63, 65, 66, 67, 71, 72, 73, 80, 81, 84, 85, 86, 87, 88, 89, 105, 107, 150, 152, 153, 157, 158, 159, 160, 161, 162, 168, 171, 172, 173, 174, 176, 182, 183, 184, 186, 187, 188, 189, 190, 191, 192, 196, 197, 198, 199, 227, 228, 231, 232], "summary": {"covered_lines": 65, "num_statements": 129, "percent_covered": 50.3875968992248, "percent_covered_display": "50", "missing_lines": 64, "excluded_lines": 0}, "missing_lines": [28, 34, 35, 36, 41, 47, 54, 55, 57, 90, 91, 94, 95, 96, 97, 98, 101, 106, 116, 117, 118, 119, 120, 121, 123, 124, 125, 129, 130, 131, 132, 133, 135, 140, 141, 143, 144, 145, 146, 151, 169, 181, 193, 194, 195, 202, 203, 204, 205, 206, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 229, 230], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 15, 22, 23, 25, 32, 38, 45, 69, 93, 103, 109, 148, 155, 164, 201, 225], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/key_manager.py": {"executed_lines": [3, 4, 5, 7, 8, 9, 12, 13, 15, 18, 19, 21, 36, 37, 41, 46, 47, 48, 49, 54, 57, 58, 64, 71, 72, 73, 74, 75, 80, 82, 83, 85, 89, 90, 91, 92, 97, 111, 122, 129, 131, 138, 140, 147, 148, 149, 150, 151, 152, 157], "summary": {"covered_lines": 49, "num_statements": 84, "percent_covered": 58.333333333333336, "percent_covered_display": "58", "missing_lines": 35, "excluded_lines": 0}, "missing_lines": [38, 42, 60, 61, 62, 76, 77, 78, 93, 94, 95, 99, 100, 103, 106, 107, 108, 109, 113, 114, 117, 118, 119, 120, 153, 154, 155, 159, 160, 161, 162, 163, 164, 165, 166], "excluded_lines": [], "functions": {"KeyManager.__init__": {"executed_lines": [36, 37, 41, 46, 47, 48, 49, 54, 57, 58], "summary": {"covered_lines": 10, "num_statements": 15, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [38, 42, 60, 61, 62], "excluded_lines": []}, "KeyManager.initialize_bip85": {"executed_lines": [71, 72, 73, 74, 75], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [76, 77, 78], "excluded_lines": []}, "KeyManager.generate_nostr_keys": {"executed_lines": [82, 83, 85, 89, 90, 91, 92], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [93, 94, 95], "excluded_lines": []}, "KeyManager.generate_v1_nostr_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [99, 100, 103, 106, 107, 108, 109], "excluded_lines": []}, "KeyManager.generate_legacy_nostr_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [113, 114, 117, 118, 119, 120], "excluded_lines": []}, "KeyManager.get_public_key_hex": {"executed_lines": [129], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "KeyManager.get_private_key_hex": {"executed_lines": [138], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "KeyManager.get_npub": {"executed_lines": [147, 148, 149, 150, 151, 152], "summary": {"covered_lines": 6, "num_statements": 9, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [153, 154, 155], "excluded_lines": []}, "KeyManager.get_nsec": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [159, 160, 161, 162, 163, 164, 165, 166], "excluded_lines": []}, "": {"executed_lines": [3, 4, 5, 7, 8, 9, 12, 13, 15, 18, 19, 21, 64, 80, 97, 111, 122, 131, 140, 157], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"KeyManager": {"executed_lines": [36, 37, 41, 46, 47, 48, 49, 54, 57, 58, 71, 72, 73, 74, 75, 82, 83, 85, 89, 90, 91, 92, 129, 138, 147, 148, 149, 150, 151, 152], "summary": {"covered_lines": 30, "num_statements": 65, "percent_covered": 46.15384615384615, "percent_covered_display": "46", "missing_lines": 35, "excluded_lines": 0}, "missing_lines": [38, 42, 60, 61, 62, 76, 77, 78, 93, 94, 95, 99, 100, 103, 106, 107, 108, 109, 113, 114, 117, 118, 119, 120, 153, 154, 155, 159, 160, 161, 162, 163, 164, 165, 166], "excluded_lines": []}, "": {"executed_lines": [3, 4, 5, 7, 8, 9, 12, 13, 15, 18, 19, 21, 64, 80, 97, 111, 122, 131, 140, 157], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/snapshot.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 25, 26, 29, 33, 34, 35, 36, 37, 45, 46, 49, 57, 58, 59, 62, 63, 65, 68, 69, 71, 72, 73, 75, 76, 77, 78, 79, 81, 82, 83, 86, 87, 90, 91, 92, 93, 99, 104, 105, 107, 108, 110, 120, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 137, 140, 141, 142, 143, 144, 158, 159, 160, 162, 167, 168, 169, 170, 172, 173, 174, 175, 176, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 204, 206, 207, 208, 212, 214, 215, 216, 217, 218, 219, 221, 225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 245, 265, 266, 267, 268, 269, 277, 279, 281, 283, 284, 285, 286, 287, 292, 293, 294, 295, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 312, 314, 316, 317, 318, 319, 320, 321, 328, 329, 330, 333, 335, 336, 337, 338, 339, 342, 343, 344, 345, 346, 348, 349, 351, 352, 353, 354, 355, 358, 359, 360, 361, 364, 366, 367, 368, 369, 370, 381, 389, 390, 391, 392, 394, 395, 397, 398, 399, 405, 406, 407, 410, 411, 412, 413, 414, 415, 416, 420, 421, 422, 423, 424, 427, 430, 431, 433, 434, 435, 437, 438, 439, 441, 442, 443], "summary": {"covered_lines": 232, "num_statements": 264, "percent_covered": 87.87878787878788, "percent_covered_display": "88", "missing_lines": 32, "excluded_lines": 11}, "missing_lines": [70, 84, 85, 96, 97, 155, 156, 205, 209, 210, 211, 213, 246, 252, 253, 262, 263, 282, 290, 291, 308, 309, 310, 315, 331, 332, 334, 340, 341, 350, 365, 396], "excluded_lines": [236, 237, 238, 243, 254, 255, 256, 261, 270, 271, 272], "functions": {"prepare_snapshot": {"executed_lines": [33, 34, 35, 36, 37, 45, 46], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "new_manifest_id": {"executed_lines": [57, 58, 59], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SnapshotHandler.publish_snapshot": {"executed_lines": [68, 69, 71, 72, 73, 75, 76, 77, 78, 79, 81, 82, 83, 86, 87, 90, 91, 92, 93, 99, 104, 105, 107, 108, 110, 120, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135], "summary": {"covered_lines": 36, "num_statements": 41, "percent_covered": 87.8048780487805, "percent_covered_display": "88", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [70, 84, 85, 96, 97], "excluded_lines": []}, "SnapshotHandler._fetch_chunks_with_retry": {"executed_lines": [140, 141, 142, 143, 144, 158, 159, 160, 162, 167, 168, 169, 170, 172, 173, 174, 175, 176, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 204, 206, 207, 208, 212, 214, 215, 216, 217, 218, 219], "summary": {"covered_lines": 50, "num_statements": 57, "percent_covered": 87.71929824561404, "percent_covered_display": "88", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [155, 156, 205, 209, 210, 211, 213], "excluded_lines": []}, "SnapshotHandler._fetch_manifest_with_keys": {"executed_lines": [225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 245, 265, 266, 267, 268, 269, 277], "summary": {"covered_lines": 17, "num_statements": 22, "percent_covered": 77.27272727272727, "percent_covered_display": "77", "missing_lines": 5, "excluded_lines": 11}, "missing_lines": [246, 252, 253, 262, 263], "excluded_lines": [236, 237, 238, 243, 254, 255, 256, 261, 270, 271, 272]}, "SnapshotHandler.fetch_latest_snapshot": {"executed_lines": [281, 283, 284, 285, 286, 287, 292, 293, 294, 295, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307], "summary": {"covered_lines": 20, "num_statements": 26, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [282, 290, 291, 308, 309, 310], "excluded_lines": []}, "SnapshotHandler.ensure_manifest_is_current": {"executed_lines": [314, 316, 317, 318, 319, 320, 321, 328, 329, 330, 333, 335, 336, 337, 338, 339, 342, 343, 344, 345, 346], "summary": {"covered_lines": 21, "num_statements": 27, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [315, 331, 332, 334, 340, 341], "excluded_lines": []}, "SnapshotHandler.publish_delta": {"executed_lines": [349, 351, 352, 353, 354, 355, 358, 359, 360, 361, 364, 366, 367, 368, 369, 370, 381, 389, 390, 391, 392], "summary": {"covered_lines": 21, "num_statements": 23, "percent_covered": 91.30434782608695, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [350, 365], "excluded_lines": []}, "SnapshotHandler.fetch_deltas_since": {"executed_lines": [395, 397, 398, 399, 405, 406, 407, 410, 411, 412, 413, 414, 415, 416, 420, 421, 422, 423, 424, 427, 430, 431], "summary": {"covered_lines": 22, "num_statements": 23, "percent_covered": 95.65217391304348, "percent_covered_display": "96", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [396], "excluded_lines": []}, "SnapshotHandler.get_current_manifest": {"executed_lines": [434, 435], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SnapshotHandler.get_current_manifest_id": {"executed_lines": [438, 439], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SnapshotHandler.get_delta_events": {"executed_lines": [442, 443], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 25, 26, 29, 49, 62, 63, 65, 137, 221, 279, 312, 348, 394, 433, 437, 441], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"SnapshotHandler": {"executed_lines": [68, 69, 71, 72, 73, 75, 76, 77, 78, 79, 81, 82, 83, 86, 87, 90, 91, 92, 93, 99, 104, 105, 107, 108, 110, 120, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 140, 141, 142, 143, 144, 158, 159, 160, 162, 167, 168, 169, 170, 172, 173, 174, 175, 176, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 204, 206, 207, 208, 212, 214, 215, 216, 217, 218, 219, 225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 245, 265, 266, 267, 268, 269, 277, 281, 283, 284, 285, 286, 287, 292, 293, 294, 295, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 314, 316, 317, 318, 319, 320, 321, 328, 329, 330, 333, 335, 336, 337, 338, 339, 342, 343, 344, 345, 346, 349, 351, 352, 353, 354, 355, 358, 359, 360, 361, 364, 366, 367, 368, 369, 370, 381, 389, 390, 391, 392, 395, 397, 398, 399, 405, 406, 407, 410, 411, 412, 413, 414, 415, 416, 420, 421, 422, 423, 424, 427, 430, 431, 434, 435, 438, 439, 442, 443], "summary": {"covered_lines": 193, "num_statements": 225, "percent_covered": 85.77777777777777, "percent_covered_display": "86", "missing_lines": 32, "excluded_lines": 11}, "missing_lines": [70, 84, 85, 96, 97, 155, 156, 205, 209, 210, 211, 213, 246, 252, 253, 262, 263, 282, 290, 291, 308, 309, 310, 315, 331, 332, 334, 340, 341, 350, 365, 396], "excluded_lines": [236, 237, 238, 243, 254, 255, 256, 261, 270, 271, 272]}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 25, 26, 29, 33, 34, 35, 36, 37, 45, 46, 49, 57, 58, 59, 62, 63, 65, 137, 221, 279, 312, 348, 394, 433, 437, 441], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/__init__.py": {"executed_lines": [1], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [1], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/api.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 20, 22, 23, 24, 25, 27, 28, 29, 31, 32, 33, 35, 36, 38, 41, 42, 43, 44, 47, 48, 50, 51, 52, 53, 56, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 70, 78, 79, 82, 83, 84, 85, 86, 87, 88, 89, 94, 95, 101, 104, 105, 106, 107, 110, 116, 117, 118, 119, 120, 123, 124, 127, 128, 129, 130, 143, 144, 150, 151, 152, 153, 154, 156, 159, 160, 171, 172, 174, 176, 177, 187, 189, 197, 199, 200, 202, 214, 216, 217, 225, 279, 280, 291, 292, 293, 294, 305, 306, 307, 310, 311, 315, 316, 317, 318, 321, 322, 326, 327, 328, 329, 332, 333, 336, 337, 338, 340, 342, 345, 346, 353, 354, 355, 356, 367, 369, 370, 372, 375, 376, 379, 380, 384, 385, 386, 388, 390, 392, 393, 394, 395, 396, 397, 400, 401, 404, 405, 406, 409, 410, 414, 415, 416, 417, 420, 421, 425, 426, 427, 428, 431, 432, 436, 437, 438, 440, 442, 443, 446, 447, 453, 454, 455, 456, 457, 460, 461, 467, 468, 469, 470, 473, 474, 475, 476, 478, 480, 483, 486, 487, 491, 492, 493, 496, 497, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 513, 514, 515, 516, 517, 520, 521, 523, 524, 525, 526, 529, 530, 534, 535, 536, 538, 540, 541, 543, 545, 546, 547, 548, 551, 552, 556, 557, 558, 559, 561, 563, 565, 566, 567, 568, 571, 572, 576, 577, 578, 580, 581, 582, 583, 586, 587, 591, 592, 593, 594, 597, 598, 602, 603, 604, 605, 608, 609, 615, 616, 617, 618, 619, 621, 622, 625, 626, 630, 631, 633, 635, 636, 637, 639, 641, 642, 643, 644, 645, 646, 648, 650, 651, 653, 656, 657, 658, 663, 664, 665, 668, 669, 676, 677, 678, 680, 682, 684, 686, 688, 689, 690, 691, 694, 695, 699, 700, 701, 703, 706, 707, 711, 712, 713, 715, 725, 727, 728, 729, 732, 733, 737, 738, 739, 740, 743, 744, 747, 748, 750], "summary": {"covered_lines": 349, "num_statements": 378, "percent_covered": 92.32804232804233, "percent_covered_display": "92", "missing_lines": 29, "excluded_lines": 0}, "missing_lines": [49, 81, 155, 227, 228, 238, 240, 241, 249, 251, 252, 259, 261, 262, 267, 274, 276, 341, 373, 391, 441, 539, 544, 562, 564, 620, 640, 654, 687], "excluded_lines": [], "functions": {"_get_pm": {"executed_lines": [42, 43, 44], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_check_token": {"executed_lines": [48, 50, 51, 52, 53], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [49], "excluded_lines": []}, "_reload_relays": {"executed_lines": [58, 59, 60, 61, 62, 63, 64, 65, 66, 67], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "start_server": {"executed_lines": [78, 79, 82, 83, 84, 85, 86, 87, 88, 89, 94, 95, 101], "summary": {"covered_lines": 13, "num_statements": 14, "percent_covered": 92.85714285714286, "percent_covered_display": "93", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [81], "excluded_lines": []}, "_require_password": {"executed_lines": [105, 106, 107], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_validate_encryption_path": {"executed_lines": [116, 117, 118, 119, 120], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "search_entry": {"executed_lines": [127, 128, 129, 130], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_entry": {"executed_lines": [150, 151, 152, 153, 154, 156], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [155], "excluded_lines": []}, "create_entry": {"executed_lines": [171, 172, 174, 176, 177, 187, 189, 197, 199, 200, 202, 214, 216, 217, 225], "summary": {"covered_lines": 15, "num_statements": 29, "percent_covered": 51.724137931034484, "percent_covered_display": "52", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [227, 228, 238, 240, 241, 249, 251, 252, 259, 261, 262, 267, 274, 276], "excluded_lines": []}, "update_entry": {"executed_lines": [291, 292, 293, 294, 305, 306, 307], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "archive_entry": {"executed_lines": [315, 316, 317, 318], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "unarchive_entry": {"executed_lines": [326, 327, 328, 329], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_config": {"executed_lines": [336, 337, 338, 340, 342], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [341], "excluded_lines": []}, "update_config": {"executed_lines": [353, 354, 355, 356, 367, 369, 370, 372, 375, 376], "summary": {"covered_lines": 10, "num_statements": 11, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [373], "excluded_lines": []}, "set_secret_mode": {"executed_lines": [384, 385, 386, 388, 390, 392, 393, 394, 395, 396, 397], "summary": {"covered_lines": 11, "num_statements": 12, "percent_covered": 91.66666666666667, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [391], "excluded_lines": []}, "list_fingerprints": {"executed_lines": [404, 405, 406], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "add_fingerprint": {"executed_lines": [414, 415, 416, 417], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "remove_fingerprint": {"executed_lines": [425, 426, 427, 428], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "select_fingerprint": {"executed_lines": [436, 437, 438, 440, 442, 443], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [441], "excluded_lines": []}, "export_totp": {"executed_lines": [453, 454, 455, 456, 457], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_totp_codes": {"executed_lines": [467, 468, 469, 470, 473, 474, 475, 476, 478, 480, 483], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_profile_stats": {"executed_lines": [491, 492, 493], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_notifications": {"executed_lines": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "get_nostr_pubkey": {"executed_lines": [515, 516, 517], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "list_relays": {"executed_lines": [523, 524, 525, 526], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "add_relay": {"executed_lines": [534, 535, 536, 538, 540, 541, 543, 545, 546, 547, 548], "summary": {"covered_lines": 11, "num_statements": 13, "percent_covered": 84.61538461538461, "percent_covered_display": "85", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [539, 544], "excluded_lines": []}, "remove_relay": {"executed_lines": [556, 557, 558, 559, 561, 563, 565, 566, 567, 568], "summary": {"covered_lines": 10, "num_statements": 12, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [562, 564], "excluded_lines": []}, "reset_relays": {"executed_lines": [576, 577, 578, 580, 581, 582, 583], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "verify_checksum": {"executed_lines": [591, 592, 593, 594], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "update_checksum": {"executed_lines": [602, 603, 604, 605], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "export_vault": {"executed_lines": [615, 616, 617, 618, 619, 621, 622], "summary": {"covered_lines": 7, "num_statements": 8, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [620], "excluded_lines": []}, "import_vault": {"executed_lines": [630, 631, 633, 635, 636, 637, 639, 641, 642, 643, 644, 645, 646, 648, 650, 651, 653, 656, 657, 658, 663, 664, 665], "summary": {"covered_lines": 23, "num_statements": 25, "percent_covered": 92.0, "percent_covered_display": "92", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [640, 654], "excluded_lines": []}, "backup_parent_seed": {"executed_lines": [676, 677, 678, 680, 682, 684, 686, 688, 689, 690, 691], "summary": {"covered_lines": 11, "num_statements": 12, "percent_covered": 91.66666666666667, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [687], "excluded_lines": []}, "change_password": {"executed_lines": [699, 700, 701, 703], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "generate_password": {"executed_lines": [711, 712, 713, 715, 725, 727, 728, 729], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "lock_vault": {"executed_lines": [737, 738, 739, 740], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "shutdown_server": {"executed_lines": [747, 748, 750], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 20, 22, 23, 24, 25, 27, 28, 29, 31, 32, 33, 35, 36, 38, 41, 47, 56, 70, 104, 110, 123, 124, 143, 144, 159, 160, 279, 280, 310, 311, 321, 322, 332, 333, 345, 346, 379, 380, 400, 401, 409, 410, 420, 421, 431, 432, 446, 447, 460, 461, 486, 487, 496, 497, 513, 514, 520, 521, 529, 530, 551, 552, 571, 572, 586, 587, 597, 598, 608, 609, 625, 626, 668, 669, 694, 695, 706, 707, 732, 733, 743, 744], "summary": {"covered_lines": 95, "num_statements": 95, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 20, 22, 23, 24, 25, 27, 28, 29, 31, 32, 33, 35, 36, 38, 41, 42, 43, 44, 47, 48, 50, 51, 52, 53, 56, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 70, 78, 79, 82, 83, 84, 85, 86, 87, 88, 89, 94, 95, 101, 104, 105, 106, 107, 110, 116, 117, 118, 119, 120, 123, 124, 127, 128, 129, 130, 143, 144, 150, 151, 152, 153, 154, 156, 159, 160, 171, 172, 174, 176, 177, 187, 189, 197, 199, 200, 202, 214, 216, 217, 225, 279, 280, 291, 292, 293, 294, 305, 306, 307, 310, 311, 315, 316, 317, 318, 321, 322, 326, 327, 328, 329, 332, 333, 336, 337, 338, 340, 342, 345, 346, 353, 354, 355, 356, 367, 369, 370, 372, 375, 376, 379, 380, 384, 385, 386, 388, 390, 392, 393, 394, 395, 396, 397, 400, 401, 404, 405, 406, 409, 410, 414, 415, 416, 417, 420, 421, 425, 426, 427, 428, 431, 432, 436, 437, 438, 440, 442, 443, 446, 447, 453, 454, 455, 456, 457, 460, 461, 467, 468, 469, 470, 473, 474, 475, 476, 478, 480, 483, 486, 487, 491, 492, 493, 496, 497, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 513, 514, 515, 516, 517, 520, 521, 523, 524, 525, 526, 529, 530, 534, 535, 536, 538, 540, 541, 543, 545, 546, 547, 548, 551, 552, 556, 557, 558, 559, 561, 563, 565, 566, 567, 568, 571, 572, 576, 577, 578, 580, 581, 582, 583, 586, 587, 591, 592, 593, 594, 597, 598, 602, 603, 604, 605, 608, 609, 615, 616, 617, 618, 619, 621, 622, 625, 626, 630, 631, 633, 635, 636, 637, 639, 641, 642, 643, 644, 645, 646, 648, 650, 651, 653, 656, 657, 658, 663, 664, 665, 668, 669, 676, 677, 678, 680, 682, 684, 686, 688, 689, 690, 691, 694, 695, 699, 700, 701, 703, 706, 707, 711, 712, 713, 715, 725, 727, 728, 729, 732, 733, 737, 738, 739, 740, 743, 744, 747, 748, 750], "summary": {"covered_lines": 349, "num_statements": 378, "percent_covered": 92.32804232804233, "percent_covered_display": "92", "missing_lines": 29, "excluded_lines": 0}, "missing_lines": [49, 81, 155, 227, 228, 238, 240, 241, 249, 251, 252, 259, 261, 262, 267, 274, 276, 341, 373, 391, 441, 539, 544, 562, 564, 620, 640, 654, 687], "excluded_lines": []}}}, "src/seedpass/cli/__init__.py": {"executed_lines": [1, 3, 4, 5, 6, 7, 9, 11, 12, 14, 20, 27, 33, 40, 42, 43, 44, 45, 46, 47, 48, 51, 60, 62, 63, 64, 68, 69, 79, 84, 85, 86, 89, 90, 92, 93, 94, 97, 98, 111, 112, 113, 114, 115, 131, 132, 137, 139, 145, 150, 151, 162, 171, 178, 180, 183], "summary": {"covered_lines": 55, "num_statements": 78, "percent_covered": 70.51282051282051, "percent_covered_display": "71", "missing_lines": 23, "excluded_lines": 2}, "missing_lines": [53, 54, 55, 56, 57, 65, 116, 117, 118, 119, 120, 121, 122, 123, 125, 129, 142, 143, 163, 164, 169, 172, 176], "excluded_lines": [183, 184], "functions": {"run": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [53, 54, 55, 56, 57], "excluded_lines": []}, "_gui_backend_available": {"executed_lines": [62, 63, 64], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [65], "excluded_lines": []}, "main": {"executed_lines": [79, 84, 85, 86], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "root_lock": {"executed_lines": [92, 93, 94], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "gui": {"executed_lines": [111, 112, 113, 114, 115, 131, 132, 137, 139, 145, 150, 151, 162, 171, 178, 180], "summary": {"covered_lines": 16, "num_statements": 33, "percent_covered": 48.484848484848484, "percent_covered_display": "48", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [116, 117, 118, 119, 120, 121, 122, 123, 125, 129, 142, 143, 163, 164, 169, 172, 176], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 7, 9, 11, 12, 14, 20, 27, 33, 40, 42, 43, 44, 45, 46, 47, 48, 51, 60, 68, 69, 89, 90, 97, 98, 183], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [183, 184]}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 6, 7, 9, 11, 12, 14, 20, 27, 33, 40, 42, 43, 44, 45, 46, 47, 48, 51, 60, 62, 63, 64, 68, 69, 79, 84, 85, 86, 89, 90, 92, 93, 94, 97, 98, 111, 112, 113, 114, 115, 131, 132, 137, 139, 145, 150, 151, 162, 171, 178, 180, 183], "summary": {"covered_lines": 55, "num_statements": 78, "percent_covered": 70.51282051282051, "percent_covered_display": "71", "missing_lines": 23, "excluded_lines": 2}, "missing_lines": [53, 54, 55, 56, 57, 65, 116, 117, 118, 119, 120, 121, 122, 123, 125, 129, 142, 143, 163, 164, 169, 172, 176], "excluded_lines": [183, 184]}}}, "src/seedpass/cli/api.py": {"executed_lines": [1, 3, 4, 6, 8, 11, 12, 14, 15, 18, 21, 22], "summary": {"covered_lines": 12, "num_statements": 15, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 3, "excluded_lines": 2}, "missing_lines": [28, 30, 31], "excluded_lines": [36, 37], "functions": {"api_start": {"executed_lines": [14, 15, 18], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "api_stop": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 2}, "missing_lines": [28, 30, 31], "excluded_lines": [36, 37]}, "": {"executed_lines": [1, 3, 4, 6, 8, 11, 12, 21, 22], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 6, 8, 11, 12, 14, 15, 18, 21, 22], "summary": {"covered_lines": 12, "num_statements": 15, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 3, "excluded_lines": 2}, "missing_lines": [28, 30, 31], "excluded_lines": [36, 37]}}}, "src/seedpass/cli/common.py": {"executed_lines": [1, 3, 5, 6, 7, 23, 25, 26, 27, 29, 30, 32, 34, 37, 42, 43, 46, 47, 48, 51, 52, 53, 56, 57, 58, 61, 62, 63], "summary": {"covered_lines": 28, "num_statements": 30, "percent_covered": 93.33333333333333, "percent_covered_display": "93", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [31, 33], "excluded_lines": [], "functions": {"_get_pm": {"executed_lines": [25, 26, 27, 29, 30, 32, 34], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [31, 33], "excluded_lines": []}, "_get_services": {"executed_lines": [42, 43], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_get_entry_service": {"executed_lines": [47, 48], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_get_config_service": {"executed_lines": [52, 53], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_get_util_service": {"executed_lines": [57, 58], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_get_nostr_service": {"executed_lines": [62, 63], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 23, 37, 46, 51, 56, 61], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 6, 7, 23, 25, 26, 27, 29, 30, 32, 34, 37, 42, 43, 46, 47, 48, 51, 52, 53, 56, 57, 58, 61, 62, 63], "summary": {"covered_lines": 28, "num_statements": 30, "percent_covered": 93.33333333333333, "percent_covered_display": "93", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [31, 33], "excluded_lines": []}}}, "src/seedpass/cli/config.py": {"executed_lines": [1, 3, 5, 7, 10, 11, 13, 14, 15, 16, 18, 21, 22, 24, 26, 27, 32, 33, 34, 35, 40, 43, 44, 50, 51, 52, 53, 58, 59, 66, 67, 68, 71, 74, 75, 76, 77, 84, 85, 90, 91, 94, 95, 97, 98, 99, 104, 105, 112, 114, 115, 117, 118, 123, 124], "summary": {"covered_lines": 55, "num_statements": 62, "percent_covered": 88.70967741935483, "percent_covered_display": "89", "missing_lines": 7, "excluded_lines": 15}, "missing_lines": [69, 78, 79, 80, 81, 82, 113], "excluded_lines": [36, 37, 38, 54, 55, 56, 86, 87, 88, 100, 101, 102, 119, 120, 121], "functions": {"config_get": {"executed_lines": [13, 14, 15, 16, 18], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "config_set": {"executed_lines": [24, 26, 27, 32, 33, 34, 35, 40], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [36, 37, 38]}, "config_toggle_secret_mode": {"executed_lines": [50, 51, 52, 53, 58, 59, 66, 67, 68, 71, 74, 75, 76, 77, 84, 85, 90, 91], "summary": {"covered_lines": 18, "num_statements": 24, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 6, "excluded_lines": 6}, "missing_lines": [69, 78, 79, 80, 81, 82], "excluded_lines": [54, 55, 56, 86, 87, 88]}, "config_toggle_offline": {"executed_lines": [97, 98, 99, 104, 105, 112, 114, 115, 117, 118, 123, 124], "summary": {"covered_lines": 12, "num_statements": 13, "percent_covered": 92.3076923076923, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 6}, "missing_lines": [113], "excluded_lines": [100, 101, 102, 119, 120, 121]}, "": {"executed_lines": [1, 3, 5, 7, 10, 11, 21, 22, 43, 44, 94, 95], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 7, 10, 11, 13, 14, 15, 16, 18, 21, 22, 24, 26, 27, 32, 33, 34, 35, 40, 43, 44, 50, 51, 52, 53, 58, 59, 66, 67, 68, 71, 74, 75, 76, 77, 84, 85, 90, 91, 94, 95, 97, 98, 99, 104, 105, 112, 114, 115, 117, 118, 123, 124], "summary": {"covered_lines": 55, "num_statements": 62, "percent_covered": 88.70967741935483, "percent_covered_display": "89", "missing_lines": 7, "excluded_lines": 15}, "missing_lines": [69, 78, 79, 80, 81, 82, 113], "excluded_lines": [36, 37, 38, 54, 55, 56, 86, 87, 88, 100, 101, 102, 119, 120, 121]}}}, "src/seedpass/cli/entry.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 12, 13, 15, 18, 19, 33, 34, 39, 40, 41, 42, 43, 44, 45, 47, 50, 51, 63, 64, 65, 66, 69, 70, 71, 72, 73, 75, 78, 79, 81, 82, 83, 84, 87, 96, 97, 98, 99, 100, 101, 102, 109, 110, 115, 118, 119, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 166, 167, 170, 171, 183, 184, 192, 195, 196, 203, 204, 209, 212, 213, 222, 223, 230, 233, 234, 241, 242, 247, 250, 251, 259, 260, 266, 269, 270, 278, 279, 280, 283, 284, 291, 292, 297, 300, 301, 316, 317, 318, 329, 330, 331, 332, 335, 336, 338, 339, 340, 343, 344, 346, 347, 348, 351, 352, 354, 355, 358, 359, 363, 364, 365, 366], "summary": {"covered_lines": 138, "num_statements": 156, "percent_covered": 88.46153846153847, "percent_covered_display": "88", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [46, 67, 68, 74, 85, 86, 88, 89, 90, 91, 92, 93, 94, 103, 104, 105, 107, 108], "excluded_lines": [], "functions": {"entry_list": {"executed_lines": [33, 34, 39, 40, 41, 42, 43, 44, 45, 47], "summary": {"covered_lines": 10, "num_statements": 11, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [46], "excluded_lines": []}, "entry_search": {"executed_lines": [63, 64, 65, 66, 69, 70, 71, 72, 73, 75], "summary": {"covered_lines": 10, "num_statements": 13, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [67, 68, 74], "excluded_lines": []}, "entry_get": {"executed_lines": [81, 82, 83, 84, 87, 96, 97, 98, 99, 100, 101, 102, 109, 110, 115], "summary": {"covered_lines": 15, "num_statements": 29, "percent_covered": 51.724137931034484, "percent_covered_display": "52", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [85, 86, 88, 89, 90, 91, 92, 93, 94, 103, 104, 105, 107, 108], "excluded_lines": []}, "entry_add": {"executed_lines": [147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 166, 167], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_add_totp": {"executed_lines": [183, 184, 192], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_add_ssh": {"executed_lines": [203, 204, 209], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_add_pgp": {"executed_lines": [222, 223, 230], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_add_nostr": {"executed_lines": [241, 242, 247], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_add_seed": {"executed_lines": [259, 260, 266], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_add_key_value": {"executed_lines": [278, 279, 280], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_add_managed_account": {"executed_lines": [291, 292, 297], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_modify": {"executed_lines": [316, 317, 318, 329, 330, 331, 332], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_archive": {"executed_lines": [338, 339, 340], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_unarchive": {"executed_lines": [346, 347, 348], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_totp_codes": {"executed_lines": [354, 355], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "entry_export_totp": {"executed_lines": [363, 364, 365, 366], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 12, 13, 15, 18, 19, 50, 51, 78, 79, 118, 119, 170, 171, 195, 196, 212, 213, 233, 234, 250, 251, 269, 270, 283, 284, 300, 301, 335, 336, 343, 344, 351, 352, 358, 359], "summary": {"covered_lines": 43, "num_statements": 43, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 12, 13, 15, 18, 19, 33, 34, 39, 40, 41, 42, 43, 44, 45, 47, 50, 51, 63, 64, 65, 66, 69, 70, 71, 72, 73, 75, 78, 79, 81, 82, 83, 84, 87, 96, 97, 98, 99, 100, 101, 102, 109, 110, 115, 118, 119, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 166, 167, 170, 171, 183, 184, 192, 195, 196, 203, 204, 209, 212, 213, 222, 223, 230, 233, 234, 241, 242, 247, 250, 251, 259, 260, 266, 269, 270, 278, 279, 280, 283, 284, 291, 292, 297, 300, 301, 316, 317, 318, 329, 330, 331, 332, 335, 336, 338, 339, 340, 343, 344, 346, 347, 348, 351, 352, 354, 355, 358, 359, 363, 364, 365, 366], "summary": {"covered_lines": 138, "num_statements": 156, "percent_covered": 88.46153846153847, "percent_covered_display": "88", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [46, 67, 68, 74, 85, 86, 88, 89, 90, 91, 92, 93, 94, 103, 104, 105, 107, 108], "excluded_lines": []}}}, "src/seedpass/cli/fingerprint.py": {"executed_lines": [1, 3, 5, 7, 10, 11, 13, 14, 15, 18, 19, 21, 22, 25, 26, 28, 29, 32, 33, 35, 36, 37], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"fingerprint_list": {"executed_lines": [13, 14, 15], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "fingerprint_add": {"executed_lines": [21, 22], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "fingerprint_remove": {"executed_lines": [28, 29], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "fingerprint_switch": {"executed_lines": [35, 36, 37], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 7, 10, 11, 18, 19, 25, 26, 32, 33], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 7, 10, 11, 13, 14, 15, 18, 19, 21, 22, 25, 26, 28, 29, 32, 33, 35, 36, 37], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/cli/nostr.py": {"executed_lines": [1, 3, 5, 7, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 28, 29, 31, 32, 33, 36, 37, 39, 40, 41, 42, 45, 46, 48, 49, 50, 54, 57, 58, 60, 61, 62, 66], "summary": {"covered_lines": 38, "num_statements": 39, "percent_covered": 97.43589743589743, "percent_covered_display": "97", "missing_lines": 1, "excluded_lines": 6}, "missing_lines": [25], "excluded_lines": [51, 52, 53, 63, 64, 65], "functions": {"nostr_sync": {"executed_lines": [15, 16, 17, 18, 19, 20, 21, 22, 23], "summary": {"covered_lines": 9, "num_statements": 10, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [25], "excluded_lines": []}, "nostr_get_pubkey": {"executed_lines": [31, 32, 33], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "nostr_list_relays": {"executed_lines": [39, 40, 41, 42], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "nostr_add_relay": {"executed_lines": [48, 49, 50, 54], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [51, 52, 53]}, "nostr_remove_relay": {"executed_lines": [60, 61, 62, 66], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [63, 64, 65]}, "": {"executed_lines": [1, 3, 5, 7, 12, 13, 28, 29, 36, 37, 45, 46, 57, 58], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 7, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 28, 29, 31, 32, 33, 36, 37, 39, 40, 41, 42, 45, 46, 48, 49, 50, 54, 57, 58, 60, 61, 62, 66], "summary": {"covered_lines": 38, "num_statements": 39, "percent_covered": 97.43589743589743, "percent_covered_display": "97", "missing_lines": 1, "excluded_lines": 6}, "missing_lines": [25], "excluded_lines": [51, 52, 53, 63, 64, 65]}}}, "src/seedpass/cli/util.py": {"executed_lines": [1, 3, 5, 7, 9, 12, 13, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 57, 58, 61, 62, 64, 65, 68, 69, 71, 72], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"generate_password": {"executed_lines": [38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 57, 58], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "verify_checksum": {"executed_lines": [64, 65], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "update_checksum": {"executed_lines": [71, 72], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 7, 9, 12, 13, 61, 62, 68, 69], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 7, 9, 12, 13, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 57, 58, 61, 62, 64, 65, 68, 69, 71, 72], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/cli/vault.py": {"executed_lines": [1, 3, 4, 5, 7, 9, 16, 19, 20, 24, 25, 26, 27, 30, 31, 35, 36, 37, 38, 41, 42, 44, 45, 46, 47, 48, 54, 57, 58, 60, 61, 62, 63, 67, 70, 71, 73, 74, 75, 78, 79, 81, 82, 83, 86, 87, 94, 95, 96], "summary": {"covered_lines": 49, "num_statements": 49, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [51, 52, 53, 64, 65, 66], "functions": {"vault_export": {"executed_lines": [24, 25, 26, 27], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "vault_import": {"executed_lines": [35, 36, 37, 38], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "vault_change_password": {"executed_lines": [44, 45, 46, 47, 48, 54], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [51, 52, 53]}, "vault_unlock": {"executed_lines": [60, 61, 62, 63, 67], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [64, 65, 66]}, "vault_lock": {"executed_lines": [73, 74, 75], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "vault_stats": {"executed_lines": [81, 82, 83], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "vault_reveal_parent_seed": {"executed_lines": [94, 95, 96], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 16, 19, 20, 30, 31, 41, 42, 57, 58, 70, 71, 78, 79, 86, 87], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 7, 9, 16, 19, 20, 24, 25, 26, 27, 30, 31, 35, 36, 37, 38, 41, 42, 44, 45, 46, 47, 48, 54, 57, 58, 60, 61, 62, 63, 67, 70, 71, 73, 74, 75, 78, 79, 81, 82, 83, 86, 87, 94, 95, 96], "summary": {"covered_lines": 49, "num_statements": 49, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [51, 52, 53, 64, 65, 66]}}}, "src/seedpass/core/__init__.py": {"executed_lines": [3, 5, 7, 17, 18, 20, 22, 24, 26, 28, 30], "summary": {"covered_lines": 10, "num_statements": 16, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [19, 21, 23, 25, 27, 29], "excluded_lines": [], "functions": {"__getattr__": {"executed_lines": [18, 20, 22, 24, 26, 28, 30], "summary": {"covered_lines": 7, "num_statements": 13, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [19, 21, 23, 25, 27, 29], "excluded_lines": []}, "": {"executed_lines": [3, 5, 7, 17], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 5, 7, 17, 18, 20, 22, 24, 26, 28, 30], "summary": {"covered_lines": 10, "num_statements": 16, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [19, 21, 23, 25, 27, 29], "excluded_lines": []}}}, "src/seedpass/core/api.py": {"executed_lines": [1, 3, 10, 11, 12, 13, 14, 16, 18, 19, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 41, 42, 44, 45, 48, 49, 51, 54, 55, 57, 60, 61, 63, 64, 67, 68, 70, 71, 74, 75, 77, 80, 81, 83, 84, 85, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 108, 109, 112, 113, 116, 117, 119, 120, 121, 123, 126, 127, 128, 130, 133, 134, 135, 137, 140, 141, 142, 145, 147, 150, 151, 154, 155, 156, 158, 161, 162, 164, 167, 168, 169, 171, 174, 175, 177, 180, 181, 185, 188, 189, 192, 193, 195, 196, 197, 199, 202, 203, 205, 208, 209, 210, 214, 217, 218, 220, 223, 224, 227, 228, 230, 231, 232, 234, 237, 238, 239, 240, 241, 242, 243, 245, 248, 249, 251, 254, 255, 258, 259, 261, 262, 263, 265, 271, 272, 278, 291, 292, 294, 295, 296, 298, 299, 300, 301, 302, 303, 304, 306, 307, 308, 311, 313, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 355, 356, 358, 368, 369, 370, 379, 380, 382, 389, 390, 396, 397, 399, 408, 409, 417, 418, 420, 427, 428, 434, 435, 437, 445, 446, 453, 454, 456, 459, 460, 463, 464, 466, 473, 474, 480, 481, 483, 496, 497, 508, 510, 511, 512, 513, 515, 516, 517, 518, 520, 521, 522, 525, 527, 528, 529, 532, 533, 535, 536, 537, 539, 540, 541, 543, 544, 545, 581, 582, 583, 584, 585, 586, 587, 592, 593, 595, 597, 598, 599, 601, 602, 603, 605, 606, 607, 608, 609, 610, 611, 613, 614, 615, 617, 618, 619, 620, 621, 624, 625, 627, 628, 629, 631, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 660, 662, 665, 666, 670, 671, 673, 674, 676, 677, 678, 680, 681, 682, 685, 686, 688, 689, 690, 692, 693, 694, 696, 697, 698, 700, 701, 702, 703, 707, 708, 709, 710], "summary": {"covered_lines": 322, "num_statements": 325, "percent_covered": 99.07692307692308, "percent_covered_display": "99", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [659, 661, 663], "excluded_lines": [], "functions": {"VaultService.__init__": {"executed_lines": [120, 121], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.export_vault": {"executed_lines": [126, 127, 128], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.import_vault": {"executed_lines": [133, 134, 135], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.export_profile": {"executed_lines": [140, 141, 142, 145], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.import_profile": {"executed_lines": [150, 151, 154, 155, 156], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.change_password": {"executed_lines": [161, 162], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.unlock": {"executed_lines": [167, 168, 169], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.lock": {"executed_lines": [174, 175], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.backup_parent_seed": {"executed_lines": [180, 181], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService.stats": {"executed_lines": [188, 189], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileService.__init__": {"executed_lines": [196, 197], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileService.list_profiles": {"executed_lines": [202, 203], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileService.add_profile": {"executed_lines": [208, 209, 210], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileService.remove_profile": {"executed_lines": [217, 218], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileService.switch_profile": {"executed_lines": [223, 224], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SyncService.__init__": {"executed_lines": [231, 232], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SyncService.sync": {"executed_lines": [237, 238, 239, 240, 241, 242, 243], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SyncService.start_background_sync": {"executed_lines": [248, 249], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SyncService.start_background_vault_sync": {"executed_lines": [254, 255], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.__init__": {"executed_lines": [262, 263], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.list_entries": {"executed_lines": [271, 272], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.search_entries": {"executed_lines": [291, 292], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.retrieve_entry": {"executed_lines": [295, 296], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.generate_password": {"executed_lines": [299, 300, 301, 302, 303, 304], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.get_totp_code": {"executed_lines": [307, 308, 311], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.add_entry": {"executed_lines": [329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 355, 356], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.add_totp": {"executed_lines": [368, 369, 370, 379, 380], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.add_ssh_key": {"executed_lines": [389, 390, 396, 397], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.add_pgp_key": {"executed_lines": [408, 409, 417, 418], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.add_nostr_key": {"executed_lines": [427, 428, 434, 435], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.add_seed": {"executed_lines": [445, 446, 453, 454], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.add_key_value": {"executed_lines": [459, 460, 463, 464], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.add_managed_account": {"executed_lines": [473, 474, 480, 481], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.modify_entry": {"executed_lines": [496, 497, 508], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.archive_entry": {"executed_lines": [511, 512, 513], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.restore_entry": {"executed_lines": [516, 517, 518], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.export_totp_entries": {"executed_lines": [521, 522, 525], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.display_totp_codes": {"executed_lines": [528, 529], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService.__init__": {"executed_lines": [536, 537], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService.get": {"executed_lines": [540, 541], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService.set": {"executed_lines": [544, 545, 581, 582, 583, 584, 585, 586, 587, 592, 593, 595], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService.get_secret_mode_enabled": {"executed_lines": [598, 599], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService.get_clipboard_clear_delay": {"executed_lines": [602, 603], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService.set_secret_mode": {"executed_lines": [606, 607, 608, 609, 610, 611], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService.get_offline_mode": {"executed_lines": [614, 615], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService.set_offline_mode": {"executed_lines": [618, 619, 620, 621], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "UtilityService.__init__": {"executed_lines": [628, 629], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "UtilityService.generate_password": {"executed_lines": [644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 660, 662, 665, 666, 670, 671, 673, 674], "summary": {"covered_lines": 23, "num_statements": 26, "percent_covered": 88.46153846153847, "percent_covered_display": "88", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [659, 661, 663], "excluded_lines": []}, "UtilityService.verify_checksum": {"executed_lines": [677, 678], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "UtilityService.update_checksum": {"executed_lines": [681, 682], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NostrService.__init__": {"executed_lines": [689, 690], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NostrService.get_pubkey": {"executed_lines": [693, 694], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NostrService.list_relays": {"executed_lines": [697, 698], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NostrService.add_relay": {"executed_lines": [701, 702, 703], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "NostrService.remove_relay": {"executed_lines": [708, 709, 710], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 10, 11, 12, 13, 14, 16, 18, 19, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 41, 42, 44, 45, 48, 49, 51, 54, 55, 57, 60, 61, 63, 64, 67, 68, 70, 71, 74, 75, 77, 80, 81, 83, 84, 85, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 108, 109, 112, 113, 116, 117, 119, 123, 130, 137, 147, 158, 164, 171, 177, 185, 192, 193, 195, 199, 205, 214, 220, 227, 228, 230, 234, 245, 251, 258, 259, 261, 265, 278, 294, 298, 306, 313, 358, 382, 399, 420, 437, 456, 466, 483, 510, 515, 520, 527, 532, 533, 535, 539, 543, 597, 601, 605, 613, 617, 624, 625, 627, 631, 676, 680, 685, 686, 688, 692, 696, 700, 707], "summary": {"covered_lines": 116, "num_statements": 116, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"VaultExportRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultExportResponse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultImportRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ChangePasswordRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "UnlockRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "UnlockResponse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BackupParentSeedRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileSwitchRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileRemoveRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SyncResponse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordPolicyOptions": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AddPasswordEntryRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "GeneratePasswordRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "GeneratePasswordResponse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService": {"executed_lines": [120, 121, 126, 127, 128, 133, 134, 135, 140, 141, 142, 145, 150, 151, 154, 155, 156, 161, 162, 167, 168, 169, 174, 175, 180, 181, 188, 189], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileService": {"executed_lines": [196, 197, 202, 203, 208, 209, 210, 217, 218, 223, 224], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SyncService": {"executed_lines": [231, 232, 237, 238, 239, 240, 241, 242, 243, 248, 249, 254, 255], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService": {"executed_lines": [262, 263, 271, 272, 291, 292, 295, 296, 299, 300, 301, 302, 303, 304, 307, 308, 311, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 355, 356, 368, 369, 370, 379, 380, 389, 390, 396, 397, 408, 409, 417, 418, 427, 428, 434, 435, 445, 446, 453, 454, 459, 460, 463, 464, 473, 474, 480, 481, 496, 497, 508, 511, 512, 513, 516, 517, 518, 521, 522, 525, 528, 529], "summary": {"covered_lines": 81, "num_statements": 81, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigService": {"executed_lines": [536, 537, 540, 541, 544, 545, 581, 582, 583, 584, 585, 586, 587, 592, 593, 595, 598, 599, 602, 603, 606, 607, 608, 609, 610, 611, 614, 615, 618, 619, 620, 621], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "UtilityService": {"executed_lines": [628, 629, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 660, 662, 665, 666, 670, 671, 673, 674, 677, 678, 681, 682], "summary": {"covered_lines": 29, "num_statements": 32, "percent_covered": 90.625, "percent_covered_display": "91", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [659, 661, 663], "excluded_lines": []}, "NostrService": {"executed_lines": [689, 690, 693, 694, 697, 698, 701, 702, 703, 708, 709, 710], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 10, 11, 12, 13, 14, 16, 18, 19, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 41, 42, 44, 45, 48, 49, 51, 54, 55, 57, 60, 61, 63, 64, 67, 68, 70, 71, 74, 75, 77, 80, 81, 83, 84, 85, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 108, 109, 112, 113, 116, 117, 119, 123, 130, 137, 147, 158, 164, 171, 177, 185, 192, 193, 195, 199, 205, 214, 220, 227, 228, 230, 234, 245, 251, 258, 259, 261, 265, 278, 294, 298, 306, 313, 358, 382, 399, 420, 437, 456, 466, 483, 510, 515, 520, 527, 532, 533, 535, 539, 543, 597, 601, 605, 613, 617, 624, 625, 627, 631, 676, 680, 685, 686, 688, 692, 696, 700, 707], "summary": {"covered_lines": 116, "num_statements": 116, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/backup.py": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 23, 24, 27, 30, 31, 39, 41, 51, 52, 53, 54, 55, 56, 57, 61, 62, 63, 64, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 89, 90, 95, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 114, 115, 116, 122, 127, 128, 129, 130, 131, 132, 148, 150, 151, 152, 156, 157, 158, 159, 170, 193, 194, 195, 197, 198, 199, 200, 202, 203, 206, 207, 208, 209, 210], "summary": {"covered_lines": 82, "num_statements": 116, "percent_covered": 70.6896551724138, "percent_covered_display": "71", "missing_lines": 34, "excluded_lines": 2}, "missing_lines": [65, 66, 72, 91, 92, 93, 123, 124, 125, 137, 138, 141, 153, 154, 155, 160, 161, 164, 171, 172, 178, 179, 180, 181, 183, 184, 185, 188, 189, 190, 191, 215, 216, 219], "excluded_lines": [108, 109], "functions": {"BackupManager.__init__": {"executed_lines": [51, 52, 53, 54, 55, 56, 57], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BackupManager.create_backup": {"executed_lines": [62, 63, 64, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 89, 90], "summary": {"covered_lines": 17, "num_statements": 23, "percent_covered": 73.91304347826087, "percent_covered_display": "74", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [65, 66, 72, 91, 92, 93], "excluded_lines": []}, "BackupManager._create_additional_backup": {"executed_lines": [97, 98, 99, 101, 102, 103, 104, 105, 106, 107], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [108, 109]}, "BackupManager.restore_latest_backup": {"executed_lines": [115, 116, 122, 127, 128, 129, 130, 131, 132], "summary": {"covered_lines": 9, "num_statements": 15, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [123, 124, 125, 137, 138, 141], "excluded_lines": []}, "BackupManager.restore_from_backup": {"executed_lines": [150, 151, 152, 156, 157, 158, 159], "summary": {"covered_lines": 7, "num_statements": 13, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [153, 154, 155, 160, 161, 164], "excluded_lines": []}, "BackupManager.list_backups": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [171, 172, 178, 179, 180, 181, 183, 184, 185, 188, 189, 190, 191], "excluded_lines": []}, "BackupManager.restore_backup_by_timestamp": {"executed_lines": [194, 195, 197, 198, 199, 200, 202, 203, 206, 207, 208, 209, 210], "summary": {"covered_lines": 13, "num_statements": 16, "percent_covered": 81.25, "percent_covered_display": "81", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [215, 216, 219], "excluded_lines": []}, "": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 23, 24, 27, 30, 31, 39, 41, 61, 95, 114, 148, 170, 193], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"BackupManager": {"executed_lines": [51, 52, 53, 54, 55, 56, 57, 62, 63, 64, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 89, 90, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 115, 116, 122, 127, 128, 129, 130, 131, 132, 150, 151, 152, 156, 157, 158, 159, 194, 195, 197, 198, 199, 200, 202, 203, 206, 207, 208, 209, 210], "summary": {"covered_lines": 63, "num_statements": 97, "percent_covered": 64.94845360824742, "percent_covered_display": "65", "missing_lines": 34, "excluded_lines": 2}, "missing_lines": [65, 66, 72, 91, 92, 93, 123, 124, 125, 137, 138, 141, 153, 154, 155, 160, 161, 164, 171, 172, 178, 179, 180, 181, 183, 184, 185, 188, 189, 190, 191, 215, 216, 219], "excluded_lines": [108, 109]}, "": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 23, 24, 27, 30, 31, 39, 41, 61, 95, 114, 148, 170, 193], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/config_manager.py": {"executed_lines": [1, 3, 5, 6, 7, 9, 11, 13, 14, 16, 18, 21, 24, 25, 27, 29, 30, 31, 32, 34, 43, 44, 45, 71, 72, 73, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 103, 104, 105, 106, 107, 115, 120, 122, 123, 124, 129, 131, 132, 133, 134, 135, 137, 139, 140, 141, 142, 144, 146, 147, 148, 150, 152, 154, 155, 156, 159, 161, 162, 163, 165, 167, 169, 170, 171, 173, 178, 180, 182, 183, 184, 186, 188, 189, 191, 199, 201, 202, 204, 212, 217, 219, 220, 221, 223, 225, 226, 227, 229, 231, 232, 233, 235, 237, 238, 239, 241, 243, 244, 246, 248, 249, 251, 253, 255, 256, 257, 259, 261, 262, 264, 266, 268, 269, 270, 272, 274, 275, 278, 280, 282, 283, 294, 299, 304, 309, 314, 316, 317, 318, 320, 322, 323, 324, 326, 328, 329, 330, 332, 334, 335, 336, 338, 340, 341, 342, 344, 346, 347, 349, 351, 353, 354, 355, 357, 359, 360, 362, 364, 366, 367, 368, 370, 372, 373, 375, 380, 381, 382], "summary": {"covered_lines": 191, "num_statements": 241, "percent_covered": 79.25311203319502, "percent_covered_display": "79", "missing_lines": 50, "excluded_lines": 2}, "missing_lines": [74, 108, 109, 110, 111, 112, 114, 116, 117, 118, 125, 126, 127, 149, 157, 168, 175, 176, 181, 193, 194, 195, 196, 197, 206, 207, 208, 209, 210, 214, 215, 254, 267, 295, 296, 297, 300, 301, 302, 305, 306, 307, 310, 311, 312, 352, 365, 376, 377, 378], "excluded_lines": [18, 19], "functions": {"ConfigManager.__init__": {"executed_lines": [30, 31, 32], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.load_config": {"executed_lines": [43, 44, 45, 71, 72, 73, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 103, 104, 105, 106, 107, 115], "summary": {"covered_lines": 37, "num_statements": 47, "percent_covered": 78.72340425531915, "percent_covered_display": "79", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [74, 108, 109, 110, 111, 112, 114, 116, 117, 118], "excluded_lines": []}, "ConfigManager.save_config": {"executed_lines": [122, 123, 124], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [125, 126, 127], "excluded_lines": []}, "ConfigManager.set_relays": {"executed_lines": [131, 132, 133, 134, 135], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_pin": {"executed_lines": [139, 140, 141, 142], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.verify_pin": {"executed_lines": [146, 147, 148, 150], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [149], "excluded_lines": []}, "ConfigManager.change_pin": {"executed_lines": [154, 155, 156], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [157], "excluded_lines": []}, "ConfigManager.set_password_hash": {"executed_lines": [161, 162, 163], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_inactivity_timeout": {"executed_lines": [167, 169, 170, 171], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [168], "excluded_lines": []}, "ConfigManager.get_inactivity_timeout": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [175, 176], "excluded_lines": []}, "ConfigManager.set_kdf_iterations": {"executed_lines": [180, 182, 183, 184], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [181], "excluded_lines": []}, "ConfigManager.get_kdf_iterations": {"executed_lines": [188, 189], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_kdf_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [193, 194, 195, 196, 197], "excluded_lines": []}, "ConfigManager.get_kdf_mode": {"executed_lines": [201, 202], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_argon2_time_cost": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [206, 207, 208, 209, 210], "excluded_lines": []}, "ConfigManager.get_argon2_time_cost": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [214, 215], "excluded_lines": []}, "ConfigManager.set_additional_backup_path": {"executed_lines": [219, 220, 221], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.get_additional_backup_path": {"executed_lines": [225, 226, 227], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_secret_mode_enabled": {"executed_lines": [231, 232, 233], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_offline_mode": {"executed_lines": [237, 238, 239], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.get_secret_mode_enabled": {"executed_lines": [243, 244], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.get_offline_mode": {"executed_lines": [248, 249], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_clipboard_clear_delay": {"executed_lines": [253, 255, 256, 257], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [254], "excluded_lines": []}, "ConfigManager.get_clipboard_clear_delay": {"executed_lines": [261, 262], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_backup_interval": {"executed_lines": [266, 268, 269, 270], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [267], "excluded_lines": []}, "ConfigManager.get_backup_interval": {"executed_lines": [274, 275], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.get_password_policy": {"executed_lines": [280, 282, 283], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_min_uppercase": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [295, 296, 297], "excluded_lines": []}, "ConfigManager.set_min_lowercase": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [300, 301, 302], "excluded_lines": []}, "ConfigManager.set_min_digits": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [305, 306, 307], "excluded_lines": []}, "ConfigManager.set_min_special": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [310, 311, 312], "excluded_lines": []}, "ConfigManager.set_include_special_chars": {"executed_lines": [316, 317, 318], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_allowed_special_chars": {"executed_lines": [322, 323, 324], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_special_mode": {"executed_lines": [328, 329, 330], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_exclude_ambiguous": {"executed_lines": [334, 335, 336], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_quick_unlock": {"executed_lines": [340, 341, 342], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.get_quick_unlock": {"executed_lines": [346, 347], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_nostr_max_retries": {"executed_lines": [351, 353, 354, 355], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [352], "excluded_lines": []}, "ConfigManager.get_nostr_max_retries": {"executed_lines": [359, 360], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_nostr_retry_delay": {"executed_lines": [364, 366, 367, 368], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [365], "excluded_lines": []}, "ConfigManager.get_nostr_retry_delay": {"executed_lines": [372, 373], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ConfigManager.set_verbose_timing": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [376, 377, 378], "excluded_lines": []}, "ConfigManager.get_verbose_timing": {"executed_lines": [381, 382], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 9, 11, 13, 14, 16, 18, 21, 24, 25, 27, 29, 34, 120, 129, 137, 144, 152, 159, 165, 173, 178, 186, 191, 199, 204, 212, 217, 223, 229, 235, 241, 246, 251, 259, 264, 272, 278, 294, 299, 304, 309, 314, 320, 326, 332, 338, 344, 349, 357, 362, 370, 375, 380], "summary": {"covered_lines": 55, "num_statements": 55, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [18, 19]}}, "classes": {"ConfigManager": {"executed_lines": [30, 31, 32, 43, 44, 45, 71, 72, 73, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 103, 104, 105, 106, 107, 115, 122, 123, 124, 131, 132, 133, 134, 135, 139, 140, 141, 142, 146, 147, 148, 150, 154, 155, 156, 161, 162, 163, 167, 169, 170, 171, 180, 182, 183, 184, 188, 189, 201, 202, 219, 220, 221, 225, 226, 227, 231, 232, 233, 237, 238, 239, 243, 244, 248, 249, 253, 255, 256, 257, 261, 262, 266, 268, 269, 270, 274, 275, 280, 282, 283, 316, 317, 318, 322, 323, 324, 328, 329, 330, 334, 335, 336, 340, 341, 342, 346, 347, 351, 353, 354, 355, 359, 360, 364, 366, 367, 368, 372, 373, 381, 382], "summary": {"covered_lines": 136, "num_statements": 186, "percent_covered": 73.11827956989248, "percent_covered_display": "73", "missing_lines": 50, "excluded_lines": 0}, "missing_lines": [74, 108, 109, 110, 111, 112, 114, 116, 117, 118, 125, 126, 127, 149, 157, 168, 175, 176, 181, 193, 194, 195, 196, 197, 206, 207, 208, 209, 210, 214, 215, 254, 267, 295, 296, 297, 300, 301, 302, 305, 306, 307, 310, 311, 312, 352, 365, 376, 377, 378], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 9, 11, 13, 14, 16, 18, 21, 24, 25, 27, 29, 34, 120, 129, 137, 144, 152, 159, 165, 173, 178, 186, 191, 199, 204, 212, 217, 223, 229, 235, 241, 246, 251, 259, 264, 272, 278, 294, 299, 304, 309, 314, 320, 326, 332, 338, 344, 349, 357, 362, 370, 375, 380], "summary": {"covered_lines": 55, "num_statements": 55, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [18, 19]}}}, "src/seedpass/core/encryption.py": {"executed_lines": [3, 4, 6, 7, 9, 10, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 35, 38, 40, 41, 42, 45, 46, 48, 49, 52, 53, 56, 57, 62, 71, 72, 74, 75, 79, 80, 82, 83, 85, 94, 95, 97, 99, 105, 106, 107, 108, 110, 111, 112, 117, 131, 133, 135, 136, 137, 138, 139, 144, 145, 146, 147, 152, 153, 154, 155, 156, 157, 158, 161, 162, 163, 166, 167, 168, 171, 181, 182, 183, 184, 185, 188, 192, 193, 198, 199, 200, 206, 211, 212, 213, 214, 215, 218, 219, 220, 221, 222, 223, 225, 228, 234, 237, 238, 239, 247, 266, 267, 268, 269, 271, 275, 276, 277, 279, 281, 282, 283, 285, 286, 289, 291, 292, 293, 295, 297, 298, 299, 300, 303, 311, 312, 313, 316, 317, 318, 319, 320, 321, 322, 325, 330, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 347, 348, 349, 350, 351, 352, 353, 355, 356, 357, 358, 359, 360, 361, 363, 370, 371, 372, 373, 376, 377, 379, 386, 387, 388, 389, 390, 391, 392, 397, 398, 399, 401, 402, 405, 407, 408, 411, 412, 417, 418, 419, 420, 421, 423, 424, 425, 426, 430, 436, 441, 442, 443, 444, 445, 446, 447, 448, 450, 470, 471, 473, 474, 475, 477, 478, 479, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 496, 497, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 512, 515, 516, 517, 518, 521, 527, 528, 560, 562, 563, 564, 565, 568, 569, 570, 571, 572, 575, 576, 579, 580, 581, 582, 589, 590, 591, 592, 593, 594, 595, 603, 609, 610, 611, 612, 613, 614, 619], "summary": {"covered_lines": 285, "num_statements": 343, "percent_covered": 83.09037900874635, "percent_covered_display": "83", "missing_lines": 58, "excluded_lines": 23}, "missing_lines": [76, 86, 87, 91, 109, 113, 114, 115, 140, 141, 172, 173, 176, 240, 241, 301, 315, 375, 395, 414, 427, 428, 429, 437, 438, 439, 481, 529, 530, 531, 535, 541, 542, 543, 566, 583, 584, 596, 597, 601, 615, 616, 617, 620, 621, 622, 623, 625, 626, 627, 628, 630, 631, 632, 633, 634, 635, 636], "excluded_lines": [11, 12, 13, 15, 201, 202, 229, 230, 238, 239, 321, 322, 430, 431, 432, 433, 544, 545, 546, 550, 556, 557, 558], "functions": {"_derive_legacy_key_from_password": {"executed_lines": [40, 41, 42], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "LegacyFormatRequiresMigrationError.__init__": {"executed_lines": [49, 52, 53], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager.__init__": {"executed_lines": [71, 72, 74, 75, 79, 80, 82, 83, 85, 94, 95, 97], "summary": {"covered_lines": 12, "num_statements": 16, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [76, 86, 87, 91], "excluded_lines": []}, "EncryptionManager.encrypt_data": {"executed_lines": [105, 106, 107, 108, 110, 111, 112], "summary": {"covered_lines": 7, "num_statements": 11, "percent_covered": 63.63636363636363, "percent_covered_display": "64", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [109, 113, 114, 115], "excluded_lines": []}, "EncryptionManager.decrypt_data": {"executed_lines": [131, 133, 135, 136, 137, 138, 139, 144, 145, 146, 147, 152, 153, 154, 155, 156, 157, 158, 161, 162, 163, 166, 167, 168, 171, 181, 182, 183, 184, 185, 188, 192, 193, 198, 199, 200], "summary": {"covered_lines": 36, "num_statements": 41, "percent_covered": 87.8048780487805, "percent_covered_display": "88", "missing_lines": 5, "excluded_lines": 2}, "missing_lines": [140, 141, 172, 173, 176], "excluded_lines": [201, 202]}, "EncryptionManager.decrypt_legacy": {"executed_lines": [211, 212, 213, 214, 215, 218, 219, 220, 221, 222, 223, 225, 228, 234, 237, 238, 239], "summary": {"covered_lines": 15, "num_statements": 17, "percent_covered": 88.23529411764706, "percent_covered_display": "88", "missing_lines": 2, "excluded_lines": 4}, "missing_lines": [240, 241], "excluded_lines": [229, 230, 238, 239]}, "EncryptionManager.resolve_relative_path": {"executed_lines": [266, 267, 268, 269], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager.encrypt_parent_seed": {"executed_lines": [275, 276, 277], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager.decrypt_parent_seed": {"executed_lines": [281, 282, 283, 285, 286, 289, 291, 292, 293, 295], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager._serialize": {"executed_lines": [298, 299, 300], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [301], "excluded_lines": []}, "EncryptionManager._deserialize": {"executed_lines": [311, 312, 313, 316, 317, 318, 319, 320, 321, 322, 325], "summary": {"covered_lines": 9, "num_statements": 10, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 1, "excluded_lines": 2}, "missing_lines": [315], "excluded_lines": [321, 322]}, "EncryptionManager.encrypt_and_save_file": {"executed_lines": [333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager.decrypt_file": {"executed_lines": [348, 349, 350, 351, 352, 353], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager.get_file_kdf": {"executed_lines": [356, 357, 358, 359, 360, 361], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager.save_json_data": {"executed_lines": [370, 371, 372, 373, 376, 377], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [375], "excluded_lines": []}, "EncryptionManager.load_json_data": {"executed_lines": [386, 387, 388, 389, 390, 391, 392, 397, 398, 399, 401, 402, 405, 407, 408, 411, 412, 417, 418, 419, 420, 421, 423, 424, 425, 426, 430, 436], "summary": {"covered_lines": 27, "num_statements": 35, "percent_covered": 77.14285714285714, "percent_covered_display": "77", "missing_lines": 8, "excluded_lines": 4}, "missing_lines": [395, 414, 427, 428, 429, 437, 438, 439], "excluded_lines": [430, 431, 432, 433]}, "EncryptionManager.get_encrypted_index": {"executed_lines": [442, 443, 444, 445, 446, 447, 448], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager.decrypt_and_save_index_from_nostr": {"executed_lines": [470, 471, 473, 474, 475, 477, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 512, 515, 516, 517, 518, 521, 527, 528], "summary": {"covered_lines": 25, "num_statements": 32, "percent_covered": 78.125, "percent_covered_display": "78", "missing_lines": 7, "excluded_lines": 7}, "missing_lines": [529, 530, 531, 535, 541, 542, 543], "excluded_lines": [544, 545, 546, 550, 556, 557, 558]}, "EncryptionManager.decrypt_and_save_index_from_nostr._process": {"executed_lines": [478, 479, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 496, 497], "summary": {"covered_lines": 16, "num_statements": 17, "percent_covered": 94.11764705882354, "percent_covered_display": "94", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [481], "excluded_lines": []}, "EncryptionManager.update_checksum": {"executed_lines": [562, 563, 564, 565, 568, 569, 570, 571, 572, 575, 576, 579, 580, 581, 582, 589, 590, 591, 592, 593, 594, 595], "summary": {"covered_lines": 22, "num_statements": 28, "percent_covered": 78.57142857142857, "percent_covered_display": "79", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [566, 583, 584, 596, 597, 601], "excluded_lines": []}, "EncryptionManager.validate_seed": {"executed_lines": [609, 610, 611, 612, 613, 614], "summary": {"covered_lines": 6, "num_statements": 9, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [615, 616, 617], "excluded_lines": []}, "EncryptionManager.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [620, 621, 622, 623, 625, 626, 627, 628, 630, 631, 632, 633, 634, 635, 636], "excluded_lines": []}, "": {"executed_lines": [3, 4, 6, 7, 9, 10, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 35, 38, 45, 46, 48, 56, 57, 62, 99, 117, 206, 247, 271, 279, 297, 303, 330, 347, 355, 363, 379, 441, 450, 560, 603, 619], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 4}, "missing_lines": [], "excluded_lines": [11, 12, 13, 15]}}, "classes": {"LegacyFormatRequiresMigrationError": {"executed_lines": [49, 52, 53], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EncryptionManager": {"executed_lines": [71, 72, 74, 75, 79, 80, 82, 83, 85, 94, 95, 97, 105, 106, 107, 108, 110, 111, 112, 131, 133, 135, 136, 137, 138, 139, 144, 145, 146, 147, 152, 153, 154, 155, 156, 157, 158, 161, 162, 163, 166, 167, 168, 171, 181, 182, 183, 184, 185, 188, 192, 193, 198, 199, 200, 211, 212, 213, 214, 215, 218, 219, 220, 221, 222, 223, 225, 228, 234, 237, 238, 239, 266, 267, 268, 269, 275, 276, 277, 281, 282, 283, 285, 286, 289, 291, 292, 293, 295, 298, 299, 300, 311, 312, 313, 316, 317, 318, 319, 320, 321, 322, 325, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 348, 349, 350, 351, 352, 353, 356, 357, 358, 359, 360, 361, 370, 371, 372, 373, 376, 377, 386, 387, 388, 389, 390, 391, 392, 397, 398, 399, 401, 402, 405, 407, 408, 411, 412, 417, 418, 419, 420, 421, 423, 424, 425, 426, 430, 436, 442, 443, 444, 445, 446, 447, 448, 470, 471, 473, 474, 475, 477, 478, 479, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 496, 497, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 512, 515, 516, 517, 518, 521, 527, 528, 562, 563, 564, 565, 568, 569, 570, 571, 572, 575, 576, 579, 580, 581, 582, 589, 590, 591, 592, 593, 594, 595, 609, 610, 611, 612, 613, 614], "summary": {"covered_lines": 233, "num_statements": 291, "percent_covered": 80.06872852233677, "percent_covered_display": "80", "missing_lines": 58, "excluded_lines": 19}, "missing_lines": [76, 86, 87, 91, 109, 113, 114, 115, 140, 141, 172, 173, 176, 240, 241, 301, 315, 375, 395, 414, 427, 428, 429, 437, 438, 439, 481, 529, 530, 531, 535, 541, 542, 543, 566, 583, 584, 596, 597, 601, 615, 616, 617, 620, 621, 622, 623, 625, 626, 627, 628, 630, 631, 632, 633, 634, 635, 636], "excluded_lines": [201, 202, 229, 230, 238, 239, 321, 322, 430, 431, 432, 433, 544, 545, 546, 550, 556, 557, 558]}, "": {"executed_lines": [3, 4, 6, 7, 9, 10, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 35, 38, 40, 41, 42, 45, 46, 48, 56, 57, 62, 99, 117, 206, 247, 271, 279, 297, 303, 330, 347, 355, 363, 379, 441, 450, 560, 603, 619], "summary": {"covered_lines": 49, "num_statements": 49, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 4}, "missing_lines": [], "excluded_lines": [11, 12, 13, 15]}}}, "src/seedpass/core/entry_management.py": {"executed_lines": [3, 18, 19, 21, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 48, 49, 50, 53, 56, 57, 64, 65, 66, 69, 70, 72, 74, 76, 78, 80, 81, 82, 84, 85, 86, 88, 89, 90, 91, 93, 94, 96, 101, 103, 104, 107, 108, 109, 110, 111, 116, 119, 120, 121, 123, 124, 125, 126, 127, 132, 138, 139, 140, 141, 142, 145, 146, 152, 183, 184, 185, 187, 188, 202, 203, 204, 205, 207, 209, 211, 213, 215, 216, 217, 219, 220, 222, 224, 228, 229, 230, 232, 233, 235, 242, 244, 245, 246, 254, 256, 271, 272, 273, 275, 276, 278, 279, 280, 281, 283, 297, 298, 299, 300, 301, 315, 317, 318, 319, 321, 322, 327, 343, 344, 346, 348, 349, 350, 352, 353, 354, 364, 365, 366, 367, 369, 372, 373, 374, 375, 378, 380, 381, 383, 396, 397, 399, 400, 401, 403, 404, 406, 407, 408, 410, 411, 412, 424, 425, 426, 427, 429, 432, 433, 434, 435, 438, 439, 440, 442, 443, 445, 446, 447, 448, 450, 461, 462, 464, 465, 466, 468, 469, 470, 471, 472, 473, 474, 475, 477, 478, 479, 489, 490, 491, 492, 494, 507, 509, 510, 511, 524, 525, 526, 527, 529, 532, 533, 534, 535, 540, 541, 542, 544, 545, 547, 548, 549, 550, 551, 552, 554, 566, 567, 569, 570, 571, 573, 574, 575, 576, 577, 579, 580, 581, 592, 593, 594, 595, 597, 600, 601, 602, 603, 608, 609, 610, 612, 613, 615, 616, 617, 619, 634, 635, 637, 638, 639, 641, 642, 644, 646, 647, 648, 649, 651, 652, 654, 655, 656, 669, 670, 671, 672, 674, 677, 678, 679, 680, 686, 687, 688, 690, 691, 693, 694, 695, 697, 703, 704, 705, 706, 710, 715, 717, 724, 725, 726, 727, 731, 732, 734, 735, 736, 738, 740, 741, 742, 743, 748, 749, 751, 755, 756, 757, 758, 759, 760, 762, 763, 764, 765, 766, 768, 769, 772, 773, 782, 784, 790, 791, 799, 806, 807, 808, 810, 811, 812, 817, 818, 821, 822, 837, 876, 877, 878, 880, 892, 894, 916, 990, 991, 994, 995, 999, 1000, 1003, 1004, 1005, 1006, 1007, 1008, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1019, 1020, 1021, 1022, 1026, 1027, 1028, 1029, 1030, 1031, 1033, 1036, 1037, 1038, 1040, 1044, 1045, 1046, 1048, 1052, 1053, 1054, 1056, 1057, 1059, 1061, 1063, 1065, 1067, 1069, 1071, 1073, 1078, 1080, 1081, 1085, 1086, 1087, 1089, 1090, 1094, 1095, 1096, 1099, 1101, 1103, 1105, 1107, 1109, 1130, 1131, 1132, 1134, 1135, 1136, 1137, 1138, 1140, 1141, 1142, 1143, 1144, 1147, 1148, 1150, 1153, 1155, 1156, 1158, 1159, 1160, 1164, 1165, 1168, 1169, 1171, 1172, 1173, 1174, 1175, 1176, 1186, 1196, 1197, 1198, 1199, 1202, 1203, 1204, 1205, 1206, 1209, 1215, 1216, 1222, 1227, 1228, 1235, 1236, 1242, 1244, 1252, 1261, 1262, 1264, 1267, 1268, 1272, 1273, 1277, 1278, 1280, 1281, 1284, 1285, 1286, 1288, 1289, 1290, 1291, 1293, 1294, 1305, 1307, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1344, 1348, 1349, 1350, 1351, 1354, 1356, 1358, 1359, 1365, 1407, 1440, 1447, 1448, 1449, 1451, 1452, 1454, 1455, 1456, 1457, 1459, 1462, 1463, 1464, 1466, 1467, 1469, 1470], "summary": {"covered_lines": 535, "num_statements": 667, "percent_covered": 80.20989505247377, "percent_covered_display": "80", "missing_lines": 132, "excluded_lines": 3}, "missing_lines": [92, 95, 100, 102, 105, 106, 112, 113, 114, 128, 129, 130, 144, 147, 148, 149, 150, 206, 208, 210, 212, 214, 218, 237, 238, 239, 240, 277, 282, 323, 324, 325, 376, 436, 538, 606, 684, 709, 711, 712, 713, 714, 730, 733, 746, 761, 767, 771, 792, 793, 794, 797, 824, 825, 826, 828, 829, 832, 835, 881, 884, 890, 1001, 1002, 1034, 1039, 1049, 1050, 1058, 1060, 1062, 1064, 1066, 1068, 1070, 1072, 1074, 1075, 1076, 1151, 1246, 1247, 1248, 1249, 1250, 1265, 1328, 1331, 1338, 1339, 1340, 1361, 1362, 1363, 1371, 1372, 1373, 1374, 1375, 1380, 1382, 1385, 1387, 1388, 1394, 1395, 1397, 1398, 1401, 1415, 1416, 1421, 1422, 1423, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1435, 1436, 1437, 1438, 1458, 1471, 1472, 1473, 1474], "excluded_lines": [22, 23, 25], "functions": {"EntryManager.__init__": {"executed_lines": [64, 65, 66, 69, 70, 72, 74], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.clear_cache": {"executed_lines": [78], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager._load_index": {"executed_lines": [81, 82, 84, 85, 86, 88, 89, 90, 91, 93, 94, 96, 101, 103, 104, 107, 108, 109, 110, 111, 116, 119, 120, 121], "summary": {"covered_lines": 24, "num_statements": 33, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [92, 95, 100, 102, 105, 106, 112, 113, 114], "excluded_lines": []}, "EntryManager._save_index": {"executed_lines": [124, 125, 126, 127], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [128, 129, 130], "excluded_lines": []}, "EntryManager.get_next_index": {"executed_lines": [138, 139, 140, 141, 142, 145, 146], "summary": {"covered_lines": 7, "num_statements": 12, "percent_covered": 58.333333333333336, "percent_covered_display": "58", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [144, 147, 148, 149, 150], "excluded_lines": []}, "EntryManager.add_entry": {"executed_lines": [183, 184, 185, 187, 188, 202, 203, 204, 205, 207, 209, 211, 213, 215, 216, 217, 219, 220, 222, 224, 228, 229, 230, 232, 233, 235], "summary": {"covered_lines": 26, "num_statements": 36, "percent_covered": 72.22222222222223, "percent_covered_display": "72", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [206, 208, 210, 212, 214, 218, 237, 238, 239, 240], "excluded_lines": []}, "EntryManager.get_next_totp_index": {"executed_lines": [244, 245, 246, 254], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.add_totp": {"executed_lines": [271, 272, 273, 275, 276, 278, 279, 280, 281, 283, 297, 298, 299, 300, 301, 315, 317, 318, 319, 321, 322], "summary": {"covered_lines": 21, "num_statements": 26, "percent_covered": 80.76923076923077, "percent_covered_display": "81", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [277, 282, 323, 324, 325], "excluded_lines": []}, "EntryManager.add_ssh_key": {"executed_lines": [343, 344, 346, 348, 349, 350, 352, 353, 354, 364, 365, 366, 367], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.get_ssh_key_pair": {"executed_lines": [372, 373, 374, 375, 378, 380, 381], "summary": {"covered_lines": 7, "num_statements": 8, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [376], "excluded_lines": []}, "EntryManager.add_pgp_key": {"executed_lines": [396, 397, 399, 400, 401, 403, 404, 406, 407, 408, 410, 411, 412, 424, 425, 426, 427], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.get_pgp_key": {"executed_lines": [432, 433, 434, 435, 438, 439, 440, 442, 443, 445, 446, 447, 448], "summary": {"covered_lines": 13, "num_statements": 14, "percent_covered": 92.85714285714286, "percent_covered_display": "93", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [436], "excluded_lines": []}, "EntryManager.add_nostr_key": {"executed_lines": [461, 462, 464, 465, 466, 468, 469, 470, 471, 472, 473, 474, 475, 477, 478, 479, 489, 490, 491, 492], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.add_key_value": {"executed_lines": [507, 509, 510, 511, 524, 525, 526, 527], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.get_nostr_key_pair": {"executed_lines": [532, 533, 534, 535, 540, 541, 542, 544, 545, 547, 548, 549, 550, 551, 552], "summary": {"covered_lines": 15, "num_statements": 16, "percent_covered": 93.75, "percent_covered_display": "94", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [538], "excluded_lines": []}, "EntryManager.add_seed": {"executed_lines": [566, 567, 569, 570, 571, 573, 574, 575, 576, 577, 579, 580, 581, 592, 593, 594, 595], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.get_seed_phrase": {"executed_lines": [600, 601, 602, 603, 608, 609, 610, 612, 613, 615, 616, 617], "summary": {"covered_lines": 12, "num_statements": 13, "percent_covered": 92.3076923076923, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [606], "excluded_lines": []}, "EntryManager.add_managed_account": {"executed_lines": [634, 635, 637, 638, 639, 641, 642, 644, 646, 647, 648, 649, 651, 652, 654, 655, 656, 669, 670, 671, 672], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.get_managed_account_seed": {"executed_lines": [677, 678, 679, 680, 686, 687, 688, 690, 691, 693, 694, 695], "summary": {"covered_lines": 12, "num_statements": 13, "percent_covered": 92.3076923076923, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [684], "excluded_lines": []}, "EntryManager.get_totp_secret": {"executed_lines": [703, 704, 705, 706, 710, 715], "summary": {"covered_lines": 6, "num_statements": 11, "percent_covered": 54.54545454545455, "percent_covered_display": "55", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [709, 711, 712, 713, 714], "excluded_lines": []}, "EntryManager.get_totp_code": {"executed_lines": [724, 725, 726, 727, 731, 732, 734, 735, 736], "summary": {"covered_lines": 9, "num_statements": 11, "percent_covered": 81.81818181818181, "percent_covered_display": "82", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [730, 733], "excluded_lines": []}, "EntryManager.get_totp_time_remaining": {"executed_lines": [740, 741, 742, 743, 748, 749], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [746], "excluded_lines": []}, "EntryManager.export_totp_entries": {"executed_lines": [755, 756, 757, 758, 759, 760, 762, 763, 764, 765, 766, 768, 769, 772, 773, 782], "summary": {"covered_lines": 16, "num_statements": 19, "percent_covered": 84.21052631578948, "percent_covered_display": "84", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [761, 767, 771], "excluded_lines": []}, "EntryManager.get_encrypted_index": {"executed_lines": [790, 791], "summary": {"covered_lines": 2, "num_statements": 6, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [792, 793, 794, 797], "excluded_lines": []}, "EntryManager.retrieve_entry": {"executed_lines": [806, 807, 808, 810, 811, 812, 817, 818, 821, 822], "summary": {"covered_lines": 10, "num_statements": 17, "percent_covered": 58.8235294117647, "percent_covered_display": "59", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [824, 825, 826, 828, 829, 832, 835], "excluded_lines": []}, "EntryManager.modify_entry": {"executed_lines": [876, 877, 878, 880, 892, 894, 916, 990, 991, 994, 995, 999, 1000, 1003, 1004, 1005, 1006, 1007, 1008, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1019, 1020, 1021, 1022, 1026, 1027, 1028, 1029, 1030, 1031, 1033, 1036, 1037, 1038, 1040, 1044, 1045, 1046, 1048, 1052, 1053, 1054, 1056, 1057, 1059, 1061, 1063, 1065, 1067, 1069, 1071, 1073, 1078, 1080, 1081, 1085, 1086, 1087, 1089, 1090, 1094, 1095, 1096, 1099], "summary": {"covered_lines": 70, "num_statements": 90, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [881, 884, 890, 1001, 1002, 1034, 1039, 1049, 1050, 1058, 1060, 1062, 1064, 1066, 1068, 1070, 1072, 1074, 1075, 1076], "excluded_lines": []}, "EntryManager.archive_entry": {"executed_lines": [1103], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.restore_entry": {"executed_lines": [1107], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryManager.list_entries": {"executed_lines": [1130, 1131, 1132, 1134, 1135, 1136, 1137, 1138, 1140, 1153, 1155, 1156, 1158, 1159, 1160, 1164, 1165, 1168, 1169, 1171, 1172, 1173, 1174, 1175, 1176, 1186, 1196, 1197, 1198, 1199, 1202, 1203, 1204, 1205, 1206, 1209, 1215, 1216, 1222, 1227, 1228, 1235, 1236, 1242, 1244], "summary": {"covered_lines": 45, "num_statements": 50, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [1246, 1247, 1248, 1249, 1250], "excluded_lines": []}, "EntryManager.list_entries.sort_key": {"executed_lines": [1141, 1142, 1143, 1144, 1147, 1148, 1150], "summary": {"covered_lines": 7, "num_statements": 8, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1151], "excluded_lines": []}, "EntryManager.search_entries": {"executed_lines": [1261, 1262, 1264, 1267, 1268, 1272, 1273, 1277, 1278, 1280, 1281, 1284, 1285, 1286, 1288, 1289, 1290, 1291, 1293, 1294, 1305], "summary": {"covered_lines": 21, "num_statements": 22, "percent_covered": 95.45454545454545, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1265], "excluded_lines": []}, "EntryManager.delete_entry": {"executed_lines": [1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322], "summary": {"covered_lines": 10, "num_statements": 15, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [1328, 1331, 1338, 1339, 1340], "excluded_lines": []}, "EntryManager.update_checksum": {"executed_lines": [1348, 1349, 1350, 1351, 1354, 1356, 1358, 1359], "summary": {"covered_lines": 8, "num_statements": 11, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1361, 1362, 1363], "excluded_lines": []}, "EntryManager.restore_from_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [1371, 1372, 1373, 1374, 1375, 1380, 1382, 1385, 1387, 1388, 1394, 1395, 1397, 1398, 1401], "excluded_lines": []}, "EntryManager.list_all_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [1415, 1416, 1421, 1422, 1423, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1435, 1436, 1437, 1438], "excluded_lines": []}, "EntryManager.get_entry_summaries": {"executed_lines": [1447, 1448, 1449, 1451, 1452, 1454, 1455, 1456, 1457, 1459, 1462, 1463, 1464, 1466, 1467, 1469, 1470], "summary": {"covered_lines": 17, "num_statements": 22, "percent_covered": 77.27272727272727, "percent_covered_display": "77", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [1458, 1471, 1472, 1473, 1474], "excluded_lines": []}, "": {"executed_lines": [3, 18, 19, 21, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 48, 49, 50, 53, 56, 57, 76, 80, 123, 132, 152, 242, 256, 327, 369, 383, 429, 450, 494, 529, 554, 597, 619, 674, 697, 717, 738, 751, 784, 799, 837, 1101, 1105, 1109, 1252, 1307, 1344, 1365, 1407, 1440], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [22, 23, 25]}}, "classes": {"EntryManager": {"executed_lines": [64, 65, 66, 69, 70, 72, 74, 78, 81, 82, 84, 85, 86, 88, 89, 90, 91, 93, 94, 96, 101, 103, 104, 107, 108, 109, 110, 111, 116, 119, 120, 121, 124, 125, 126, 127, 138, 139, 140, 141, 142, 145, 146, 183, 184, 185, 187, 188, 202, 203, 204, 205, 207, 209, 211, 213, 215, 216, 217, 219, 220, 222, 224, 228, 229, 230, 232, 233, 235, 244, 245, 246, 254, 271, 272, 273, 275, 276, 278, 279, 280, 281, 283, 297, 298, 299, 300, 301, 315, 317, 318, 319, 321, 322, 343, 344, 346, 348, 349, 350, 352, 353, 354, 364, 365, 366, 367, 372, 373, 374, 375, 378, 380, 381, 396, 397, 399, 400, 401, 403, 404, 406, 407, 408, 410, 411, 412, 424, 425, 426, 427, 432, 433, 434, 435, 438, 439, 440, 442, 443, 445, 446, 447, 448, 461, 462, 464, 465, 466, 468, 469, 470, 471, 472, 473, 474, 475, 477, 478, 479, 489, 490, 491, 492, 507, 509, 510, 511, 524, 525, 526, 527, 532, 533, 534, 535, 540, 541, 542, 544, 545, 547, 548, 549, 550, 551, 552, 566, 567, 569, 570, 571, 573, 574, 575, 576, 577, 579, 580, 581, 592, 593, 594, 595, 600, 601, 602, 603, 608, 609, 610, 612, 613, 615, 616, 617, 634, 635, 637, 638, 639, 641, 642, 644, 646, 647, 648, 649, 651, 652, 654, 655, 656, 669, 670, 671, 672, 677, 678, 679, 680, 686, 687, 688, 690, 691, 693, 694, 695, 703, 704, 705, 706, 710, 715, 724, 725, 726, 727, 731, 732, 734, 735, 736, 740, 741, 742, 743, 748, 749, 755, 756, 757, 758, 759, 760, 762, 763, 764, 765, 766, 768, 769, 772, 773, 782, 790, 791, 806, 807, 808, 810, 811, 812, 817, 818, 821, 822, 876, 877, 878, 880, 892, 894, 916, 990, 991, 994, 995, 999, 1000, 1003, 1004, 1005, 1006, 1007, 1008, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1019, 1020, 1021, 1022, 1026, 1027, 1028, 1029, 1030, 1031, 1033, 1036, 1037, 1038, 1040, 1044, 1045, 1046, 1048, 1052, 1053, 1054, 1056, 1057, 1059, 1061, 1063, 1065, 1067, 1069, 1071, 1073, 1078, 1080, 1081, 1085, 1086, 1087, 1089, 1090, 1094, 1095, 1096, 1099, 1103, 1107, 1130, 1131, 1132, 1134, 1135, 1136, 1137, 1138, 1140, 1141, 1142, 1143, 1144, 1147, 1148, 1150, 1153, 1155, 1156, 1158, 1159, 1160, 1164, 1165, 1168, 1169, 1171, 1172, 1173, 1174, 1175, 1176, 1186, 1196, 1197, 1198, 1199, 1202, 1203, 1204, 1205, 1206, 1209, 1215, 1216, 1222, 1227, 1228, 1235, 1236, 1242, 1244, 1261, 1262, 1264, 1267, 1268, 1272, 1273, 1277, 1278, 1280, 1281, 1284, 1285, 1286, 1288, 1289, 1290, 1291, 1293, 1294, 1305, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1348, 1349, 1350, 1351, 1354, 1356, 1358, 1359, 1447, 1448, 1449, 1451, 1452, 1454, 1455, 1456, 1457, 1459, 1462, 1463, 1464, 1466, 1467, 1469, 1470], "summary": {"covered_lines": 478, "num_statements": 610, "percent_covered": 78.36065573770492, "percent_covered_display": "78", "missing_lines": 132, "excluded_lines": 0}, "missing_lines": [92, 95, 100, 102, 105, 106, 112, 113, 114, 128, 129, 130, 144, 147, 148, 149, 150, 206, 208, 210, 212, 214, 218, 237, 238, 239, 240, 277, 282, 323, 324, 325, 376, 436, 538, 606, 684, 709, 711, 712, 713, 714, 730, 733, 746, 761, 767, 771, 792, 793, 794, 797, 824, 825, 826, 828, 829, 832, 835, 881, 884, 890, 1001, 1002, 1034, 1039, 1049, 1050, 1058, 1060, 1062, 1064, 1066, 1068, 1070, 1072, 1074, 1075, 1076, 1151, 1246, 1247, 1248, 1249, 1250, 1265, 1328, 1331, 1338, 1339, 1340, 1361, 1362, 1363, 1371, 1372, 1373, 1374, 1375, 1380, 1382, 1385, 1387, 1388, 1394, 1395, 1397, 1398, 1401, 1415, 1416, 1421, 1422, 1423, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1435, 1436, 1437, 1438, 1458, 1471, 1472, 1473, 1474], "excluded_lines": []}, "": {"executed_lines": [3, 18, 19, 21, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 48, 49, 50, 53, 56, 57, 76, 80, 123, 132, 152, 242, 256, 327, 369, 383, 429, 450, 494, 529, 554, 597, 619, 674, 697, 717, 738, 751, 784, 799, 837, 1101, 1105, 1109, 1252, 1307, 1344, 1365, 1407, 1440], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [22, 23, 25]}}}, "src/seedpass/core/entry_service.py": {"executed_lines": [1, 3, 4, 5, 7, 9, 14, 15, 17, 21, 22, 24, 25, 27, 28, 29, 30, 31, 39, 40, 41, 44, 45, 46, 47, 52, 53, 54, 55, 61, 62, 64, 65, 66, 68, 69, 71, 77, 78, 81, 88, 90, 91, 92, 100, 102, 103, 104, 105, 106, 107, 108, 114, 115, 119, 120, 122, 123, 124, 127, 128, 131, 139, 140, 142, 143, 144, 150, 151, 152, 153, 154, 162, 164, 167, 168, 171, 174, 175, 177, 178, 179, 181, 184, 185, 188, 191, 194, 196, 199, 202, 204, 205, 208, 210, 213, 216, 218, 237], "summary": {"covered_lines": 97, "num_statements": 114, "percent_covered": 85.08771929824562, "percent_covered_display": "85", "missing_lines": 17, "excluded_lines": 8}, "missing_lines": [116, 117, 129, 155, 156, 157, 158, 169, 186, 192, 193, 200, 201, 206, 207, 214, 215], "excluded_lines": [17, 18, 95, 96, 239, 240, 241, 242], "functions": {"EntryService.__init__": {"executed_lines": [25], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.handle_add_password": {"executed_lines": [28, 29, 30, 31, 39, 64, 102, 103, 104, 105, 106, 107, 108, 114, 115, 119, 120, 122, 123, 124, 127, 128, 131, 139, 140, 142, 143, 144, 150, 151, 152, 153, 154, 162, 164, 167, 168, 171, 174, 175, 177, 178, 179, 181, 184, 185, 188, 191, 194, 196, 199, 202, 204, 205, 208, 210, 213, 216, 218, 237], "summary": {"covered_lines": 60, "num_statements": 77, "percent_covered": 77.92207792207792, "percent_covered_display": "78", "missing_lines": 17, "excluded_lines": 4}, "missing_lines": [116, 117, 129, 155, 156, 157, 158, 169, 186, 192, 193, 200, 201, 206, 207, 214, 215], "excluded_lines": [239, 240, 241, 242]}, "EntryService.handle_add_password.prompt_length": {"executed_lines": [40, 41, 44, 45, 46, 47, 52, 53, 54, 55, 61, 62], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryService.handle_add_password.finalize_entry": {"executed_lines": [65, 66, 68, 69, 71, 77, 78, 81, 88, 90, 91, 92, 100], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [95, 96]}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 14, 15, 17, 21, 22, 24, 27], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [17, 18]}}, "classes": {"EntryService": {"executed_lines": [25, 28, 29, 30, 31, 39, 40, 41, 44, 45, 46, 47, 52, 53, 54, 55, 61, 62, 64, 65, 66, 68, 69, 71, 77, 78, 81, 88, 90, 91, 92, 100, 102, 103, 104, 105, 106, 107, 108, 114, 115, 119, 120, 122, 123, 124, 127, 128, 131, 139, 140, 142, 143, 144, 150, 151, 152, 153, 154, 162, 164, 167, 168, 171, 174, 175, 177, 178, 179, 181, 184, 185, 188, 191, 194, 196, 199, 202, 204, 205, 208, 210, 213, 216, 218, 237], "summary": {"covered_lines": 86, "num_statements": 103, "percent_covered": 83.49514563106796, "percent_covered_display": "83", "missing_lines": 17, "excluded_lines": 6}, "missing_lines": [116, 117, 129, 155, 156, 157, 158, 169, 186, 192, 193, 200, 201, 206, 207, 214, 215], "excluded_lines": [95, 96, 239, 240, 241, 242]}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 14, 15, 17, 21, 22, 24, 27], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [17, 18]}}}, "src/seedpass/core/entry_types.py": {"executed_lines": [2, 4, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 21], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [2, 4, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 21], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"EntryType": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [2, 4, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 21], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/errors.py": {"executed_lines": [1, 11, 12, 15, 16, 18, 19, 22, 23, 30], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"SeedPassError.__init__": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 15, 16, 18, 22, 23, 30], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"SeedPassError": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DecryptionError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 15, 16, 18, 22, 23, 30], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/manager.py": {"executed_lines": [3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 52, 53, 60, 66, 67, 68, 69, 75, 76, 77, 78, 79, 81, 94, 95, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 112, 113, 114, 115, 118, 121, 122, 124, 125, 126, 127, 128, 129, 141, 142, 143, 148, 149, 152, 153, 154, 155, 158, 160, 161, 164, 189, 190, 191, 193, 194, 197, 200, 201, 202, 204, 206, 209, 210, 212, 215, 216, 218, 220, 221, 222, 223, 224, 227, 228, 237, 238, 239, 240, 241, 242, 244, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 277, 278, 279, 280, 281, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 304, 305, 306, 309, 310, 311, 314, 316, 318, 321, 323, 327, 328, 339, 340, 345, 348, 349, 350, 351, 352, 353, 355, 357, 363, 364, 365, 366, 367, 369, 371, 372, 373, 374, 375, 376, 377, 378, 386, 387, 391, 392, 394, 396, 398, 399, 400, 405, 407, 408, 422, 423, 425, 426, 427, 428, 432, 434, 435, 436, 437, 438, 439, 441, 443, 444, 445, 446, 447, 448, 450, 452, 453, 454, 458, 462, 463, 465, 467, 469, 470, 471, 472, 473, 474, 475, 477, 478, 479, 480, 481, 483, 484, 485, 486, 487, 489, 490, 491, 492, 493, 494, 495, 497, 499, 500, 501, 502, 503, 505, 518, 519, 521, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 536, 541, 542, 543, 546, 547, 548, 549, 551, 555, 556, 557, 565, 569, 570, 572, 575, 577, 581, 582, 583, 586, 587, 588, 590, 591, 592, 597, 598, 600, 602, 603, 607, 608, 613, 614, 621, 626, 627, 634, 635, 636, 637, 638, 639, 644, 648, 649, 657, 658, 660, 662, 663, 664, 665, 667, 670, 671, 672, 675, 686, 688, 689, 690, 700, 709, 710, 711, 712, 713, 714, 716, 721, 726, 727, 729, 730, 731, 733, 734, 735, 736, 737, 738, 739, 741, 744, 745, 746, 747, 752, 753, 754, 755, 757, 764, 765, 766, 767, 768, 770, 775, 776, 781, 794, 799, 802, 805, 806, 811, 816, 817, 822, 825, 826, 830, 831, 832, 833, 839, 840, 841, 842, 844, 845, 847, 850, 851, 852, 853, 855, 859, 860, 861, 863, 864, 865, 866, 867, 869, 870, 871, 872, 873, 875, 876, 878, 880, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 894, 895, 896, 897, 898, 900, 901, 987, 988, 993, 995, 1005, 1006, 1007, 1009, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1029, 1032, 1052, 1053, 1054, 1055, 1056, 1058, 1060, 1064, 1065, 1066, 1071, 1077, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1093, 1094, 1095, 1106, 1109, 1115, 1116, 1117, 1118, 1119, 1120, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1133, 1137, 1138, 1139, 1141, 1146, 1147, 1149, 1150, 1152, 1153, 1157, 1158, 1159, 1160, 1169, 1170, 1177, 1178, 1179, 1180, 1182, 1184, 1185, 1186, 1187, 1192, 1193, 1205, 1214, 1217, 1224, 1225, 1226, 1227, 1228, 1233, 1234, 1235, 1238, 1239, 1240, 1241, 1243, 1244, 1246, 1251, 1261, 1262, 1263, 1264, 1265, 1266, 1271, 1278, 1279, 1280, 1281, 1282, 1292, 1293, 1303, 1304, 1305, 1309, 1313, 1318, 1320, 1321, 1323, 1324, 1325, 1326, 1331, 1335, 1336, 1338, 1342, 1347, 1348, 1350, 1351, 1353, 1354, 1358, 1359, 1365, 1369, 1370, 1371, 1372, 1373, 1374, 1376, 1386, 1387, 1389, 1395, 1400, 1402, 1406, 1409, 1413, 1414, 1419, 1420, 1421, 1427, 1428, 1431, 1432, 1433, 1435, 1440, 1441, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1465, 1466, 1469, 1470, 1471, 1472, 1473, 1474, 1485, 1488, 1490, 1491, 1492, 1499, 1500, 1501, 1502, 1503, 1504, 1507, 1508, 1509, 1530, 1532, 1533, 1534, 1535, 1537, 1539, 1541, 1542, 1543, 1544, 1545, 1546, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1594, 1595, 1596, 1597, 1629, 1630, 1631, 1647, 1651, 1652, 1654, 1656, 1657, 1658, 1659, 1660, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1674, 1675, 1676, 1677, 1680, 1681, 1683, 1685, 1687, 1688, 1690, 1693, 1695, 1702, 1703, 1704, 1707, 1708, 1709, 1714, 1715, 1716, 1717, 1719, 1720, 1722, 1724, 1725, 1750, 1757, 1760, 1761, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1797, 1798, 1799, 1800, 1802, 1803, 1804, 1805, 1807, 1811, 1813, 1814, 1816, 1824, 1835, 1837, 1840, 1841, 1842, 1843, 1848, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1859, 1861, 1863, 1864, 1866, 1867, 1868, 1869, 1871, 1872, 1875, 1876, 1877, 1878, 1879, 1880, 1887, 1888, 1890, 1891, 1892, 1894, 1895, 1897, 1898, 1899, 1900, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1916, 1917, 1918, 1923, 1924, 1927, 1932, 1933, 1934, 1939, 1949, 1953, 1954, 1955, 1956, 1957, 1962, 1963, 1964, 1965, 1966, 1967, 1973, 1974, 2036, 2037, 2094, 2095, 2164, 2165, 2232, 2233, 2292, 2293, 2374, 2375, 2437, 2439, 2440, 2441, 2444, 2445, 2453, 2455, 2457, 2458, 2459, 2460, 2461, 2462, 2464, 2481, 2483, 2484, 2485, 2486, 2488, 2492, 2493, 2494, 2496, 2497, 2498, 2500, 2501, 2505, 2506, 2507, 2509, 2511, 2513, 2514, 2515, 2522, 2523, 2524, 2525, 2526, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2539, 2541, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2562, 2576, 2577, 2578, 2584, 2587, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2602, 2604, 2606, 2607, 2608, 2609, 2616, 2617, 2618, 2623, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2638, 2644, 2652, 2657, 2662, 2663, 2664, 2665, 2666, 2667, 2680, 2682, 2685, 2687, 2688, 2703, 2704, 2705, 2706, 2713, 2714, 2715, 2716, 2721, 2722, 2724, 2728, 2729, 2730, 2731, 2732, 2733, 2736, 2737, 2738, 2745, 2756, 2758, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2780, 2781, 2782, 2783, 2784, 2785, 2787, 2788, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2803, 2804, 2812, 2813, 2814, 2815, 2819, 2821, 2822, 2823, 2824, 2827, 2828, 2829, 2830, 2833, 2834, 2835, 2836, 2838, 2839, 2841, 2842, 2843, 2852, 2853, 2857, 2859, 2860, 2861, 2862, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2875, 2876, 2878, 2887, 2888, 2889, 2890, 2892, 2893, 2894, 2895, 2896, 2902, 2906, 2908, 2909, 2910, 2911, 2914, 2915, 2916, 2917, 2920, 2921, 2922, 2923, 2925, 2926, 2928, 2929, 2938, 2942, 2944, 2945, 2946, 2947, 2948, 2951, 2952, 2953, 2954, 2963, 2964, 2966, 2967, 2972, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2982, 2983, 2985, 2990, 2999, 3001, 3002, 3029, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3039, 3040, 3041, 3042, 3044, 3049, 3056, 3057, 3060, 3069, 3070, 3071, 3075, 3078, 3079, 3080, 3081, 3082, 3083, 3085, 3091, 3093, 3095, 3096, 3101, 3103, 3104, 3105, 3106, 3113, 3119, 3120, 3121, 3122, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3144, 3145, 3146, 3147, 3148, 3149, 3160, 3163, 3165, 3166, 3168, 3169, 3170, 3177, 3180, 3184, 3186, 3187, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198, 3200, 3201, 3206, 3207, 3208, 3215, 3218, 3221, 3224, 3225, 3228, 3230, 3339, 3403, 3512, 3513, 3514, 3515, 3516, 3518, 3524, 3525, 3526, 3527, 3534, 3541, 3547, 3553, 3560, 3561, 3573, 3580, 3581, 3582, 3594, 3597, 3603, 3615, 3616, 3618, 3621, 3622, 3623, 3632, 3638, 3639, 3641, 3642, 3643, 3650, 3651, 3652, 3653, 3654, 3656, 3657, 3662, 3663, 3664, 3671, 3672, 3673, 3674, 3676, 3677, 3679, 3682, 3684, 3690, 3691, 3692, 3693, 3694, 3696, 3698, 3699, 3702, 3703, 3704, 3705, 3706, 3709, 3715, 3716, 3718, 3719, 3721, 3722, 3723, 3724, 3725, 3726, 3732, 3733, 3735, 3736, 3738, 3739, 3740, 3741, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3753, 3754, 3756, 3757, 3758, 3759, 3762, 3763, 3764, 3765, 3768, 3769, 3770, 3771, 3776, 3777, 3779, 3780, 3782, 3783, 3784, 3785, 3788, 3789, 3791, 3792, 3794, 3795, 3796, 3797, 3798, 3799, 3800, 3802, 3803, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3815, 3816, 3817, 3818, 3819, 3821, 3822, 3824, 3825, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3840, 3846, 3848, 3849, 3850, 3852, 3854, 3855, 3858, 3861, 3863, 3869, 3872, 3873, 3876, 3877, 3878, 3889, 3890, 3892, 3893, 3896, 3899, 3900, 3901, 3902, 3903, 3908, 3909, 3911, 3913, 3916, 3919, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3940, 3941, 3942, 3943, 3946, 3947, 3948, 3953, 3954, 3955, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3978, 3979, 3986, 3987, 3988, 3990, 3991, 3995, 3996, 3997, 4004, 4005, 4006, 4007, 4008, 4012, 4013, 4015, 4016, 4017, 4019, 4025, 4030, 4031, 4059, 4065, 4066, 4067, 4068, 4069, 4079, 4100, 4104, 4105, 4106, 4107, 4108, 4110, 4111, 4112, 4113, 4114, 4115, 4117, 4121, 4122, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4135, 4136, 4141, 4142, 4143, 4145, 4148, 4150, 4154, 4155, 4156, 4161, 4165, 4166, 4167, 4176, 4177, 4189, 4190, 4191, 4198, 4199, 4202, 4209, 4210, 4211, 4212, 4213, 4219, 4220, 4223, 4224, 4230, 4233, 4234, 4235, 4240, 4241, 4243, 4244, 4252, 4253, 4259, 4268, 4269, 4270, 4271, 4302, 4303, 4305, 4306, 4307, 4308, 4315, 4316, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4330, 4331, 4341, 4345, 4348, 4350, 4352, 4363, 4365, 4366, 4367, 4373, 4374, 4386, 4387, 4388, 4395, 4396, 4400, 4406, 4410, 4415, 4418, 4419, 4422, 4423, 4424, 4431, 4432, 4436, 4439, 4440, 4443, 4444, 4446, 4447, 4451, 4454, 4460, 4461, 4462, 4465, 4470, 4480, 4481, 4482, 4483, 4495, 4496, 4497, 4500, 4515, 4526, 4527, 4528, 4529, 4530, 4532, 4537, 4538, 4539, 4540, 4550, 4573, 4575, 4576, 4577, 4581, 4582, 4585, 4587, 4588, 4591, 4593, 4595, 4596, 4597, 4598, 4599, 4602, 4603, 4604, 4606, 4610, 4611, 4621, 4637, 4638, 4639, 4648, 4720], "summary": {"covered_lines": 1665, "num_statements": 2703, "percent_covered": 61.59822419533851, "percent_covered_display": "62", "missing_lines": 1038, "excluded_lines": 32}, "missing_lines": [130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 174, 175, 176, 177, 180, 182, 183, 185, 186, 203, 333, 334, 335, 343, 389, 395, 401, 402, 403, 410, 411, 412, 413, 414, 417, 418, 419, 420, 429, 430, 455, 456, 468, 520, 522, 558, 559, 560, 563, 604, 605, 610, 616, 617, 618, 619, 641, 642, 645, 676, 682, 697, 698, 758, 759, 760, 761, 762, 777, 778, 779, 780, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 800, 803, 818, 819, 820, 827, 828, 829, 834, 835, 836, 837, 848, 879, 906, 907, 908, 911, 912, 915, 916, 917, 923, 927, 928, 929, 934, 936, 937, 938, 939, 941, 942, 943, 946, 947, 948, 951, 956, 960, 961, 962, 963, 964, 965, 966, 967, 970, 975, 976, 977, 978, 980, 981, 982, 983, 984, 985, 1008, 1010, 1025, 1026, 1030, 1061, 1062, 1063, 1067, 1068, 1069, 1075, 1096, 1102, 1110, 1113, 1161, 1162, 1163, 1165, 1166, 1167, 1188, 1189, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1203, 1204, 1206, 1212, 1218, 1221, 1229, 1230, 1248, 1249, 1267, 1268, 1269, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1314, 1315, 1360, 1361, 1362, 1363, 1379, 1380, 1381, 1384, 1390, 1391, 1392, 1393, 1403, 1459, 1460, 1461, 1462, 1463, 1464, 1516, 1523, 1540, 1547, 1548, 1553, 1557, 1604, 1610, 1611, 1616, 1623, 1632, 1633, 1638, 1639, 1642, 1648, 1649, 1663, 1689, 1691, 1700, 1727, 1728, 1729, 1730, 1731, 1732, 1733, 1734, 1735, 1737, 1738, 1739, 1740, 1743, 1744, 1745, 1746, 1748, 1758, 1762, 1801, 1808, 1809, 1822, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1838, 1844, 1845, 1846, 1873, 1882, 1885, 1914, 1915, 1919, 1922, 1950, 1951, 1968, 1969, 1975, 1976, 1977, 1978, 1979, 1983, 1984, 1985, 1986, 1987, 1988, 1991, 1996, 1997, 2007, 2008, 2009, 2015, 2016, 2017, 2018, 2019, 2023, 2024, 2025, 2026, 2027, 2028, 2030, 2031, 2032, 2033, 2034, 2039, 2040, 2041, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2059, 2062, 2065, 2066, 2068, 2071, 2072, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2088, 2089, 2090, 2091, 2092, 2097, 2098, 2099, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2118, 2119, 2120, 2121, 2122, 2125, 2126, 2127, 2129, 2132, 2133, 2135, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2150, 2151, 2152, 2153, 2154, 2158, 2159, 2160, 2161, 2162, 2167, 2168, 2169, 2176, 2177, 2178, 2179, 2180, 2184, 2185, 2186, 2187, 2192, 2200, 2203, 2204, 2206, 2209, 2210, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2226, 2227, 2228, 2229, 2230, 2235, 2236, 2237, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2255, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2272, 2273, 2274, 2275, 2278, 2279, 2280, 2286, 2287, 2288, 2289, 2290, 2295, 2296, 2297, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, 2337, 2345, 2346, 2348, 2349, 2350, 2351, 2352, 2353, 2360, 2361, 2362, 2368, 2369, 2370, 2371, 2372, 2377, 2378, 2379, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2397, 2400, 2401, 2402, 2403, 2409, 2410, 2411, 2412, 2419, 2420, 2421, 2423, 2424, 2425, 2431, 2432, 2433, 2434, 2435, 2442, 2466, 2467, 2472, 2473, 2474, 2475, 2477, 2478, 2479, 2557, 2558, 2559, 2560, 2561, 2563, 2564, 2565, 2567, 2568, 2569, 2570, 2573, 2574, 2575, 2601, 2619, 2620, 2624, 2625, 2633, 2634, 2635, 2636, 2637, 2639, 2640, 2641, 2642, 2643, 2645, 2646, 2647, 2648, 2649, 2653, 2654, 2655, 2656, 2658, 2659, 2660, 2661, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2677, 2679, 2689, 2690, 2692, 2696, 2697, 2699, 2700, 2701, 2735, 2740, 2772, 2773, 2786, 2789, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 2837, 2840, 2844, 2845, 2874, 2877, 2879, 2880, 2924, 2927, 2930, 2931, 2955, 2956, 2965, 2968, 2981, 2984, 2991, 2992, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3021, 3028, 3038, 3043, 3061, 3062, 3072, 3073, 3074, 3092, 3094, 3150, 3153, 3162, 3181, 3182, 3183, 3188, 3189, 3219, 3220, 3226, 3231, 3232, 3233, 3234, 3235, 3237, 3243, 3244, 3245, 3251, 3255, 3258, 3259, 3260, 3261, 3263, 3267, 3270, 3271, 3272, 3273, 3275, 3279, 3286, 3287, 3288, 3289, 3290, 3291, 3293, 3297, 3299, 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3320, 3323, 3329, 3340, 3341, 3342, 3344, 3350, 3356, 3360, 3367, 3368, 3369, 3370, 3371, 3372, 3374, 3378, 3380, 3387, 3390, 3396, 3407, 3408, 3409, 3410, 3412, 3418, 3424, 3430, 3434, 3435, 3439, 3440, 3444, 3451, 3452, 3453, 3454, 3455, 3456, 3458, 3462, 3464, 3471, 3472, 3473, 3474, 3475, 3476, 3479, 3480, 3481, 3482, 3483, 3487, 3490, 3496, 3504, 3505, 3507, 3562, 3563, 3564, 3565, 3567, 3571, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3626, 3627, 3634, 3635, 3636, 3658, 3659, 3660, 3675, 3683, 3687, 3688, 3689, 3700, 3717, 3720, 3734, 3737, 3752, 3755, 3778, 3781, 3790, 3793, 3801, 3804, 3820, 3823, 3839, 3859, 3860, 3866, 3867, 3879, 3880, 3885, 3886, 3887, 3897, 3898, 3904, 3905, 3906, 3951, 3952, 3977, 3981, 3982, 3983, 3984, 4026, 4027, 4028, 4033, 4034, 4035, 4036, 4037, 4038, 4045, 4046, 4047, 4054, 4055, 4056, 4057, 4071, 4072, 4073, 4074, 4075, 4076, 4077, 4085, 4086, 4087, 4088, 4089, 4092, 4098, 4109, 4120, 4123, 4157, 4158, 4159, 4172, 4173, 4174, 4214, 4215, 4216, 4217, 4236, 4237, 4238, 4239, 4260, 4261, 4267, 4272, 4273, 4274, 4280, 4282, 4283, 4284, 4285, 4286, 4289, 4290, 4291, 4292, 4293, 4296, 4297, 4299, 4300, 4327, 4328, 4329, 4342, 4343, 4353, 4354, 4355, 4358, 4359, 4360, 4361, 4368, 4369, 4370, 4371, 4407, 4411, 4412, 4433, 4434, 4448, 4449, 4466, 4467, 4468, 4485, 4486, 4487, 4488, 4489, 4491, 4492, 4493, 4499, 4501, 4502, 4503, 4509, 4510, 4511, 4512, 4513, 4543, 4544, 4549, 4551, 4553, 4554, 4555, 4556, 4558, 4559, 4564, 4565, 4568, 4569, 4570, 4571, 4578, 4607, 4608, 4624, 4626, 4627, 4628, 4640, 4641, 4644, 4645, 4646, 4650, 4651, 4653, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4674, 4675, 4676, 4679, 4680, 4681, 4682, 4683, 4685, 4686, 4687, 4689, 4692, 4693, 4694, 4695, 4698, 4701, 4702, 4703, 4708, 4709, 4710, 4711, 4712, 4714, 4715, 4716, 4718, 4722, 4723, 4724, 4725, 4727, 4728, 4729, 4730, 4731, 4732, 4738, 4739, 4744, 4745, 4751, 4757, 4758, 4759, 4760], "excluded_lines": [1804, 1805, 1832, 1833, 2221, 2222, 2281, 2282, 2363, 2364, 2426, 2427, 2741, 2742, 2743, 2816, 2817, 2818, 2854, 2855, 2856, 2903, 2904, 2905, 2939, 2940, 2941, 2969, 2970, 2971, 3772, 3773], "functions": {"AuditLogger.__init__": {"executed_lines": [125, 126, 127, 128, 129], "summary": {"covered_lines": 5, "num_statements": 15, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [130, 131, 132, 133, 134, 135, 136, 137, 138, 139], "excluded_lines": []}, "AuditLogger.log": {"executed_lines": [142, 143, 148, 149, 152, 153, 154, 155], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "calculate_profile_id": {"executed_lines": [160, 161], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "restore_backup_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [174, 175, 176, 177, 180, 182, 183, 185, 186], "excluded_lines": []}, "requires_unlocked": {"executed_lines": [200, 201, 206], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "requires_unlocked.wrapper": {"executed_lines": [202, 204], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [203], "excluded_lines": []}, "AuthGuard.__init__": {"executed_lines": [215, 216], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AuthGuard.check_timeout": {"executed_lines": [220, 221, 222, 223, 224], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.__init__": {"executed_lines": [254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 277, 278, 279, 280, 281, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 304, 305, 306, 309, 310, 311, 314, 316, 318, 321, 323], "summary": {"covered_lines": 55, "num_statements": 55, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.get_bip85_entropy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [333, 334, 335], "excluded_lines": []}, "PasswordManager.clear_bip85_cache": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [343], "excluded_lines": []}, "PasswordManager.derive_key_hierarchy": {"executed_lines": [348, 349, 350, 351, 352, 353], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.ensure_key_hierarchy": {"executed_lines": [357, 363, 364, 365, 366, 367], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.ensure_script_checksum": {"executed_lines": [371, 372, 373, 374, 375, 376, 377, 378], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.get_password_prompt": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [389], "excluded_lines": []}, "PasswordManager.parent_seed": {"executed_lines": [400, 405], "summary": {"covered_lines": 2, "num_statements": 5, "percent_covered": 40.0, "percent_covered_display": "40", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [401, 402, 403], "excluded_lines": []}, "PasswordManager.header_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [410, 411, 412, 413, 414, 417, 418, 419, 420], "excluded_lines": []}, "PasswordManager.header_fingerprint_args": {"executed_lines": [425, 426, 427, 428], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [429, 430], "excluded_lines": []}, "PasswordManager.update_activity": {"executed_lines": [434, 435, 436, 437, 438, 439], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.notify": {"executed_lines": [443, 444, 445, 446, 447, 448], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.get_current_notification": {"executed_lines": [452, 453, 454, 458, 462, 463], "summary": {"covered_lines": 6, "num_statements": 8, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [455, 456], "excluded_lines": []}, "PasswordManager.poll_background_errors": {"executed_lines": [467, 469, 470, 471, 472, 473, 474, 475], "summary": {"covered_lines": 8, "num_statements": 9, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [468], "excluded_lines": []}, "PasswordManager.menu_handler": {"executed_lines": [479, 480, 481], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.profile_service": {"executed_lines": [485, 486, 487], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.entry_service": {"executed_lines": [491, 492, 493, 494, 495], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.lock_vault": {"executed_lines": [499, 500, 501, 502, 503], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.unlock_vault": {"executed_lines": [518, 519, 521, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 536, 541, 542, 543, 546, 547, 548, 549], "summary": {"covered_lines": 21, "num_statements": 23, "percent_covered": 91.30434782608695, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [520, 522], "excluded_lines": []}, "PasswordManager.initialize_fingerprint_manager": {"executed_lines": [555, 556, 557], "summary": {"covered_lines": 3, "num_statements": 7, "percent_covered": 42.857142857142854, "percent_covered_display": "43", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [558, 559, 560, 563], "excluded_lines": []}, "PasswordManager.setup_parent_seed": {"executed_lines": [569, 570, 572, 575], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.select_or_add_fingerprint": {"executed_lines": [581, 582, 583, 586, 587, 588, 590, 591, 592, 597, 598, 600, 602, 603, 607, 608, 613, 614], "summary": {"covered_lines": 18, "num_statements": 25, "percent_covered": 72.0, "percent_covered_display": "72", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [604, 605, 610, 616, 617, 618, 619], "excluded_lines": []}, "PasswordManager.add_new_fingerprint": {"executed_lines": [626, 627, 634, 635, 636, 637, 638, 639, 644, 648, 649, 657, 658, 660, 662, 663, 664, 665], "summary": {"covered_lines": 18, "num_statements": 21, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [641, 642, 645], "excluded_lines": []}, "PasswordManager.select_fingerprint": {"executed_lines": [670, 671, 672, 675, 686, 688, 689, 690], "summary": {"covered_lines": 8, "num_statements": 12, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [676, 682, 697, 698], "excluded_lines": []}, "PasswordManager.setup_encryption_manager": {"executed_lines": [709, 710, 711, 712, 713, 714, 716, 721, 726, 727, 729, 730, 731, 733, 734, 735, 736, 737, 738, 739, 741, 744, 745, 746, 747, 752, 753, 754, 755, 757, 764, 765, 766, 767, 768, 770, 775, 776, 781], "summary": {"covered_lines": 39, "num_statements": 59, "percent_covered": 66.10169491525424, "percent_covered_display": "66", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [758, 759, 760, 761, 762, 777, 778, 779, 780, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792], "excluded_lines": []}, "PasswordManager.load_parent_seed": {"executed_lines": [799, 802, 805, 806, 811, 816, 817, 822, 825, 826, 830, 831, 832, 833], "summary": {"covered_lines": 14, "num_statements": 26, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [800, 803, 818, 819, 820, 827, 828, 829, 834, 835, 836, 837], "excluded_lines": []}, "PasswordManager.handle_switch_fingerprint": {"executed_lines": [842], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.load_managed_account": {"executed_lines": [847, 850, 851, 852, 853, 855, 859, 860, 861, 863, 864, 865, 866, 867, 869, 870, 871, 872, 873], "summary": {"covered_lines": 19, "num_statements": 20, "percent_covered": 95.0, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [848], "excluded_lines": []}, "PasswordManager.exit_managed_account": {"executed_lines": [878, 880, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 894, 895, 896, 897, 898], "summary": {"covered_lines": 18, "num_statements": 19, "percent_covered": 94.73684210526316, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [879], "excluded_lines": []}, "PasswordManager.handle_existing_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 44, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 44, "excluded_lines": 0}, "missing_lines": [906, 907, 908, 911, 912, 915, 916, 917, 923, 927, 928, 929, 934, 936, 937, 938, 939, 941, 942, 943, 946, 947, 948, 951, 956, 960, 961, 962, 963, 964, 965, 966, 967, 970, 975, 976, 977, 978, 980, 981, 982, 983, 984, 985], "excluded_lines": []}, "PasswordManager.handle_new_seed_setup": {"executed_lines": [993, 995, 1005, 1006, 1007, 1009, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1029], "summary": {"covered_lines": 20, "num_statements": 25, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [1008, 1010, 1025, 1026, 1030], "excluded_lines": []}, "PasswordManager.setup_existing_seed": {"executed_lines": [1052, 1053, 1054, 1055, 1056, 1058, 1060, 1064, 1065, 1066], "summary": {"covered_lines": 10, "num_statements": 16, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [1061, 1062, 1063, 1067, 1068, 1069], "excluded_lines": []}, "PasswordManager.setup_existing_seed_word_by_word": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1075], "excluded_lines": []}, "PasswordManager._finalize_existing_seed": {"executed_lines": [1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1093, 1094, 1095, 1106, 1109, 1115, 1116, 1117, 1118, 1119, 1120, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1133, 1137, 1138, 1139, 1141, 1146, 1147, 1149, 1150, 1152, 1153, 1157, 1158, 1159, 1160], "summary": {"covered_lines": 43, "num_statements": 53, "percent_covered": 81.13207547169812, "percent_covered_display": "81", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [1096, 1102, 1110, 1113, 1161, 1162, 1163, 1165, 1166, 1167], "excluded_lines": []}, "PasswordManager.generate_new_seed": {"executed_lines": [1177, 1178, 1179, 1180, 1182, 1184, 1185, 1186, 1187, 1192, 1193, 1205, 1214, 1217, 1224, 1225, 1226, 1227, 1228, 1233, 1234, 1235, 1238, 1239, 1240, 1241, 1243, 1244, 1246], "summary": {"covered_lines": 29, "num_statements": 48, "percent_covered": 60.416666666666664, "percent_covered_display": "60", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [1188, 1189, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1203, 1204, 1206, 1212, 1218, 1221, 1229, 1230, 1248, 1249], "excluded_lines": []}, "PasswordManager.validate_bip85_seed": {"executed_lines": [1261, 1262, 1263, 1264, 1265, 1266], "summary": {"covered_lines": 6, "num_statements": 9, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1267, 1268, 1269], "excluded_lines": []}, "PasswordManager.generate_bip85_seed": {"executed_lines": [1278, 1279, 1280, 1281, 1282], "summary": {"covered_lines": 5, "num_statements": 13, "percent_covered": 38.46153846153846, "percent_covered_display": "38", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290], "excluded_lines": []}, "PasswordManager.save_and_encrypt_seed": {"executed_lines": [1303, 1304, 1305, 1309, 1313, 1318, 1320, 1321, 1323, 1324, 1325, 1326, 1331, 1335, 1336, 1338, 1342, 1347, 1348, 1350, 1351, 1353, 1354, 1358, 1359], "summary": {"covered_lines": 25, "num_statements": 31, "percent_covered": 80.64516129032258, "percent_covered_display": "81", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [1314, 1315, 1360, 1361, 1362, 1363], "excluded_lines": []}, "PasswordManager.initialize_bip85": {"executed_lines": [1369, 1370, 1371, 1372, 1373, 1374, 1376, 1386, 1387, 1389], "summary": {"covered_lines": 10, "num_statements": 14, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [1390, 1391, 1392, 1393], "excluded_lines": []}, "PasswordManager.initialize_bip85.cached_derive": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [1379, 1380, 1381, 1384], "excluded_lines": []}, "PasswordManager.initialize_managers": {"executed_lines": [1400, 1402, 1406, 1409, 1413, 1414, 1419, 1420, 1421, 1427, 1428, 1431, 1432, 1433, 1435, 1440, 1441, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1465, 1466, 1469, 1470, 1471, 1472, 1473, 1474, 1485, 1488, 1490, 1491, 1492, 1499, 1500, 1501, 1502, 1503, 1504, 1507, 1508, 1509, 1530, 1532, 1533, 1534, 1535], "summary": {"covered_lines": 53, "num_statements": 62, "percent_covered": 85.48387096774194, "percent_covered_display": "85", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [1403, 1459, 1460, 1461, 1462, 1463, 1464, 1516, 1523], "excluded_lines": []}, "PasswordManager.sync_index_from_nostr_async": {"executed_lines": [1539, 1541, 1542, 1543, 1544, 1545, 1546, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1594, 1595, 1596, 1597, 1629, 1630, 1631, 1647], "summary": {"covered_lines": 42, "num_statements": 59, "percent_covered": 71.1864406779661, "percent_covered_display": "71", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [1540, 1547, 1548, 1553, 1557, 1604, 1610, 1611, 1616, 1623, 1632, 1633, 1638, 1639, 1642, 1648, 1649], "excluded_lines": []}, "PasswordManager.sync_index_from_nostr": {"executed_lines": [1652], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.start_background_sync": {"executed_lines": [1656, 1657, 1658, 1659, 1660, 1665, 1674, 1675, 1676, 1677, 1680, 1681, 1683], "summary": {"covered_lines": 13, "num_statements": 14, "percent_covered": 92.85714285714286, "percent_covered_display": "93", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1663], "excluded_lines": []}, "PasswordManager.start_background_sync._worker": {"executed_lines": [1666, 1667, 1668, 1669, 1670, 1671, 1672], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.cleanup": {"executed_lines": [1687, 1688, 1690], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [1689, 1691], "excluded_lines": []}, "PasswordManager.start_background_relay_check": {"executed_lines": [1695, 1702, 1719, 1720], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1700], "excluded_lines": []}, "PasswordManager.start_background_relay_check._worker": {"executed_lines": [1703, 1704, 1707, 1708, 1709, 1714, 1715, 1716, 1717], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.start_background_vault_sync": {"executed_lines": [1724, 1725], "summary": {"covered_lines": 2, "num_statements": 12, "percent_covered": 16.666666666666668, "percent_covered_display": "17", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [1727, 1737, 1738, 1739, 1740, 1743, 1744, 1745, 1746, 1748], "excluded_lines": []}, "PasswordManager.start_background_vault_sync._worker": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [1728, 1729, 1730, 1731, 1732, 1733, 1734, 1735], "excluded_lines": []}, "PasswordManager.attempt_initial_sync_async": {"executed_lines": [1757, 1760, 1761, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1797, 1798, 1799, 1800, 1802, 1803, 1804, 1805, 1807, 1811], "summary": {"covered_lines": 32, "num_statements": 37, "percent_covered": 86.48648648648648, "percent_covered_display": "86", "missing_lines": 5, "excluded_lines": 2}, "missing_lines": [1758, 1762, 1801, 1808, 1809], "excluded_lines": [1804, 1805]}, "PasswordManager.attempt_initial_sync": {"executed_lines": [1814], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.sync_index_from_nostr_if_missing": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1822], "excluded_lines": []}, "PasswordManager.sync_index_from_nostr_if_missing_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 2}, "missing_lines": [1825, 1826, 1827, 1828, 1829, 1830, 1831], "excluded_lines": [1832, 1833]}, "PasswordManager.check_nostr_backup_exists": {"executed_lines": [1837, 1840, 1841, 1842, 1843, 1848, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1859], "summary": {"covered_lines": 16, "num_statements": 20, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [1838, 1844, 1845, 1846], "excluded_lines": []}, "PasswordManager.restore_from_nostr_with_guidance": {"executed_lines": [1863, 1864, 1866, 1867, 1868, 1869, 1871, 1872, 1875, 1876, 1877, 1878, 1879, 1880, 1887, 1888], "summary": {"covered_lines": 16, "num_statements": 19, "percent_covered": 84.21052631578948, "percent_covered_display": "84", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1873, 1882, 1885], "excluded_lines": []}, "PasswordManager.handle_add_password": {"executed_lines": [1892], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.handle_add_totp": {"executed_lines": [1897, 1898, 1899, 1900, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1916, 1917, 1918, 1923, 1924, 1927, 1932, 1933, 1934, 1939, 1949, 1953, 1954, 1955, 1956, 1957, 1962, 1963, 1964, 1965, 1966, 1967, 1973, 1974], "summary": {"covered_lines": 35, "num_statements": 76, "percent_covered": 46.05263157894737, "percent_covered_display": "46", "missing_lines": 41, "excluded_lines": 0}, "missing_lines": [1914, 1915, 1919, 1922, 1950, 1951, 1968, 1969, 1975, 1976, 1977, 1978, 1979, 1983, 1984, 1985, 1986, 1987, 1988, 1991, 1996, 1997, 2007, 2008, 2009, 2015, 2016, 2017, 2018, 2019, 2023, 2024, 2025, 2026, 2027, 2028, 2030, 2031, 2032, 2033, 2034], "excluded_lines": []}, "PasswordManager.handle_add_ssh_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 0}, "missing_lines": [2039, 2040, 2041, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2059, 2062, 2065, 2066, 2068, 2071, 2072, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2088, 2089, 2090, 2091, 2092], "excluded_lines": []}, "PasswordManager.handle_add_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 0}, "missing_lines": [2097, 2098, 2099, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2118, 2119, 2120, 2121, 2122, 2125, 2126, 2127, 2129, 2132, 2133, 2135, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2150, 2151, 2152, 2153, 2154, 2158, 2159, 2160, 2161, 2162], "excluded_lines": []}, "PasswordManager.handle_add_pgp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 2}, "missing_lines": [2167, 2168, 2169, 2176, 2177, 2178, 2179, 2180, 2184, 2185, 2186, 2187, 2192, 2200, 2203, 2204, 2206, 2209, 2210, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2226, 2227, 2228, 2229, 2230], "excluded_lines": [2221, 2222]}, "PasswordManager.handle_add_nostr_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 31, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 31, "excluded_lines": 2}, "missing_lines": [2235, 2236, 2237, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2255, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2272, 2273, 2274, 2275, 2278, 2279, 2280, 2286, 2287, 2288, 2289, 2290], "excluded_lines": [2281, 2282]}, "PasswordManager.handle_add_key_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 2}, "missing_lines": [2295, 2296, 2297, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, 2337, 2345, 2346, 2348, 2349, 2350, 2351, 2352, 2353, 2360, 2361, 2362, 2368, 2369, 2370, 2371, 2372], "excluded_lines": [2363, 2364]}, "PasswordManager.handle_add_managed_account": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 30, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 30, "excluded_lines": 2}, "missing_lines": [2377, 2378, 2379, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2397, 2400, 2401, 2402, 2403, 2409, 2410, 2411, 2412, 2419, 2420, 2421, 2423, 2424, 2425, 2431, 2432, 2433, 2434, 2435], "excluded_lines": [2426, 2427]}, "PasswordManager.show_entry_details_by_index": {"executed_lines": [2439, 2440, 2441, 2444, 2445, 2453, 2455, 2457, 2458, 2459, 2460, 2461, 2462], "summary": {"covered_lines": 13, "num_statements": 14, "percent_covered": 92.85714285714286, "percent_covered_display": "93", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [2442], "excluded_lines": []}, "PasswordManager._prompt_toggle_archive": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [2466, 2467, 2472, 2473, 2474, 2475, 2477, 2478, 2479], "excluded_lines": []}, "PasswordManager._entry_type_str": {"executed_lines": [2483, 2484, 2485, 2486], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager._generate_password_for_entry": {"executed_lines": [2492, 2493, 2494, 2496, 2497, 2498, 2500, 2501, 2505, 2506, 2507, 2509], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager._entry_actions_menu": {"executed_lines": [2513, 2514, 2515, 2522, 2523, 2524, 2525, 2526, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2539, 2541, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2562, 2576, 2577, 2578, 2584, 2587, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2602], "summary": {"covered_lines": 45, "num_statements": 61, "percent_covered": 73.77049180327869, "percent_covered_display": "74", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [2557, 2558, 2559, 2560, 2561, 2563, 2564, 2565, 2567, 2568, 2569, 2570, 2573, 2574, 2575, 2601], "excluded_lines": []}, "PasswordManager._entry_edit_menu": {"executed_lines": [2606, 2607, 2608, 2609, 2616, 2617, 2618, 2623, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2638, 2644, 2652, 2657, 2662, 2663, 2664, 2665, 2666, 2667, 2680], "summary": {"covered_lines": 26, "num_statements": 62, "percent_covered": 41.935483870967744, "percent_covered_display": "42", "missing_lines": 36, "excluded_lines": 0}, "missing_lines": [2619, 2620, 2624, 2625, 2633, 2634, 2635, 2636, 2637, 2639, 2640, 2641, 2642, 2643, 2645, 2646, 2647, 2648, 2649, 2653, 2654, 2655, 2656, 2658, 2659, 2660, 2661, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2677, 2679], "excluded_lines": []}, "PasswordManager._entry_qr_menu": {"executed_lines": [2685, 2687, 2688, 2703, 2704, 2705, 2706, 2713, 2714, 2715, 2716, 2721, 2722, 2724, 2728, 2729, 2730, 2731, 2732, 2733, 2736, 2737, 2738], "summary": {"covered_lines": 23, "num_statements": 33, "percent_covered": 69.6969696969697, "percent_covered_display": "70", "missing_lines": 10, "excluded_lines": 3}, "missing_lines": [2689, 2690, 2692, 2696, 2697, 2699, 2700, 2701, 2735, 2740], "excluded_lines": [2741, 2742, 2743]}, "PasswordManager.display_sensitive_entry_info": {"executed_lines": [2756, 2758, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2780, 2781, 2782, 2783, 2784, 2785, 2787, 2788, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2803, 2804, 2812, 2813, 2814, 2815, 2819, 2821, 2822, 2823, 2824, 2827, 2828, 2829, 2830, 2833, 2834, 2835, 2836, 2838, 2839, 2841, 2842, 2843, 2852, 2853, 2857, 2859, 2860, 2861, 2862, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2875, 2876, 2878, 2887, 2888, 2889, 2890, 2892, 2893, 2894, 2895, 2896, 2902, 2906, 2908, 2909, 2910, 2911, 2914, 2915, 2916, 2917, 2920, 2921, 2922, 2923, 2925, 2926, 2928, 2929, 2938, 2942, 2944, 2945, 2946, 2947, 2948, 2951, 2952, 2953, 2954, 2963, 2964, 2966, 2967, 2972, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2982, 2983, 2985, 2990, 2999, 3001, 3002, 3029, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3039, 3040, 3041, 3042, 3044, 3049, 3056, 3057, 3060, 3069, 3070, 3071, 3075, 3078, 3079, 3080, 3081, 3082, 3083, 3085, 3091, 3093, 3095, 3096, 3101, 3103, 3104, 3105, 3106, 3113, 3119, 3120, 3121, 3122, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3144, 3145, 3146, 3147, 3148, 3149, 3160, 3163], "summary": {"covered_lines": 197, "num_statements": 257, "percent_covered": 76.65369649805447, "percent_covered_display": "77", "missing_lines": 60, "excluded_lines": 15}, "missing_lines": [2772, 2773, 2786, 2789, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 2837, 2840, 2844, 2845, 2874, 2877, 2879, 2880, 2924, 2927, 2930, 2931, 2955, 2956, 2965, 2968, 2981, 2984, 2991, 2992, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3021, 3028, 3038, 3043, 3061, 3062, 3072, 3073, 3074, 3092, 3094, 3150, 3153, 3162], "excluded_lines": [2816, 2817, 2818, 2854, 2855, 2856, 2903, 2904, 2905, 2939, 2940, 2941, 2969, 2970, 2971]}, "PasswordManager.handle_retrieve_entry": {"executed_lines": [3168, 3169, 3170, 3177, 3180, 3184, 3186, 3187, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198], "summary": {"covered_lines": 16, "num_statements": 21, "percent_covered": 76.19047619047619, "percent_covered_display": "76", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [3181, 3182, 3183, 3188, 3189], "excluded_lines": []}, "PasswordManager.handle_modify_entry": {"executed_lines": [3206, 3207, 3208, 3215, 3218, 3221, 3224, 3225, 3228, 3230, 3339, 3403, 3512, 3513, 3514, 3515, 3516, 3518, 3524, 3525, 3526, 3527, 3534, 3541, 3547, 3553, 3560, 3561, 3573, 3580, 3581, 3582, 3594, 3597, 3603, 3615, 3616, 3618, 3621, 3622, 3623, 3632], "summary": {"covered_lines": 42, "num_statements": 168, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 126, "excluded_lines": 0}, "missing_lines": [3219, 3220, 3226, 3231, 3232, 3233, 3234, 3235, 3237, 3243, 3244, 3245, 3251, 3255, 3258, 3259, 3260, 3261, 3263, 3267, 3270, 3271, 3272, 3273, 3275, 3279, 3286, 3287, 3288, 3289, 3290, 3291, 3293, 3297, 3299, 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3320, 3323, 3329, 3340, 3341, 3342, 3344, 3350, 3356, 3360, 3367, 3368, 3369, 3370, 3371, 3372, 3374, 3378, 3380, 3387, 3390, 3396, 3407, 3408, 3409, 3410, 3412, 3418, 3424, 3430, 3434, 3435, 3439, 3440, 3444, 3451, 3452, 3453, 3454, 3455, 3456, 3458, 3462, 3464, 3471, 3472, 3473, 3474, 3475, 3476, 3479, 3480, 3481, 3482, 3483, 3487, 3490, 3496, 3504, 3505, 3507, 3562, 3563, 3564, 3565, 3567, 3571, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3626, 3627, 3634, 3635, 3636], "excluded_lines": []}, "PasswordManager.handle_search_entries": {"executed_lines": [3641, 3642, 3643, 3650, 3651, 3652, 3653, 3654, 3656, 3657, 3662, 3663, 3664, 3671, 3672, 3673, 3674, 3676, 3677, 3679, 3682, 3684, 3690, 3691, 3692, 3693, 3694], "summary": {"covered_lines": 27, "num_statements": 35, "percent_covered": 77.14285714285714, "percent_covered_display": "77", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [3658, 3659, 3660, 3675, 3683, 3687, 3688, 3689], "excluded_lines": []}, "PasswordManager.display_entry_details": {"executed_lines": [3698, 3699, 3702, 3703, 3704, 3705, 3706, 3709, 3715, 3716, 3718, 3719, 3721, 3722, 3723, 3724, 3725, 3726, 3732, 3733, 3735, 3736, 3738, 3739, 3740, 3741, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3753, 3754, 3756, 3757, 3758, 3759, 3762, 3763, 3764, 3765, 3768, 3769, 3770, 3771, 3776, 3777, 3779, 3780, 3782, 3783, 3784, 3785, 3788, 3789, 3791, 3792, 3794, 3795, 3796, 3797, 3798, 3799, 3800, 3802, 3803, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3815, 3816, 3817, 3818, 3819, 3821, 3822, 3824, 3825, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3840, 3846], "summary": {"covered_lines": 100, "num_statements": 116, "percent_covered": 86.20689655172414, "percent_covered_display": "86", "missing_lines": 16, "excluded_lines": 2}, "missing_lines": [3700, 3717, 3720, 3734, 3737, 3752, 3755, 3778, 3781, 3790, 3793, 3801, 3804, 3820, 3823, 3839], "excluded_lines": [3772, 3773]}, "PasswordManager.handle_list_entries": {"executed_lines": [3850], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.delete_entry": {"executed_lines": [3854, 3855, 3858, 3861, 3863, 3869, 3872, 3873, 3876, 3877, 3878], "summary": {"covered_lines": 11, "num_statements": 20, "percent_covered": 55.0, "percent_covered_display": "55", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [3859, 3860, 3866, 3867, 3879, 3880, 3885, 3886, 3887], "excluded_lines": []}, "PasswordManager.handle_archive_entry": {"executed_lines": [3892, 3893, 3896, 3899, 3900, 3901, 3902, 3903], "summary": {"covered_lines": 8, "num_statements": 13, "percent_covered": 61.53846153846154, "percent_covered_display": "62", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [3897, 3898, 3904, 3905, 3906], "excluded_lines": []}, "PasswordManager.handle_view_archived_entries": {"executed_lines": [3911, 3913, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3940, 3941, 3942, 3943, 3946, 3947, 3948, 3953, 3954, 3955, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3978, 3979], "summary": {"covered_lines": 42, "num_statements": 49, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [3951, 3952, 3977, 3981, 3982, 3983, 3984], "excluded_lines": []}, "PasswordManager.handle_view_archived_entries._load_archived_entries": {"executed_lines": [3916, 3919], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.handle_display_totp_codes": {"executed_lines": [3988], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.handle_verify_checksum": {"executed_lines": [3995, 3996, 3997, 4004, 4005, 4006, 4007, 4008, 4012, 4013, 4015, 4016, 4017, 4019, 4025], "summary": {"covered_lines": 15, "num_statements": 18, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [4026, 4027, 4028], "excluded_lines": []}, "PasswordManager.handle_update_script_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [4033, 4034, 4035, 4036, 4037, 4038, 4045, 4046, 4047, 4054, 4055, 4056, 4057], "excluded_lines": []}, "PasswordManager.get_encrypted_data": {"executed_lines": [4065, 4066, 4067, 4068, 4069], "summary": {"covered_lines": 5, "num_statements": 12, "percent_covered": 41.666666666666664, "percent_covered_display": "42", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [4071, 4072, 4073, 4074, 4075, 4076, 4077], "excluded_lines": []}, "PasswordManager.decrypt_and_save_index_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [4085, 4086, 4087, 4088, 4089, 4092, 4098], "excluded_lines": []}, "PasswordManager.sync_vault_async": {"executed_lines": [4104, 4105, 4106, 4107, 4108, 4110, 4111, 4112, 4113, 4114, 4115, 4117, 4121, 4122, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4135, 4136, 4141, 4142, 4143], "summary": {"covered_lines": 26, "num_statements": 29, "percent_covered": 89.65517241379311, "percent_covered_display": "90", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [4109, 4120, 4123], "excluded_lines": []}, "PasswordManager.sync_vault": {"executed_lines": [4148], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.backup_database": {"executed_lines": [4154, 4155, 4156], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [4157, 4158, 4159], "excluded_lines": []}, "PasswordManager.restore_database": {"executed_lines": [4165, 4166, 4167], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [4172, 4173, 4174], "excluded_lines": []}, "PasswordManager.handle_export_database": {"executed_lines": [4189, 4190, 4191, 4198, 4199, 4202, 4209, 4210, 4211, 4212, 4213], "summary": {"covered_lines": 11, "num_statements": 15, "percent_covered": 73.33333333333333, "percent_covered_display": "73", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [4214, 4215, 4216, 4217], "excluded_lines": []}, "PasswordManager.handle_import_database": {"executed_lines": [4223, 4224, 4230, 4233, 4234, 4235, 4240, 4241, 4243, 4244, 4252, 4253, 4259, 4268, 4269, 4270, 4271], "summary": {"covered_lines": 17, "num_statements": 42, "percent_covered": 40.476190476190474, "percent_covered_display": "40", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [4236, 4237, 4238, 4239, 4260, 4261, 4267, 4272, 4273, 4274, 4280, 4282, 4283, 4284, 4285, 4286, 4289, 4290, 4291, 4292, 4293, 4296, 4297, 4299, 4300], "excluded_lines": []}, "PasswordManager.handle_export_totp_codes": {"executed_lines": [4305, 4306, 4307, 4308, 4315, 4316, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4330, 4331, 4341, 4345, 4348, 4350, 4352, 4363, 4365, 4366, 4367], "summary": {"covered_lines": 25, "num_statements": 41, "percent_covered": 60.97560975609756, "percent_covered_display": "61", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [4327, 4328, 4329, 4342, 4343, 4353, 4354, 4355, 4358, 4359, 4360, 4361, 4368, 4369, 4370, 4371], "excluded_lines": []}, "PasswordManager.handle_backup_reveal_parent_seed": {"executed_lines": [4386, 4387, 4388, 4395, 4396, 4400, 4406, 4410, 4415, 4418, 4419, 4422, 4423, 4424, 4431, 4432, 4436, 4439, 4440, 4443, 4444, 4446, 4447, 4451, 4454, 4460, 4461, 4462, 4465], "summary": {"covered_lines": 29, "num_statements": 39, "percent_covered": 74.35897435897436, "percent_covered_display": "74", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [4407, 4411, 4412, 4433, 4434, 4448, 4449, 4466, 4467, 4468], "excluded_lines": []}, "PasswordManager.verify_password": {"executed_lines": [4480, 4481, 4482, 4483, 4495, 4496, 4497, 4500], "summary": {"covered_lines": 8, "num_statements": 25, "percent_covered": 32.0, "percent_covered_display": "32", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [4485, 4486, 4487, 4488, 4489, 4491, 4492, 4493, 4499, 4501, 4502, 4503, 4509, 4510, 4511, 4512, 4513], "excluded_lines": []}, "PasswordManager.is_valid_filename": {"executed_lines": [4526, 4527, 4528, 4529, 4530], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager.store_hashed_password": {"executed_lines": [4537, 4538, 4539, 4540, 4550], "summary": {"covered_lines": 5, "num_statements": 21, "percent_covered": 23.80952380952381, "percent_covered_display": "24", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [4543, 4544, 4549, 4551, 4553, 4554, 4555, 4556, 4558, 4559, 4564, 4565, 4568, 4569, 4570, 4571], "excluded_lines": []}, "PasswordManager.change_password": {"executed_lines": [4575, 4576, 4577, 4581, 4582, 4585, 4587, 4588, 4591, 4593, 4595, 4596, 4597, 4598, 4599, 4602, 4603, 4604, 4606, 4610, 4611, 4621, 4637, 4638, 4639], "summary": {"covered_lines": 25, "num_statements": 37, "percent_covered": 67.56756756756756, "percent_covered_display": "68", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [4578, 4607, 4608, 4624, 4626, 4627, 4628, 4640, 4641, 4644, 4645, 4646], "excluded_lines": []}, "PasswordManager.get_profile_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 47, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 47, "excluded_lines": 0}, "missing_lines": [4650, 4651, 4653, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4674, 4675, 4676, 4679, 4680, 4681, 4682, 4683, 4685, 4686, 4687, 4689, 4692, 4693, 4694, 4695, 4698, 4701, 4702, 4703, 4708, 4709, 4710, 4711, 4712, 4714, 4715, 4716, 4718], "excluded_lines": []}, "PasswordManager.display_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [4722, 4723, 4724, 4725, 4727, 4728, 4729, 4730, 4731, 4732, 4738, 4739, 4744, 4745, 4751, 4757, 4758, 4759, 4760], "excluded_lines": []}, "": {"executed_lines": [3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 52, 53, 60, 66, 67, 68, 69, 75, 76, 77, 78, 79, 81, 94, 95, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 112, 113, 114, 115, 118, 121, 122, 124, 141, 158, 164, 189, 190, 191, 193, 194, 197, 209, 210, 212, 218, 227, 228, 237, 238, 239, 240, 241, 242, 244, 327, 328, 339, 340, 345, 355, 369, 386, 387, 391, 392, 398, 399, 407, 408, 422, 423, 432, 441, 450, 465, 477, 478, 483, 484, 489, 490, 497, 505, 551, 565, 577, 621, 667, 700, 794, 839, 840, 841, 844, 845, 875, 876, 900, 901, 987, 988, 1032, 1071, 1077, 1169, 1170, 1251, 1271, 1292, 1293, 1365, 1395, 1537, 1651, 1654, 1685, 1693, 1722, 1750, 1813, 1816, 1824, 1835, 1861, 1890, 1891, 1894, 1895, 2036, 2037, 2094, 2095, 2164, 2165, 2232, 2233, 2292, 2293, 2374, 2375, 2437, 2464, 2481, 2488, 2511, 2604, 2682, 2745, 3165, 3166, 3200, 3201, 3638, 3639, 3696, 3848, 3849, 3852, 3889, 3890, 3908, 3909, 3986, 3987, 3990, 3991, 4030, 4031, 4059, 4079, 4100, 4145, 4150, 4161, 4176, 4177, 4219, 4220, 4302, 4303, 4373, 4374, 4470, 4515, 4532, 4573, 4648, 4720], "summary": {"covered_lines": 219, "num_statements": 219, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"AuditLogger": {"executed_lines": [125, 126, 127, 128, 129, 142, 143, 148, 149, 152, 153, 154, 155], "summary": {"covered_lines": 13, "num_statements": 23, "percent_covered": 56.52173913043478, "percent_covered_display": "57", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [130, 131, 132, 133, 134, 135, 136, 137, 138, 139], "excluded_lines": []}, "Notification": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AuthGuard": {"executed_lines": [215, 216, 220, 221, 222, 223, 224], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordManager": {"executed_lines": [254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 277, 278, 279, 280, 281, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 304, 305, 306, 309, 310, 311, 314, 316, 318, 321, 323, 348, 349, 350, 351, 352, 353, 357, 363, 364, 365, 366, 367, 371, 372, 373, 374, 375, 376, 377, 378, 394, 396, 400, 405, 425, 426, 427, 428, 434, 435, 436, 437, 438, 439, 443, 444, 445, 446, 447, 448, 452, 453, 454, 458, 462, 463, 467, 469, 470, 471, 472, 473, 474, 475, 479, 480, 481, 485, 486, 487, 491, 492, 493, 494, 495, 499, 500, 501, 502, 503, 518, 519, 521, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 536, 541, 542, 543, 546, 547, 548, 549, 555, 556, 557, 569, 570, 572, 575, 581, 582, 583, 586, 587, 588, 590, 591, 592, 597, 598, 600, 602, 603, 607, 608, 613, 614, 626, 627, 634, 635, 636, 637, 638, 639, 644, 648, 649, 657, 658, 660, 662, 663, 664, 665, 670, 671, 672, 675, 686, 688, 689, 690, 709, 710, 711, 712, 713, 714, 716, 721, 726, 727, 729, 730, 731, 733, 734, 735, 736, 737, 738, 739, 741, 744, 745, 746, 747, 752, 753, 754, 755, 757, 764, 765, 766, 767, 768, 770, 775, 776, 781, 799, 802, 805, 806, 811, 816, 817, 822, 825, 826, 830, 831, 832, 833, 842, 847, 850, 851, 852, 853, 855, 859, 860, 861, 863, 864, 865, 866, 867, 869, 870, 871, 872, 873, 878, 880, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 894, 895, 896, 897, 898, 993, 995, 1005, 1006, 1007, 1009, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1029, 1052, 1053, 1054, 1055, 1056, 1058, 1060, 1064, 1065, 1066, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1093, 1094, 1095, 1106, 1109, 1115, 1116, 1117, 1118, 1119, 1120, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1133, 1137, 1138, 1139, 1141, 1146, 1147, 1149, 1150, 1152, 1153, 1157, 1158, 1159, 1160, 1177, 1178, 1179, 1180, 1182, 1184, 1185, 1186, 1187, 1192, 1193, 1205, 1214, 1217, 1224, 1225, 1226, 1227, 1228, 1233, 1234, 1235, 1238, 1239, 1240, 1241, 1243, 1244, 1246, 1261, 1262, 1263, 1264, 1265, 1266, 1278, 1279, 1280, 1281, 1282, 1303, 1304, 1305, 1309, 1313, 1318, 1320, 1321, 1323, 1324, 1325, 1326, 1331, 1335, 1336, 1338, 1342, 1347, 1348, 1350, 1351, 1353, 1354, 1358, 1359, 1369, 1370, 1371, 1372, 1373, 1374, 1376, 1386, 1387, 1389, 1400, 1402, 1406, 1409, 1413, 1414, 1419, 1420, 1421, 1427, 1428, 1431, 1432, 1433, 1435, 1440, 1441, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1465, 1466, 1469, 1470, 1471, 1472, 1473, 1474, 1485, 1488, 1490, 1491, 1492, 1499, 1500, 1501, 1502, 1503, 1504, 1507, 1508, 1509, 1530, 1532, 1533, 1534, 1535, 1539, 1541, 1542, 1543, 1544, 1545, 1546, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1594, 1595, 1596, 1597, 1629, 1630, 1631, 1647, 1652, 1656, 1657, 1658, 1659, 1660, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1674, 1675, 1676, 1677, 1680, 1681, 1683, 1687, 1688, 1690, 1695, 1702, 1703, 1704, 1707, 1708, 1709, 1714, 1715, 1716, 1717, 1719, 1720, 1724, 1725, 1757, 1760, 1761, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1797, 1798, 1799, 1800, 1802, 1803, 1804, 1805, 1807, 1811, 1814, 1837, 1840, 1841, 1842, 1843, 1848, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1859, 1863, 1864, 1866, 1867, 1868, 1869, 1871, 1872, 1875, 1876, 1877, 1878, 1879, 1880, 1887, 1888, 1892, 1897, 1898, 1899, 1900, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1916, 1917, 1918, 1923, 1924, 1927, 1932, 1933, 1934, 1939, 1949, 1953, 1954, 1955, 1956, 1957, 1962, 1963, 1964, 1965, 1966, 1967, 1973, 1974, 2439, 2440, 2441, 2444, 2445, 2453, 2455, 2457, 2458, 2459, 2460, 2461, 2462, 2483, 2484, 2485, 2486, 2492, 2493, 2494, 2496, 2497, 2498, 2500, 2501, 2505, 2506, 2507, 2509, 2513, 2514, 2515, 2522, 2523, 2524, 2525, 2526, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2539, 2541, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2562, 2576, 2577, 2578, 2584, 2587, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2602, 2606, 2607, 2608, 2609, 2616, 2617, 2618, 2623, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2638, 2644, 2652, 2657, 2662, 2663, 2664, 2665, 2666, 2667, 2680, 2685, 2687, 2688, 2703, 2704, 2705, 2706, 2713, 2714, 2715, 2716, 2721, 2722, 2724, 2728, 2729, 2730, 2731, 2732, 2733, 2736, 2737, 2738, 2756, 2758, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2780, 2781, 2782, 2783, 2784, 2785, 2787, 2788, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2803, 2804, 2812, 2813, 2814, 2815, 2819, 2821, 2822, 2823, 2824, 2827, 2828, 2829, 2830, 2833, 2834, 2835, 2836, 2838, 2839, 2841, 2842, 2843, 2852, 2853, 2857, 2859, 2860, 2861, 2862, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2875, 2876, 2878, 2887, 2888, 2889, 2890, 2892, 2893, 2894, 2895, 2896, 2902, 2906, 2908, 2909, 2910, 2911, 2914, 2915, 2916, 2917, 2920, 2921, 2922, 2923, 2925, 2926, 2928, 2929, 2938, 2942, 2944, 2945, 2946, 2947, 2948, 2951, 2952, 2953, 2954, 2963, 2964, 2966, 2967, 2972, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2982, 2983, 2985, 2990, 2999, 3001, 3002, 3029, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3039, 3040, 3041, 3042, 3044, 3049, 3056, 3057, 3060, 3069, 3070, 3071, 3075, 3078, 3079, 3080, 3081, 3082, 3083, 3085, 3091, 3093, 3095, 3096, 3101, 3103, 3104, 3105, 3106, 3113, 3119, 3120, 3121, 3122, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3144, 3145, 3146, 3147, 3148, 3149, 3160, 3163, 3168, 3169, 3170, 3177, 3180, 3184, 3186, 3187, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198, 3206, 3207, 3208, 3215, 3218, 3221, 3224, 3225, 3228, 3230, 3339, 3403, 3512, 3513, 3514, 3515, 3516, 3518, 3524, 3525, 3526, 3527, 3534, 3541, 3547, 3553, 3560, 3561, 3573, 3580, 3581, 3582, 3594, 3597, 3603, 3615, 3616, 3618, 3621, 3622, 3623, 3632, 3641, 3642, 3643, 3650, 3651, 3652, 3653, 3654, 3656, 3657, 3662, 3663, 3664, 3671, 3672, 3673, 3674, 3676, 3677, 3679, 3682, 3684, 3690, 3691, 3692, 3693, 3694, 3698, 3699, 3702, 3703, 3704, 3705, 3706, 3709, 3715, 3716, 3718, 3719, 3721, 3722, 3723, 3724, 3725, 3726, 3732, 3733, 3735, 3736, 3738, 3739, 3740, 3741, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3753, 3754, 3756, 3757, 3758, 3759, 3762, 3763, 3764, 3765, 3768, 3769, 3770, 3771, 3776, 3777, 3779, 3780, 3782, 3783, 3784, 3785, 3788, 3789, 3791, 3792, 3794, 3795, 3796, 3797, 3798, 3799, 3800, 3802, 3803, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3815, 3816, 3817, 3818, 3819, 3821, 3822, 3824, 3825, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3840, 3846, 3850, 3854, 3855, 3858, 3861, 3863, 3869, 3872, 3873, 3876, 3877, 3878, 3892, 3893, 3896, 3899, 3900, 3901, 3902, 3903, 3911, 3913, 3916, 3919, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3940, 3941, 3942, 3943, 3946, 3947, 3948, 3953, 3954, 3955, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3978, 3979, 3988, 3995, 3996, 3997, 4004, 4005, 4006, 4007, 4008, 4012, 4013, 4015, 4016, 4017, 4019, 4025, 4065, 4066, 4067, 4068, 4069, 4104, 4105, 4106, 4107, 4108, 4110, 4111, 4112, 4113, 4114, 4115, 4117, 4121, 4122, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4135, 4136, 4141, 4142, 4143, 4148, 4154, 4155, 4156, 4165, 4166, 4167, 4189, 4190, 4191, 4198, 4199, 4202, 4209, 4210, 4211, 4212, 4213, 4223, 4224, 4230, 4233, 4234, 4235, 4240, 4241, 4243, 4244, 4252, 4253, 4259, 4268, 4269, 4270, 4271, 4305, 4306, 4307, 4308, 4315, 4316, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4330, 4331, 4341, 4345, 4348, 4350, 4352, 4363, 4365, 4366, 4367, 4386, 4387, 4388, 4395, 4396, 4400, 4406, 4410, 4415, 4418, 4419, 4422, 4423, 4424, 4431, 4432, 4436, 4439, 4440, 4443, 4444, 4446, 4447, 4451, 4454, 4460, 4461, 4462, 4465, 4480, 4481, 4482, 4483, 4495, 4496, 4497, 4500, 4526, 4527, 4528, 4529, 4530, 4537, 4538, 4539, 4540, 4550, 4575, 4576, 4577, 4581, 4582, 4585, 4587, 4588, 4591, 4593, 4595, 4596, 4597, 4598, 4599, 4602, 4603, 4604, 4606, 4610, 4611, 4621, 4637, 4638, 4639], "summary": {"covered_lines": 1419, "num_statements": 2437, "percent_covered": 58.22732868280673, "percent_covered_display": "58", "missing_lines": 1018, "excluded_lines": 32}, "missing_lines": [333, 334, 335, 343, 389, 395, 401, 402, 403, 410, 411, 412, 413, 414, 417, 418, 419, 420, 429, 430, 455, 456, 468, 520, 522, 558, 559, 560, 563, 604, 605, 610, 616, 617, 618, 619, 641, 642, 645, 676, 682, 697, 698, 758, 759, 760, 761, 762, 777, 778, 779, 780, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 800, 803, 818, 819, 820, 827, 828, 829, 834, 835, 836, 837, 848, 879, 906, 907, 908, 911, 912, 915, 916, 917, 923, 927, 928, 929, 934, 936, 937, 938, 939, 941, 942, 943, 946, 947, 948, 951, 956, 960, 961, 962, 963, 964, 965, 966, 967, 970, 975, 976, 977, 978, 980, 981, 982, 983, 984, 985, 1008, 1010, 1025, 1026, 1030, 1061, 1062, 1063, 1067, 1068, 1069, 1075, 1096, 1102, 1110, 1113, 1161, 1162, 1163, 1165, 1166, 1167, 1188, 1189, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1203, 1204, 1206, 1212, 1218, 1221, 1229, 1230, 1248, 1249, 1267, 1268, 1269, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1314, 1315, 1360, 1361, 1362, 1363, 1379, 1380, 1381, 1384, 1390, 1391, 1392, 1393, 1403, 1459, 1460, 1461, 1462, 1463, 1464, 1516, 1523, 1540, 1547, 1548, 1553, 1557, 1604, 1610, 1611, 1616, 1623, 1632, 1633, 1638, 1639, 1642, 1648, 1649, 1663, 1689, 1691, 1700, 1727, 1728, 1729, 1730, 1731, 1732, 1733, 1734, 1735, 1737, 1738, 1739, 1740, 1743, 1744, 1745, 1746, 1748, 1758, 1762, 1801, 1808, 1809, 1822, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1838, 1844, 1845, 1846, 1873, 1882, 1885, 1914, 1915, 1919, 1922, 1950, 1951, 1968, 1969, 1975, 1976, 1977, 1978, 1979, 1983, 1984, 1985, 1986, 1987, 1988, 1991, 1996, 1997, 2007, 2008, 2009, 2015, 2016, 2017, 2018, 2019, 2023, 2024, 2025, 2026, 2027, 2028, 2030, 2031, 2032, 2033, 2034, 2039, 2040, 2041, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2059, 2062, 2065, 2066, 2068, 2071, 2072, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2088, 2089, 2090, 2091, 2092, 2097, 2098, 2099, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2118, 2119, 2120, 2121, 2122, 2125, 2126, 2127, 2129, 2132, 2133, 2135, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2150, 2151, 2152, 2153, 2154, 2158, 2159, 2160, 2161, 2162, 2167, 2168, 2169, 2176, 2177, 2178, 2179, 2180, 2184, 2185, 2186, 2187, 2192, 2200, 2203, 2204, 2206, 2209, 2210, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2226, 2227, 2228, 2229, 2230, 2235, 2236, 2237, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2255, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2272, 2273, 2274, 2275, 2278, 2279, 2280, 2286, 2287, 2288, 2289, 2290, 2295, 2296, 2297, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, 2337, 2345, 2346, 2348, 2349, 2350, 2351, 2352, 2353, 2360, 2361, 2362, 2368, 2369, 2370, 2371, 2372, 2377, 2378, 2379, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2397, 2400, 2401, 2402, 2403, 2409, 2410, 2411, 2412, 2419, 2420, 2421, 2423, 2424, 2425, 2431, 2432, 2433, 2434, 2435, 2442, 2466, 2467, 2472, 2473, 2474, 2475, 2477, 2478, 2479, 2557, 2558, 2559, 2560, 2561, 2563, 2564, 2565, 2567, 2568, 2569, 2570, 2573, 2574, 2575, 2601, 2619, 2620, 2624, 2625, 2633, 2634, 2635, 2636, 2637, 2639, 2640, 2641, 2642, 2643, 2645, 2646, 2647, 2648, 2649, 2653, 2654, 2655, 2656, 2658, 2659, 2660, 2661, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2677, 2679, 2689, 2690, 2692, 2696, 2697, 2699, 2700, 2701, 2735, 2740, 2772, 2773, 2786, 2789, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 2837, 2840, 2844, 2845, 2874, 2877, 2879, 2880, 2924, 2927, 2930, 2931, 2955, 2956, 2965, 2968, 2981, 2984, 2991, 2992, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3021, 3028, 3038, 3043, 3061, 3062, 3072, 3073, 3074, 3092, 3094, 3150, 3153, 3162, 3181, 3182, 3183, 3188, 3189, 3219, 3220, 3226, 3231, 3232, 3233, 3234, 3235, 3237, 3243, 3244, 3245, 3251, 3255, 3258, 3259, 3260, 3261, 3263, 3267, 3270, 3271, 3272, 3273, 3275, 3279, 3286, 3287, 3288, 3289, 3290, 3291, 3293, 3297, 3299, 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3320, 3323, 3329, 3340, 3341, 3342, 3344, 3350, 3356, 3360, 3367, 3368, 3369, 3370, 3371, 3372, 3374, 3378, 3380, 3387, 3390, 3396, 3407, 3408, 3409, 3410, 3412, 3418, 3424, 3430, 3434, 3435, 3439, 3440, 3444, 3451, 3452, 3453, 3454, 3455, 3456, 3458, 3462, 3464, 3471, 3472, 3473, 3474, 3475, 3476, 3479, 3480, 3481, 3482, 3483, 3487, 3490, 3496, 3504, 3505, 3507, 3562, 3563, 3564, 3565, 3567, 3571, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3626, 3627, 3634, 3635, 3636, 3658, 3659, 3660, 3675, 3683, 3687, 3688, 3689, 3700, 3717, 3720, 3734, 3737, 3752, 3755, 3778, 3781, 3790, 3793, 3801, 3804, 3820, 3823, 3839, 3859, 3860, 3866, 3867, 3879, 3880, 3885, 3886, 3887, 3897, 3898, 3904, 3905, 3906, 3951, 3952, 3977, 3981, 3982, 3983, 3984, 4026, 4027, 4028, 4033, 4034, 4035, 4036, 4037, 4038, 4045, 4046, 4047, 4054, 4055, 4056, 4057, 4071, 4072, 4073, 4074, 4075, 4076, 4077, 4085, 4086, 4087, 4088, 4089, 4092, 4098, 4109, 4120, 4123, 4157, 4158, 4159, 4172, 4173, 4174, 4214, 4215, 4216, 4217, 4236, 4237, 4238, 4239, 4260, 4261, 4267, 4272, 4273, 4274, 4280, 4282, 4283, 4284, 4285, 4286, 4289, 4290, 4291, 4292, 4293, 4296, 4297, 4299, 4300, 4327, 4328, 4329, 4342, 4343, 4353, 4354, 4355, 4358, 4359, 4360, 4361, 4368, 4369, 4370, 4371, 4407, 4411, 4412, 4433, 4434, 4448, 4449, 4466, 4467, 4468, 4485, 4486, 4487, 4488, 4489, 4491, 4492, 4493, 4499, 4501, 4502, 4503, 4509, 4510, 4511, 4512, 4513, 4543, 4544, 4549, 4551, 4553, 4554, 4555, 4556, 4558, 4559, 4564, 4565, 4568, 4569, 4570, 4571, 4578, 4607, 4608, 4624, 4626, 4627, 4628, 4640, 4641, 4644, 4645, 4646, 4650, 4651, 4653, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4674, 4675, 4676, 4679, 4680, 4681, 4682, 4683, 4685, 4686, 4687, 4689, 4692, 4693, 4694, 4695, 4698, 4701, 4702, 4703, 4708, 4709, 4710, 4711, 4712, 4714, 4715, 4716, 4718, 4722, 4723, 4724, 4725, 4727, 4728, 4729, 4730, 4731, 4732, 4738, 4739, 4744, 4745, 4751, 4757, 4758, 4759, 4760], "excluded_lines": [1804, 1805, 1832, 1833, 2221, 2222, 2281, 2282, 2363, 2364, 2426, 2427, 2741, 2742, 2743, 2816, 2817, 2818, 2854, 2855, 2856, 2903, 2904, 2905, 2939, 2940, 2941, 2969, 2970, 2971, 3772, 3773]}, "": {"executed_lines": [3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 52, 53, 60, 66, 67, 68, 69, 75, 76, 77, 78, 79, 81, 94, 95, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 112, 113, 114, 115, 118, 121, 122, 124, 141, 158, 160, 161, 164, 189, 190, 191, 193, 194, 197, 200, 201, 202, 204, 206, 209, 210, 212, 218, 227, 228, 237, 238, 239, 240, 241, 242, 244, 327, 328, 339, 340, 345, 355, 369, 386, 387, 391, 392, 398, 399, 407, 408, 422, 423, 432, 441, 450, 465, 477, 478, 483, 484, 489, 490, 497, 505, 551, 565, 577, 621, 667, 700, 794, 839, 840, 841, 844, 845, 875, 876, 900, 901, 987, 988, 1032, 1071, 1077, 1169, 1170, 1251, 1271, 1292, 1293, 1365, 1395, 1537, 1651, 1654, 1685, 1693, 1722, 1750, 1813, 1816, 1824, 1835, 1861, 1890, 1891, 1894, 1895, 2036, 2037, 2094, 2095, 2164, 2165, 2232, 2233, 2292, 2293, 2374, 2375, 2437, 2464, 2481, 2488, 2511, 2604, 2682, 2745, 3165, 3166, 3200, 3201, 3638, 3639, 3696, 3848, 3849, 3852, 3889, 3890, 3908, 3909, 3986, 3987, 3990, 3991, 4030, 4031, 4059, 4079, 4100, 4145, 4150, 4161, 4176, 4177, 4219, 4220, 4302, 4303, 4373, 4374, 4470, 4515, 4532, 4573, 4648, 4720], "summary": {"covered_lines": 226, "num_statements": 236, "percent_covered": 95.76271186440678, "percent_covered_display": "96", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [174, 175, 176, 177, 180, 182, 183, 185, 186, 203], "excluded_lines": []}}}, "src/seedpass/core/menu_handler.py": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 16, 20, 21, 23, 24, 26, 27, 29, 30, 31, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 58, 59, 62, 63, 64, 73, 74, 75, 82, 83, 84, 85, 86, 89, 92, 93, 94, 97, 98, 99, 100, 102, 103, 105, 106, 107, 108, 115, 116, 117, 118, 119, 122, 123, 124, 125, 127, 131, 133, 134, 135, 136, 137, 141, 142, 143, 144, 151, 152, 153, 154, 177, 178, 179, 180, 181, 186, 187, 188, 189, 190, 193, 197, 200, 201, 202, 205, 207, 208, 209], "summary": {"covered_lines": 101, "num_statements": 127, "percent_covered": 79.5275590551181, "percent_covered_display": "80", "missing_lines": 26, "excluded_lines": 8}, "missing_lines": [51, 55, 56, 66, 67, 88, 95, 96, 128, 129, 138, 139, 155, 156, 157, 158, 163, 164, 165, 166, 167, 170, 174, 203, 204, 206], "excluded_lines": [16, 17, 98, 99, 100, 210, 211, 212], "functions": {"MenuHandler.__init__": {"executed_lines": [24], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MenuHandler.handle_list_entries": {"executed_lines": [29, 30, 31, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 58, 59, 62, 63, 64, 73, 74, 75, 82, 83, 84, 85, 86, 89, 92, 93, 94, 97, 98, 99, 100], "summary": {"covered_lines": 36, "num_statements": 44, "percent_covered": 81.81818181818181, "percent_covered_display": "82", "missing_lines": 8, "excluded_lines": 3}, "missing_lines": [51, 55, 56, 66, 67, 88, 95, 96], "excluded_lines": [98, 99, 100]}, "MenuHandler.handle_display_totp_codes": {"executed_lines": [105, 106, 107, 108, 115, 116, 117, 118, 119, 122, 123, 124, 125, 127, 131, 133, 134, 135, 136, 137, 141, 142, 143, 144, 151, 152, 153, 154, 177, 178, 179, 180, 181, 186, 187, 188, 189, 190, 193, 197, 200, 201, 202, 205, 207, 208, 209], "summary": {"covered_lines": 47, "num_statements": 65, "percent_covered": 72.3076923076923, "percent_covered_display": "72", "missing_lines": 18, "excluded_lines": 3}, "missing_lines": [128, 129, 138, 139, 155, 156, 157, 158, 163, 164, 165, 166, 167, 170, 174, 203, 204, 206], "excluded_lines": [210, 211, 212]}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 16, 20, 21, 23, 26, 27, 102, 103], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [16, 17]}}, "classes": {"MenuHandler": {"executed_lines": [24, 29, 30, 31, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 58, 59, 62, 63, 64, 73, 74, 75, 82, 83, 84, 85, 86, 89, 92, 93, 94, 97, 98, 99, 100, 105, 106, 107, 108, 115, 116, 117, 118, 119, 122, 123, 124, 125, 127, 131, 133, 134, 135, 136, 137, 141, 142, 143, 144, 151, 152, 153, 154, 177, 178, 179, 180, 181, 186, 187, 188, 189, 190, 193, 197, 200, 201, 202, 205, 207, 208, 209], "summary": {"covered_lines": 84, "num_statements": 110, "percent_covered": 76.36363636363636, "percent_covered_display": "76", "missing_lines": 26, "excluded_lines": 6}, "missing_lines": [51, 55, 56, 66, 67, 88, 95, 96, 128, 129, 138, 139, 155, 156, 157, 158, 163, 164, 165, 166, 167, 170, 174, 203, 204, 206], "excluded_lines": [98, 99, 100, 210, 211, 212]}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 16, 20, 21, 23, 26, 27, 102, 103], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [16, 17]}}}, "src/seedpass/core/migrations.py": {"executed_lines": [1, 3, 5, 7, 10, 15, 16, 17, 19, 22, 23, 25, 26, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46, 47, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 61, 62, 64, 65, 66, 67, 68, 71, 74, 76, 77, 80, 81, 82, 84, 85, 87], "summary": {"covered_lines": 56, "num_statements": 58, "percent_covered": 96.55172413793103, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [78, 83], "excluded_lines": [], "functions": {"migration": {"executed_lines": [15, 19], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "migration.decorator": {"executed_lines": [16, 17], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_v0_to_v1": {"executed_lines": [25, 26], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_v1_to_v2": {"executed_lines": [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_v2_to_v3": {"executed_lines": [49, 50, 51, 52, 53, 54, 55, 56, 57, 58], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_v3_to_v4": {"executed_lines": [64, 65, 66, 67, 68], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "apply_migrations": {"executed_lines": [76, 77, 80, 81, 82, 84, 85, 87], "summary": {"covered_lines": 8, "num_statements": 10, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [78, 83], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 7, 10, 22, 23, 29, 30, 46, 47, 61, 62, 71, 74], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 7, 10, 15, 16, 17, 19, 22, 23, 25, 26, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46, 47, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 61, 62, 64, 65, 66, 67, 68, 71, 74, 76, 77, 80, 81, 82, 84, 85, 87], "summary": {"covered_lines": 56, "num_statements": 58, "percent_covered": 96.55172413793103, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [78, 83], "excluded_lines": []}}}, "src/seedpass/core/password_generation.py": {"executed_lines": [3, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 47, 49, 55, 58, 61, 62, 63, 76, 77, 78, 79, 80, 81, 82, 83, 86, 87, 95, 110, 111, 112, 113, 114, 116, 117, 119, 123, 129, 131, 132, 134, 141, 142, 144, 145, 146, 148, 150, 151, 152, 154, 163, 164, 165, 166, 167, 168, 169, 170, 172, 175, 176, 177, 178, 179, 181, 202, 204, 205, 208, 211, 219, 221, 222, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 236, 238, 239, 240, 243, 246, 247, 248, 249, 250, 251, 252, 259, 260, 263, 264, 268, 270, 271, 272, 273, 275, 291, 292, 293, 294, 295, 297, 298, 299, 300, 301, 303, 306, 307, 308, 309, 311, 316, 317, 318, 319, 322, 323, 325, 327, 328, 329, 332, 333, 334, 335, 336, 337, 339, 340, 341, 342, 343, 344, 346, 347, 348, 349, 350, 351, 353, 354, 355, 356, 357, 358, 361, 362, 363, 364, 366, 367, 369, 370, 371, 372, 376, 377, 378, 379, 380, 381, 382, 383, 384, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 404, 405, 406, 411, 414, 415, 420, 421, 422, 423, 424, 428, 436, 438, 441, 444, 445, 446, 448, 449, 455, 456, 461, 464, 466, 469, 480, 481, 482, 490, 497, 498, 499, 500, 501, 502, 504, 505, 507, 509, 510, 512, 513, 514, 516, 517, 518, 519, 520, 521, 522, 524, 525, 526, 527, 528, 529, 530, 531, 532, 534, 535, 536, 538, 539, 542, 543, 544, 545, 548, 550, 551, 552, 554, 555, 556, 557, 558, 559, 571], "summary": {"covered_lines": 265, "num_statements": 277, "percent_covered": 95.66787003610108, "percent_covered_display": "96", "missing_lines": 12, "excluded_lines": 13}, "missing_lines": [124, 125, 126, 127, 212, 215, 368, 385, 430, 431, 432, 433], "excluded_lines": [39, 40, 41, 42, 43, 45, 516, 517, 518, 519, 520, 521, 522], "functions": {"PasswordGenerator.__init__": {"executed_lines": [110, 111, 112, 113, 114, 116, 117, 119, 123], "summary": {"covered_lines": 9, "num_statements": 13, "percent_covered": 69.23076923076923, "percent_covered_display": "69", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [124, 125, 126, 127], "excluded_lines": []}, "PasswordGenerator._derive_password_entropy": {"executed_lines": [131, 132, 134, 141, 142, 144, 145, 146], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordGenerator._map_entropy_to_chars": {"executed_lines": [150, 151, 152], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordGenerator._fisher_yates_hmac": {"executed_lines": [163, 164, 165, 166, 167, 168, 169, 170], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordGenerator._shuffle_deterministically": {"executed_lines": [175, 176, 177, 178, 179], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordGenerator.generate_password": {"executed_lines": [202, 204, 205, 208, 211, 219, 221, 222, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 236, 238, 239, 240, 243, 246, 247, 248, 249, 250, 251, 252, 259, 260, 263, 264, 268, 270, 271, 272, 273], "summary": {"covered_lines": 39, "num_statements": 41, "percent_covered": 95.1219512195122, "percent_covered_display": "95", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [212, 215], "excluded_lines": []}, "PasswordGenerator._enforce_complexity": {"executed_lines": [291, 292, 293, 294, 295, 297, 298, 299, 300, 301, 303, 306, 307, 308, 309, 311, 316, 317, 318, 319, 322, 323, 325, 332, 333, 334, 335, 336, 337, 339, 340, 341, 342, 343, 344, 346, 347, 348, 349, 350, 351, 353, 354, 355, 356, 357, 358, 361, 362, 363, 364, 366, 367, 369, 370, 371, 372, 376, 377, 378, 379, 380, 381, 382, 383, 384, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 404, 405, 406, 411, 414, 415, 420, 421, 422, 423, 424, 428], "summary": {"covered_lines": 92, "num_statements": 98, "percent_covered": 93.87755102040816, "percent_covered_display": "94", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [368, 385, 430, 431, 432, 433], "excluded_lines": []}, "PasswordGenerator._enforce_complexity.get_dk_value": {"executed_lines": [327, 328, 329], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "derive_ssh_key": {"executed_lines": [438], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "derive_ssh_key_pair": {"executed_lines": [444, 445, 446, 448, 449, 455, 456, 461], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "derive_seed_phrase": {"executed_lines": [466], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "derive_pgp_key": {"executed_lines": [480, 481, 482, 490, 497, 498, 499, 500, 501, 502, 504, 505, 507, 509, 510, 512, 516, 524, 525, 526, 527, 528, 529, 530, 531, 532, 534, 535, 536, 538, 539, 542, 543, 544, 545, 548, 550, 551, 552, 554, 555, 556, 557, 558, 559, 571], "summary": {"covered_lines": 44, "num_statements": 44, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [516]}, "derive_pgp_key.DRNG.__init__": {"executed_lines": [513, 514], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "derive_pgp_key.DRNG.__call__": {"executed_lines": [517, 518, 519, 520, 521, 522], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [517, 518, 519, 520, 521, 522]}, "": {"executed_lines": [3, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 47, 49, 55, 58, 61, 62, 63, 76, 77, 78, 79, 80, 81, 82, 83, 86, 87, 95, 129, 148, 154, 172, 181, 275, 436, 441, 464, 469], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [39, 40, 41, 42, 43, 45]}}, "classes": {"PasswordPolicy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordGenerator": {"executed_lines": [110, 111, 112, 113, 114, 116, 117, 119, 123, 131, 132, 134, 141, 142, 144, 145, 146, 150, 151, 152, 163, 164, 165, 166, 167, 168, 169, 170, 175, 176, 177, 178, 179, 202, 204, 205, 208, 211, 219, 221, 222, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 236, 238, 239, 240, 243, 246, 247, 248, 249, 250, 251, 252, 259, 260, 263, 264, 268, 270, 271, 272, 273, 291, 292, 293, 294, 295, 297, 298, 299, 300, 301, 303, 306, 307, 308, 309, 311, 316, 317, 318, 319, 322, 323, 325, 327, 328, 329, 332, 333, 334, 335, 336, 337, 339, 340, 341, 342, 343, 344, 346, 347, 348, 349, 350, 351, 353, 354, 355, 356, 357, 358, 361, 362, 363, 364, 366, 367, 369, 370, 371, 372, 376, 377, 378, 379, 380, 381, 382, 383, 384, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 404, 405, 406, 411, 414, 415, 420, 421, 422, 423, 424, 428], "summary": {"covered_lines": 167, "num_statements": 179, "percent_covered": 93.29608938547486, "percent_covered_display": "93", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [124, 125, 126, 127, 212, 215, 368, 385, 430, 431, 432, 433], "excluded_lines": []}, "derive_pgp_key.DRNG": {"executed_lines": [513, 514, 517, 518, 519, 520, 521, 522], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [517, 518, 519, 520, 521, 522]}, "": {"executed_lines": [3, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 47, 49, 55, 58, 61, 62, 63, 76, 77, 78, 79, 80, 81, 82, 83, 86, 87, 95, 129, 148, 154, 172, 181, 275, 436, 438, 441, 444, 445, 446, 448, 449, 455, 456, 461, 464, 466, 469, 480, 481, 482, 490, 497, 498, 499, 500, 501, 502, 504, 505, 507, 509, 510, 512, 516, 524, 525, 526, 527, 528, 529, 530, 531, 532, 534, 535, 536, 538, 539, 542, 543, 544, 545, 548, 550, 551, 552, 554, 555, 556, 557, 558, 559, 571], "summary": {"covered_lines": 96, "num_statements": 96, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 7}, "missing_lines": [], "excluded_lines": [39, 40, 41, 42, 43, 45, 516]}}}, "src/seedpass/core/portable_backup.py": {"executed_lines": [2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 22, 23, 24, 26, 28, 29, 32, 33, 35, 36, 39, 42, 45, 62, 63, 64, 65, 66, 68, 69, 71, 72, 77, 78, 79, 80, 81, 83, 84, 85, 87, 89, 99, 100, 101, 102, 104, 121, 124, 132, 133, 136, 137, 140, 141, 143, 144, 149, 150, 151, 152, 153, 154, 158, 160, 161, 162, 164, 165], "summary": {"covered_lines": 71, "num_statements": 84, "percent_covered": 84.52380952380952, "percent_covered_display": "85", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [105, 106, 107, 108, 109, 110, 111, 117, 118, 119, 134, 138, 156], "excluded_lines": [], "functions": {"_derive_export_key": {"executed_lines": [42], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "export_backup": {"executed_lines": [62, 63, 64, 65, 66, 68, 69, 71, 72, 77, 78, 79, 80, 81, 83, 84, 85, 87, 89, 99, 100, 101, 102, 104, 121], "summary": {"covered_lines": 25, "num_statements": 35, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [105, 106, 107, 108, 109, 110, 111, 117, 118, 119], "excluded_lines": []}, "import_backup": {"executed_lines": [132, 133, 136, 137, 140, 141, 143, 144, 149, 150, 151, 152, 153, 154, 158, 160, 161, 162, 164, 165], "summary": {"covered_lines": 20, "num_statements": 23, "percent_covered": 86.95652173913044, "percent_covered_display": "87", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [134, 138, 156], "excluded_lines": []}, "": {"executed_lines": [2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 22, 23, 24, 26, 28, 29, 32, 33, 35, 36, 39, 45, 124], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"PortableMode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 22, 23, 24, 26, 28, 29, 32, 33, 35, 36, 39, 42, 45, 62, 63, 64, 65, 66, 68, 69, 71, 72, 77, 78, 79, 80, 81, 83, 84, 85, 87, 89, 99, 100, 101, 102, 104, 121, 124, 132, 133, 136, 137, 140, 141, 143, 144, 149, 150, 151, 152, 153, 154, 158, 160, 161, 162, 164, 165], "summary": {"covered_lines": 71, "num_statements": 84, "percent_covered": 84.52380952380952, "percent_covered_display": "85", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [105, 106, 107, 108, 109, 110, 111, 117, 118, 119, 134, 138, 156], "excluded_lines": []}}}, "src/seedpass/core/profile_service.py": {"executed_lines": [1, 3, 4, 6, 8, 10, 12, 17, 18, 20, 21, 23, 25, 26, 27, 28, 29, 30, 35, 37, 38, 42, 43, 44, 45, 46, 48, 49, 58, 59, 63, 68, 69, 70, 71, 73, 74, 82, 95, 105], "summary": {"covered_lines": 38, "num_statements": 51, "percent_covered": 74.50980392156863, "percent_covered_display": "75", "missing_lines": 13, "excluded_lines": 7}, "missing_lines": [39, 40, 50, 56, 66, 85, 87, 88, 89, 98, 99, 100, 103], "excluded_lines": [12, 13, 14, 106, 107, 108, 109], "functions": {"ProfileService.__init__": {"executed_lines": [21], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileService.handle_switch_fingerprint": {"executed_lines": [25, 26, 27, 28, 29, 30, 35, 37, 38, 42, 43, 44, 45, 46, 48, 49, 58, 59, 63, 68, 69, 70, 71, 73, 74, 82, 95, 105], "summary": {"covered_lines": 28, "num_statements": 41, "percent_covered": 68.29268292682927, "percent_covered_display": "68", "missing_lines": 13, "excluded_lines": 4}, "missing_lines": [39, 40, 50, 56, 66, 85, 87, 88, 89, 98, 99, 100, 103], "excluded_lines": [106, 107, 108, 109]}, "": {"executed_lines": [1, 3, 4, 6, 8, 10, 12, 17, 18, 20, 23], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [12, 13, 14]}}, "classes": {"ProfileService": {"executed_lines": [21, 25, 26, 27, 28, 29, 30, 35, 37, 38, 42, 43, 44, 45, 46, 48, 49, 58, 59, 63, 68, 69, 70, 71, 73, 74, 82, 95, 105], "summary": {"covered_lines": 29, "num_statements": 42, "percent_covered": 69.04761904761905, "percent_covered_display": "69", "missing_lines": 13, "excluded_lines": 4}, "missing_lines": [39, 40, 50, 56, 66, 85, 87, 88, 89, 98, 99, 100, 103], "excluded_lines": [106, 107, 108, 109]}, "": {"executed_lines": [1, 3, 4, 6, 8, 10, 12, 17, 18, 20, 23], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [12, 13, 14]}}}, "src/seedpass/core/pubsub.py": {"executed_lines": [1, 2, 5, 6, 8, 9, 11, 13, 15, 17, 18, 20, 22, 23, 27], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"PubSub.__init__": {"executed_lines": [9], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PubSub.subscribe": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PubSub.unsubscribe": {"executed_lines": [17, 18], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PubSub.publish": {"executed_lines": [22, 23], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 8, 11, 15, 20, 27], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"PubSub": {"executed_lines": [9, 13, 17, 18, 22, 23], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 8, 11, 15, 20, 27], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/seedqr.py": {"executed_lines": [1, 3, 5, 6, 9, 11, 12, 13, 14], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"encode_seedqr": {"executed_lines": [11, 12, 13, 14], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 9], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 6, 9, 11, 12, 13, 14], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/state_manager.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 12, 13, 15, 17, 18, 19, 21, 22, 23, 31, 32, 33, 34, 43, 44, 47, 48, 49, 50, 51, 52, 53, 55, 56, 57, 58, 59, 60, 61, 63, 64, 65, 67, 68, 69, 70, 73, 74, 76, 77, 78, 79, 81, 82, 83, 85, 86, 87, 88, 90, 92, 93, 94], "summary": {"covered_lines": 59, "num_statements": 65, "percent_covered": 90.76923076923077, "percent_covered_display": "91", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [35, 45, 46, 80, 89, 91], "excluded_lines": [], "functions": {"StateManager.__init__": {"executed_lines": [18, 19], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "StateManager._load": {"executed_lines": [22, 23, 31, 32, 33, 34, 43, 44, 47, 48, 49, 50, 51, 52, 53], "summary": {"covered_lines": 15, "num_statements": 18, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [35, 45, 46], "excluded_lines": []}, "StateManager._save": {"executed_lines": [56, 57, 58, 59, 60, 61], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "StateManager.state": {"executed_lines": [65], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "StateManager.update_state": {"executed_lines": [68, 69, 70], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "StateManager.list_relays": {"executed_lines": [74], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "StateManager.add_relay": {"executed_lines": [77, 78, 79, 81, 82, 83], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [80], "excluded_lines": []}, "StateManager.remove_relay": {"executed_lines": [86, 87, 88, 90, 92, 93, 94], "summary": {"covered_lines": 7, "num_statements": 9, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [89, 91], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 12, 13, 15, 17, 21, 55, 63, 64, 67, 73, 76, 85], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"StateManager": {"executed_lines": [18, 19, 22, 23, 31, 32, 33, 34, 43, 44, 47, 48, 49, 50, 51, 52, 53, 56, 57, 58, 59, 60, 61, 65, 68, 69, 70, 74, 77, 78, 79, 81, 82, 83, 86, 87, 88, 90, 92, 93, 94], "summary": {"covered_lines": 41, "num_statements": 47, "percent_covered": 87.23404255319149, "percent_covered_display": "87", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [35, 45, 46, 80, 89, 91], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 12, 13, 15, 17, 21, 55, 63, 64, 67, 73, 76, 85], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/stats_manager.py": {"executed_lines": [1, 3, 6, 7, 9, 10, 12, 18, 20], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [14, 15, 16], "excluded_lines": [], "functions": {"StatsManager.__init__": {"executed_lines": [10], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "StatsManager.display_stats_once": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [14, 15, 16], "excluded_lines": []}, "StatsManager.reset": {"executed_lines": [20], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 9, 12, 18], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"StatsManager": {"executed_lines": [10, 20], "summary": {"covered_lines": 2, "num_statements": 5, "percent_covered": 40.0, "percent_covered_display": "40", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [14, 15, 16], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 9, 12, 18], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/totp.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 20, 22, 25, 26, 28, 29, 31, 33, 34, 38, 39, 40, 41, 42, 44, 45, 47, 48, 50, 51, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 65, 66, 70, 71, 73, 74, 76, 77, 78, 80, 81, 83, 84, 85, 86, 94, 95, 97, 98, 100, 101, 102, 103], "summary": {"covered_lines": 64, "num_statements": 71, "percent_covered": 90.14084507042253, "percent_covered_display": "90", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [87, 88, 89, 90, 91, 92, 93], "excluded_lines": [], "functions": {"random_totp_secret": {"executed_lines": [22], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TotpManager.derive_secret": {"executed_lines": [31], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TotpManager.current_code": {"executed_lines": [38, 39, 40, 41, 42], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TotpManager.current_code_from_secret": {"executed_lines": [47, 48], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TotpManager.parse_otpauth": {"executed_lines": [53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TotpManager.make_otpauth_uri": {"executed_lines": [70, 71], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TotpManager.time_remaining": {"executed_lines": [76, 77, 78], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TotpManager.print_progress_bar": {"executed_lines": [83, 84, 85, 86, 94, 95], "summary": {"covered_lines": 6, "num_statements": 13, "percent_covered": 46.15384615384615, "percent_covered_display": "46", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [87, 88, 89, 90, 91, 92, 93], "excluded_lines": []}, "TotpManager.print_qr_code": {"executed_lines": [100, 101, 102, 103], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 20, 25, 26, 28, 29, 33, 34, 44, 45, 50, 51, 65, 66, 73, 74, 80, 81, 97, 98], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"TotpManager": {"executed_lines": [31, 38, 39, 40, 41, 42, 47, 48, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 70, 71, 76, 77, 78, 83, 84, 85, 86, 94, 95, 100, 101, 102, 103], "summary": {"covered_lines": 34, "num_statements": 41, "percent_covered": 82.92682926829268, "percent_covered_display": "83", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [87, 88, 89, 90, 91, 92, 93], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 20, 22, 25, 26, 28, 29, 33, 34, 44, 45, 50, 51, 65, 66, 73, 74, 80, 81, 97, 98], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/vault.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 17, 18, 21, 22, 24, 25, 27, 32, 33, 34, 35, 36, 38, 40, 42, 43, 48, 63, 64, 65, 66, 67, 68, 69, 74, 75, 77, 80, 81, 82, 83, 84, 86, 87, 88, 93, 94, 95, 98, 99, 102, 103, 110, 111, 114, 117, 118, 124, 127, 128, 129, 130, 136, 142, 143, 144, 145, 146, 147, 152, 155, 156, 157, 160, 161, 164, 165, 168, 169, 172, 173, 174, 175, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 191, 192, 194, 196, 197, 198, 201, 203, 204, 205, 206, 209, 232, 235, 236, 237, 239, 241, 245, 247, 249, 264, 267, 270, 271, 272, 275, 277, 279, 281], "summary": {"covered_lines": 119, "num_statements": 140, "percent_covered": 85.0, "percent_covered_display": "85", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [96, 97, 100, 149, 163, 210, 211, 212, 213, 216, 217, 218, 219, 220, 221, 224, 225, 226, 227, 229, 230], "excluded_lines": [], "functions": {"Vault.__init__": {"executed_lines": [32, 33, 34, 35, 36], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Vault.set_encryption_manager": {"executed_lines": [40], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Vault._hkdf_kdf": {"executed_lines": [43], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Vault.load_index": {"executed_lines": [63, 64, 65, 66, 67, 68, 69, 74, 75, 77, 80, 81, 82, 83, 84, 86, 87, 88, 93, 94, 95, 98, 99, 102, 103, 110, 111, 114, 117, 118, 124, 127, 128, 129, 130, 136, 142, 143, 144, 145, 146, 147, 152, 155, 156, 157, 160, 161, 164, 165, 168, 169, 172, 173, 174, 175, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 191, 192, 194, 196, 197, 198, 201, 203, 204, 205, 206, 209, 232, 235, 236, 237], "summary": {"covered_lines": 82, "num_statements": 103, "percent_covered": 79.6116504854369, "percent_covered_display": "80", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [96, 97, 100, 149, 163, 210, 211, 212, 213, 216, 217, 218, 219, 220, 221, 224, 225, 226, 227, 229, 230], "excluded_lines": []}, "Vault.save_index": {"executed_lines": [241], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Vault.get_encrypted_index": {"executed_lines": [247], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Vault.decrypt_and_save_index_from_nostr": {"executed_lines": [264, 267, 270, 271, 272], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Vault.load_config": {"executed_lines": [277], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Vault.save_config": {"executed_lines": [281], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 17, 18, 21, 22, 24, 25, 27, 38, 42, 48, 239, 245, 249, 275, 279], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"Vault": {"executed_lines": [32, 33, 34, 35, 36, 40, 43, 63, 64, 65, 66, 67, 68, 69, 74, 75, 77, 80, 81, 82, 83, 84, 86, 87, 88, 93, 94, 95, 98, 99, 102, 103, 110, 111, 114, 117, 118, 124, 127, 128, 129, 130, 136, 142, 143, 144, 145, 146, 147, 152, 155, 156, 157, 160, 161, 164, 165, 168, 169, 172, 173, 174, 175, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 191, 192, 194, 196, 197, 198, 201, 203, 204, 205, 206, 209, 232, 235, 236, 237, 241, 247, 264, 267, 270, 271, 272, 277, 281], "summary": {"covered_lines": 98, "num_statements": 119, "percent_covered": 82.3529411764706, "percent_covered_display": "82", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [96, 97, 100, 149, 163, 210, 211, 212, 213, 216, 217, 218, 219, 220, 221, 224, 225, 226, 227, 229, 230], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 17, 18, 21, 22, 24, 25, 27, 38, 42, 48, 239, 245, 249, 275, 279], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/errors.py": {"executed_lines": [1, 3, 6, 7, 9, 10, 13], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"VaultLockedError.__init__": {"executed_lines": [10], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 9, 13], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"VaultLockedError": {"executed_lines": [10], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 9, 13], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass_gui/__init__.py": {"executed_lines": [1, 3, 6, 11], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [8], "excluded_lines": [], "functions": {"main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [8], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 11], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 6, 11], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [8], "excluded_lines": []}}}, "src/seedpass_gui/__main__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1, 3, 4], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1, 3, 4], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1, 3, 4], "excluded_lines": []}}}, "src/seedpass_gui/app.py": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 21, 24, 25, 27, 33, 36, 37, 38, 40, 41, 42, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 60, 66, 67, 68, 71, 72, 74, 81, 84, 85, 86, 87, 88, 89, 90, 91, 93, 94, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 115, 117, 118, 119, 120, 121, 123, 125, 126, 127, 150, 154, 161, 165, 169, 173, 176, 177, 179, 182, 183, 185, 186, 187, 189, 194, 195, 196, 197, 198, 199, 203, 204, 206, 207, 208, 209, 210, 212, 213, 217, 218, 219, 220, 223, 224, 226, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 261, 262, 263, 264, 265, 266, 267, 268, 270, 271, 272, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 289, 290, 292, 293, 294, 295, 296, 297, 298, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 312, 320, 321, 323, 324, 325, 326, 327, 329, 331, 334, 335, 337, 350, 367, 368, 370, 388, 393, 404, 408, 409, 411, 434, 439, 451, 464, 469, 470, 484], "summary": {"covered_lines": 203, "num_statements": 303, "percent_covered": 66.996699669967, "percent_covered_display": "67", "missing_lines": 100, "excluded_lines": 24}, "missing_lines": [128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 151, 152, 155, 156, 157, 158, 159, 162, 163, 166, 167, 170, 171, 190, 191, 192, 200, 338, 339, 340, 341, 344, 345, 346, 347, 348, 351, 352, 353, 354, 355, 364, 371, 372, 373, 375, 380, 381, 382, 384, 385, 386, 389, 390, 391, 394, 395, 398, 399, 400, 401, 402, 405, 412, 413, 414, 416, 417, 418, 419, 420, 422, 423, 424, 425, 426, 427, 428, 429, 430, 432, 435, 436, 437, 440, 441, 442, 443, 444, 448, 449, 452, 453, 454, 455, 456, 457, 461, 466], "excluded_lines": [57, 58, 59, 445, 446, 447, 458, 459, 460, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 484, 485, 486], "functions": {"LockScreenWindow.__init__": {"executed_lines": [33, 36, 37, 38, 40, 41, 42, 46, 47, 48, 49, 50, 51], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "LockScreenWindow.handle_unlock": {"executed_lines": [54, 55, 56, 60, 66, 67, 68], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [57, 58, 59]}, "MainWindow.__init__": {"executed_lines": [81, 84, 85, 86, 87, 88, 89, 90, 91, 93, 94, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 115, 117, 118, 119, 120, 121, 123], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MainWindow.refresh_entries": {"executed_lines": [126, 127], "summary": {"covered_lines": 2, "num_statements": 13, "percent_covered": 15.384615384615385, "percent_covered_display": "15", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139], "excluded_lines": []}, "MainWindow.add_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [151, 152], "excluded_lines": []}, "MainWindow.edit_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [155, 156, 157, 158, 159], "excluded_lines": []}, "MainWindow.search_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [162, 163], "excluded_lines": []}, "MainWindow.manage_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [166, 167], "excluded_lines": []}, "MainWindow.show_totp_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [170, 171], "excluded_lines": []}, "MainWindow.start_vault_sync": {"executed_lines": [176, 179], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MainWindow.start_vault_sync._runner": {"executed_lines": [177], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MainWindow.sync_started": {"executed_lines": [183], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MainWindow.sync_finished": {"executed_lines": [186, 187], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MainWindow.vault_locked": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [190, 191, 192], "excluded_lines": []}, "MainWindow.cleanup": {"executed_lines": [195, 196, 197, 198, 199], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [200], "excluded_lines": []}, "EntryDialog.__init__": {"executed_lines": [207, 208, 209, 210, 212, 213, 217, 218, 219, 220, 223, 224, 226, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "EntryDialog.save": {"executed_lines": [262, 263, 264, 265, 266, 267, 268, 270, 271, 272, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 289, 290, 292, 293, 294, 295, 296, 297, 298, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 312, 320, 321, 323, 324, 325, 326, 327, 329, 331], "summary": {"covered_lines": 51, "num_statements": 51, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SearchDialog.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [338, 339, 340, 341, 344, 345, 346, 347, 348], "excluded_lines": []}, "SearchDialog.do_search": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [351, 352, 353, 354, 355, 364], "excluded_lines": []}, "TotpViewerWindow.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [371, 372, 373, 375, 380, 381, 382, 384, 385, 386], "excluded_lines": []}, "TotpViewerWindow._update_loop": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [389, 390, 391], "excluded_lines": []}, "TotpViewerWindow.refresh_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [394, 395, 398, 399, 400, 401, 402], "excluded_lines": []}, "TotpViewerWindow.cleanup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [405], "excluded_lines": []}, "RelayManagerDialog.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [412, 413, 414, 416, 417, 418, 419, 420, 422, 423, 424, 425, 426, 427, 428, 429, 430, 432], "excluded_lines": []}, "RelayManagerDialog.refresh": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [435, 436, 437], "excluded_lines": []}, "RelayManagerDialog.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 3}, "missing_lines": [440, 441, 442, 443, 444, 448, 449], "excluded_lines": [445, 446, 447]}, "RelayManagerDialog.remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 3}, "missing_lines": [452, 453, 454, 455, 456, 457, 461], "excluded_lines": [458, 459, 460]}, "build": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [466], "excluded_lines": []}, "SeedPassApp.startup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 11}, "missing_lines": [], "excluded_lines": [471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481]}, "main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [485, 486]}, "": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 21, 24, 25, 27, 53, 71, 72, 74, 125, 150, 154, 161, 165, 169, 173, 182, 185, 189, 194, 203, 204, 206, 261, 334, 335, 337, 350, 367, 368, 370, 388, 393, 404, 408, 409, 411, 434, 439, 451, 464, 469, 470, 484], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [470, 484]}}, "classes": {"LockScreenWindow": {"executed_lines": [33, 36, 37, 38, 40, 41, 42, 46, 47, 48, 49, 50, 51, 54, 55, 56, 60, 66, 67, 68], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [57, 58, 59]}, "MainWindow": {"executed_lines": [81, 84, 85, 86, 87, 88, 89, 90, 91, 93, 94, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 115, 117, 118, 119, 120, 121, 123, 126, 127, 176, 177, 179, 183, 186, 187, 195, 196, 197, 198, 199], "summary": {"covered_lines": 44, "num_statements": 72, "percent_covered": 61.111111111111114, "percent_covered_display": "61", "missing_lines": 28, "excluded_lines": 0}, "missing_lines": [128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 151, 152, 155, 156, 157, 158, 159, 162, 163, 166, 167, 170, 171, 190, 191, 192, 200], "excluded_lines": []}, "EntryDialog": {"executed_lines": [207, 208, 209, 210, 212, 213, 217, 218, 219, 220, 223, 224, 226, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 262, 263, 264, 265, 266, 267, 268, 270, 271, 272, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 289, 290, 292, 293, 294, 295, 296, 297, 298, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 312, 320, 321, 323, 324, 325, 326, 327, 329, 331], "summary": {"covered_lines": 93, "num_statements": 93, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SearchDialog": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [338, 339, 340, 341, 344, 345, 346, 347, 348, 351, 352, 353, 354, 355, 364], "excluded_lines": []}, "TotpViewerWindow": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [371, 372, 373, 375, 380, 381, 382, 384, 385, 386, 389, 390, 391, 394, 395, 398, 399, 400, 401, 402, 405], "excluded_lines": []}, "RelayManagerDialog": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 35, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 35, "excluded_lines": 6}, "missing_lines": [412, 413, 414, 416, 417, 418, 419, 420, 422, 423, 424, 425, 426, 427, 428, 429, 430, 432, 435, 436, 437, 440, 441, 442, 443, 444, 448, 449, 452, 453, 454, 455, 456, 457, 461], "excluded_lines": [445, 446, 447, 458, 459, 460]}, "SeedPassApp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 11}, "missing_lines": [], "excluded_lines": [471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481]}, "": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 21, 24, 25, 27, 53, 71, 72, 74, 125, 150, 154, 161, 165, 169, 173, 182, 185, 189, 194, 203, 204, 206, 261, 334, 335, 337, 350, 367, 368, 370, 388, 393, 404, 408, 409, 411, 434, 439, 451, 464, 469, 470, 484], "summary": {"covered_lines": 46, "num_statements": 47, "percent_covered": 97.87234042553192, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 4}, "missing_lines": [466], "excluded_lines": [470, 484, 485, 486]}}}, "src/tests/conftest.py": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 14, 15, 26, 27, 28, 29, 30, 33, 36, 37, 40, 41, 42, 45, 46, 52, 58, 66, 67, 68, 71, 74, 77, 78, 79, 80, 82, 83, 84, 85, 86, 89, 90, 91, 92, 95, 96, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 115, 116, 117, 145, 146, 147, 148, 149, 150, 153, 154, 156, 157, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 172, 174, 175, 176, 178, 181, 182, 183, 185, 186, 187, 188, 189, 191, 194, 195, 196], "summary": {"covered_lines": 103, "num_statements": 105, "percent_covered": 98.0952380952381, "percent_covered_display": "98", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [75, 179], "excluded_lines": [], "functions": {"anyio_backend": {"executed_lines": [37], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "mute_logging": {"executed_lines": [42], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pytest_addoption": {"executed_lines": [46, 52, 58], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pytest_configure": {"executed_lines": [67, 68], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pytest_collection_modifyitems": {"executed_lines": [74, 77, 78, 79, 80, 82, 83, 84, 85, 86], "summary": {"covered_lines": 10, "num_statements": 11, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [75], "excluded_lines": []}, "vault": {"executed_lines": [91, 92], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "password_manager": {"executed_lines": [97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "client": {"executed_lines": [117, 145, 146, 147, 148, 149, 150], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_dummy_nostr_client": {"executed_lines": [156, 157, 159, 191], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_dummy_nostr_client._make": {"executed_lines": [160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 172, 174, 175, 178, 181, 182, 185, 186, 187, 188, 189], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_dummy_nostr_client._make.DummyKeys.private_key_hex": {"executed_lines": [176], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_dummy_nostr_client._make.DummyKeys.public_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [179], "excluded_lines": []}, "make_dummy_nostr_client._make.DummyKeyManager.__init__": {"executed_lines": [183], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "dummy_nostr_client": {"executed_lines": [196], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 14, 15, 26, 27, 28, 29, 30, 33, 36, 40, 41, 45, 66, 71, 89, 90, 95, 96, 115, 116, 153, 154, 194, 195], "summary": {"covered_lines": 34, "num_statements": 34, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"make_dummy_nostr_client._make.DummyKeys": {"executed_lines": [176], "summary": {"covered_lines": 1, "num_statements": 2, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [179], "excluded_lines": []}, "make_dummy_nostr_client._make.DummyKeyManager": {"executed_lines": [183], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 14, 15, 26, 27, 28, 29, 30, 33, 36, 37, 40, 41, 42, 45, 46, 52, 58, 66, 67, 68, 71, 74, 77, 78, 79, 80, 82, 83, 84, 85, 86, 89, 90, 91, 92, 95, 96, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 115, 116, 117, 145, 146, 147, 148, 149, 150, 153, 154, 156, 157, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 172, 174, 175, 178, 181, 182, 185, 186, 187, 188, 189, 191, 194, 195, 196], "summary": {"covered_lines": 101, "num_statements": 102, "percent_covered": 99.01960784313725, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [75], "excluded_lines": []}}}, "src/tests/helpers.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 11, 12, 18, 22, 25, 31, 32, 33, 34, 36, 37, 38, 39, 42, 43, 44, 45, 46, 47, 49, 50, 53, 54, 55, 56, 57, 59, 60, 63, 64, 65, 66, 71, 72, 74, 76, 77, 79, 80, 83, 84, 85, 86, 88, 89, 90, 92, 93, 96, 97, 98, 101, 102, 103, 104, 105, 106, 107, 109, 110, 112, 113, 114, 119, 121, 122, 123, 125, 126, 127, 128, 130, 131, 132, 134, 135, 136, 139, 140, 141, 143, 144, 145, 148, 149, 150, 152, 153, 155, 156, 157, 160, 161, 162, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 177, 180, 181, 183, 186, 187, 188, 189, 190, 191, 192, 193, 194, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 226, 227, 228, 230, 231, 233], "summary": {"covered_lines": 156, "num_statements": 167, "percent_covered": 93.41317365269461, "percent_covered_display": "93", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [67, 68, 70, 94, 115, 116, 118, 178, 184, 195, 196], "excluded_lines": [], "functions": {"create_vault": {"executed_lines": [31, 32, 33, 34, 36, 37, 38, 39], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEvent.__init__": {"executed_lines": [44, 45, 46, 47], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEvent.content": {"executed_lines": [50], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyUnsignedEvent.__init__": {"executed_lines": [55, 56, 57], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyUnsignedEvent.sign_with_keys": {"executed_lines": [60], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyBuilder.__init__": {"executed_lines": [65, 66, 71, 72], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [67, 68, 70], "excluded_lines": []}, "DummyBuilder.tags": {"executed_lines": [76, 77], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyBuilder.build": {"executed_lines": [80], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyTag.identifier": {"executed_lines": [86], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyTag.event": {"executed_lines": [90], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyTag.alt": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [94], "excluded_lines": []}, "DummyTag.expiration": {"executed_lines": [98], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyFilter.__init__": {"executed_lines": [103, 104, 105, 106, 107], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyFilter.author": {"executed_lines": [110], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyFilter.kind": {"executed_lines": [113, 114, 119], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [115, 116, 118], "excluded_lines": []}, "DummyFilter.identifier": {"executed_lines": [122, 123], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyFilter.id": {"executed_lines": [126, 127, 128], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyFilter.limit": {"executed_lines": [131, 132], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyFilter.since": {"executed_lines": [135, 136], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyTimestamp.__init__": {"executed_lines": [141], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyTimestamp.from_secs": {"executed_lines": [145], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEventId.__init__": {"executed_lines": [150], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEventId.to_hex": {"executed_lines": [153], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEventId.parse": {"executed_lines": [157], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummySendResult.__init__": {"executed_lines": [162], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyRelayClient.__init__": {"executed_lines": [167, 168, 169, 170, 171, 172], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyRelayClient.add_relays": {"executed_lines": [175], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyRelayClient.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [178], "excluded_lines": []}, "DummyRelayClient.connect": {"executed_lines": [181], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyRelayClient.disconnect": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [184], "excluded_lines": []}, "DummyRelayClient.send_event": {"executed_lines": [187, 188, 189, 190, 191, 192, 193, 194, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207], "summary": {"covered_lines": 19, "num_statements": 21, "percent_covered": 90.47619047619048, "percent_covered_display": "90", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [195, 196], "excluded_lines": []}, "DummyRelayClient.fetch_events": {"executed_lines": [210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 226, 227, 230, 233], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyRelayClient.fetch_events.Result.__init__": {"executed_lines": [228], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyRelayClient.fetch_events.Result.to_vec": {"executed_lines": [231], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 11, 12, 18, 22, 25, 42, 43, 49, 53, 54, 59, 63, 64, 74, 79, 83, 84, 85, 88, 89, 92, 93, 96, 97, 101, 102, 109, 112, 121, 125, 130, 134, 139, 140, 143, 144, 148, 149, 152, 155, 156, 160, 161, 165, 166, 174, 177, 180, 183, 186, 209], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEvent": {"executed_lines": [44, 45, 46, 47, 50], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyUnsignedEvent": {"executed_lines": [55, 56, 57, 60], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyBuilder": {"executed_lines": [65, 66, 71, 72, 76, 77, 80], "summary": {"covered_lines": 7, "num_statements": 10, "percent_covered": 70.0, "percent_covered_display": "70", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [67, 68, 70], "excluded_lines": []}, "DummyTag": {"executed_lines": [86, 90, 98], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [94], "excluded_lines": []}, "DummyFilter": {"executed_lines": [103, 104, 105, 106, 107, 110, 113, 114, 119, 122, 123, 126, 127, 128, 131, 132, 135, 136], "summary": {"covered_lines": 18, "num_statements": 21, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [115, 116, 118], "excluded_lines": []}, "DummyTimestamp": {"executed_lines": [141, 145], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEventId": {"executed_lines": [150, 153, 157], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummySendResult": {"executed_lines": [162], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyRelayClient": {"executed_lines": [167, 168, 169, 170, 171, 172, 175, 181, 187, 188, 189, 190, 191, 192, 193, 194, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 226, 227, 230, 233], "summary": {"covered_lines": 46, "num_statements": 50, "percent_covered": 92.0, "percent_covered_display": "92", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [178, 184, 195, 196], "excluded_lines": []}, "DummyRelayClient.fetch_events.Result": {"executed_lines": [228, 231], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 11, 12, 18, 22, 25, 31, 32, 33, 34, 36, 37, 38, 39, 42, 43, 49, 53, 54, 59, 63, 64, 74, 79, 83, 84, 85, 88, 89, 92, 93, 96, 97, 101, 102, 109, 112, 121, 125, 130, 134, 139, 140, 143, 144, 148, 149, 152, 155, 156, 160, 161, 165, 166, 174, 177, 180, 183, 186, 209], "summary": {"covered_lines": 65, "num_statements": 65, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_add_new_fingerprint_words.py": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 11, 13, 14, 16, 17, 18, 20, 23, 24, 29, 31, 33, 34, 35], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_add_new_fingerprint_word_entry_exits": {"executed_lines": [9, 10, 11, 13, 14, 16, 20, 23, 24, 29, 31, 33, 34, 35], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_new_fingerprint_word_entry_exits.setup_wrapper": {"executed_lines": [17, 18], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 11, 13, 14, 16, 17, 18, 20, 23, 24, 29, 31, 33, 34, 35], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_add_tags_from_retrieve.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 18, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 41, 43, 44, 46, 48, 49], "summary": {"covered_lines": 37, "num_statements": 37, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakePasswordGenerator.generate_password": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_tags_from_retrieve": {"executed_lines": [22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 41, 43, 44, 46, 48, 49], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 21], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakePasswordGenerator": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 41, 43, 44, 46, 48, 49], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_additional_backup.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 24, 25, 26, 27, 29, 31, 32, 34, 35, 36, 37], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_entry_manager_additional_backup": {"executed_lines": [13, 14, 15, 16, 17, 18, 19, 21, 22, 24, 25, 26, 27, 29, 31, 32, 34, 35, 36, 37], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 12], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 24, 25, 26, 27, 29, 31, 32, 34, 35, 36, 37], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_ai_tui_agent_harness.py": {"executed_lines": [1, 3, 4, 5, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 24, 25, 26, 28, 29, 31, 33, 34, 35, 36, 37, 40, 41, 43, 44, 46, 47, 49, 50, 51, 52, 55, 56, 57, 58, 59, 61, 62, 64, 65, 67, 68, 69, 70, 71, 74, 75, 76, 77, 78, 80, 81, 83, 84, 86, 87, 88, 89, 94, 95, 96, 97, 105, 107, 108, 109, 110, 112, 113, 115, 118, 119, 120, 121, 124, 125, 126, 129, 132, 135, 136, 137, 140, 141, 142, 143, 144, 146, 147, 148, 149, 150, 152, 153, 154, 156, 159, 160, 161, 162, 163, 166, 167, 168, 169, 171, 172, 174, 175, 177, 178, 180, 183], "summary": {"covered_lines": 118, "num_statements": 123, "percent_covered": 95.9349593495935, "percent_covered_display": "96", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [116, 127, 130, 133, 157], "excluded_lines": [], "functions": {"_load_harness_module": {"executed_lines": [11, 12, 13, 14, 15, 16, 17, 18], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_run_step_records_passed_result": {"executed_lines": [25, 26, 28, 31, 33, 34, 35, 36, 37], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_run_step_records_passed_result._ok": {"executed_lines": [29], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_run_step_records_failed_result_and_reraises": {"executed_lines": [41, 43, 46, 47, 49, 50, 51, 52], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_run_step_records_failed_result_and_reraises._boom": {"executed_lines": [44], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_waits_when_choice_omitted": {"executed_lines": [56, 57, 61, 64, 67, 68, 69, 70, 71], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_waits_when_choice_omitted.Runner.__init__": {"executed_lines": [58, 59], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_waits_when_choice_omitted.Runner.sendline": {"executed_lines": [62], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_waits_when_choice_omitted.Runner.wait_for": {"executed_lines": [65], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_sends_choice_when_provided": {"executed_lines": [75, 76, 80, 83, 86, 87, 88, 89], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_sends_choice_when_provided.Runner.__init__": {"executed_lines": [77, 78], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_sends_choice_when_provided.Runner.sendline": {"executed_lines": [81], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_sends_choice_when_provided.Runner.expect_and_send": {"executed_lines": [84], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password": {"executed_lines": [95, 96, 107, 112, 115, 118, 119, 120, 121], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password.Runner.__init__": {"executed_lines": [97, 105], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password.Runner.try_wait_for": {"executed_lines": [108, 109, 110], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password.Runner.sendline": {"executed_lines": [113], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password.Runner.pump": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [116], "excluded_lines": []}, "test_complete_onboarding_times_out_without_expected_prompts": {"executed_lines": [125, 126, 129, 132, 135, 136, 137], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_times_out_without_expected_prompts.Runner.try_wait_for": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [127], "excluded_lines": []}, "test_complete_onboarding_times_out_without_expected_prompts.Runner.sendline": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [130], "excluded_lines": []}, "test_complete_onboarding_times_out_without_expected_prompts.Runner.pump": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [133], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns": {"executed_lines": [141, 142, 146, 152, 156, 159, 160, 161, 162, 163], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns.Runner.__init__": {"executed_lines": [143, 144], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns.Runner.wait_for": {"executed_lines": [147, 148, 149, 150], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns.Runner.expect_and_send": {"executed_lines": [153, 154], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns.Runner.pump": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [157], "excluded_lines": []}, "test_drain_to_main_menu_times_out_when_no_prompt_progress": {"executed_lines": [167, 168, 171, 174, 177, 178, 180, 183], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_times_out_when_no_prompt_progress.Runner.wait_for": {"executed_lines": [169], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_times_out_when_no_prompt_progress.Runner.expect_and_send": {"executed_lines": [172], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_times_out_when_no_prompt_progress.Runner.pump": {"executed_lines": [175], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 10, 21, 24, 40, 55, 74, 94, 124, 140, 166], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_add_entry_menu_open_waits_when_choice_omitted.Runner": {"executed_lines": [58, 59, 62, 65], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_sends_choice_when_provided.Runner": {"executed_lines": [77, 78, 81, 84], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password.Runner": {"executed_lines": [97, 105, 108, 109, 110, 113], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [116], "excluded_lines": []}, "test_complete_onboarding_times_out_without_expected_prompts.Runner": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [127, 130, 133], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns.Runner": {"executed_lines": [143, 144, 147, 148, 149, 150, 153, 154], "summary": {"covered_lines": 8, "num_statements": 9, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [157], "excluded_lines": []}, "test_drain_to_main_menu_times_out_when_no_prompt_progress.Runner": {"executed_lines": [169, 172, 175], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 24, 25, 26, 28, 29, 31, 33, 34, 35, 36, 37, 40, 41, 43, 44, 46, 47, 49, 50, 51, 52, 55, 56, 57, 61, 64, 67, 68, 69, 70, 71, 74, 75, 76, 80, 83, 86, 87, 88, 89, 94, 95, 96, 107, 112, 115, 118, 119, 120, 121, 124, 125, 126, 129, 132, 135, 136, 137, 140, 141, 142, 146, 152, 156, 159, 160, 161, 162, 163, 166, 167, 168, 171, 174, 177, 178, 180, 183], "summary": {"covered_lines": 93, "num_statements": 93, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_api.py": {"executed_lines": [1, 2, 4, 5, 7, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 36, 39, 40, 41, 42, 47, 48, 49, 50, 53, 54, 55, 56, 60, 61, 62, 63, 66, 67, 68, 69, 73, 74, 75, 76, 79, 80, 81, 82, 86, 87, 88, 89, 92, 93, 94, 95, 97, 102, 103, 105, 110, 111, 113, 114, 115, 117, 118, 119, 122, 123, 124, 125, 127, 128, 130, 131, 132, 137, 138, 139, 140, 143, 144, 145, 146, 147, 150, 151, 156, 157, 158, 161, 162, 163, 164, 165, 166, 167, 172, 173, 174, 175, 178, 179, 180, 181, 182, 187, 190, 191, 192, 194, 196, 197, 198, 199, 201, 203, 207, 208, 209, 210, 211, 212, 215, 216, 233, 234, 235, 236, 237, 238, 239, 240], "summary": {"covered_lines": 137, "num_statements": 137, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_token_hashed": {"executed_lines": [14, 15, 16], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cors_and_auth": {"executed_lines": [21, 22, 23, 24, 25], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_invalid_token": {"executed_lines": [30, 31, 36], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_entry_by_id": {"executed_lines": [41, 42, 47, 48, 49, 50], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_config_value": {"executed_lines": [55, 56, 60, 61, 62, 63], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_list_fingerprint": {"executed_lines": [68, 69, 73, 74, 75, 76], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_nostr_pubkey": {"executed_lines": [81, 82, 86, 87, 88, 89], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_create_modify_archive_entry": {"executed_lines": [94, 95, 97, 102, 103, 105, 110, 111, 113, 114, 115, 117, 118, 119], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_config": {"executed_lines": [124, 125, 127, 130, 131, 132, 137, 138, 139, 140], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_config.set_timeout": {"executed_lines": [128], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_config_quick_unlock": {"executed_lines": [145, 146, 147, 150, 151, 156, 157, 158], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_change_password_route": {"executed_lines": [163, 164, 165, 166, 167, 172, 173, 174, 175], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_config_unknown_key": {"executed_lines": [180, 181, 182, 187], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_shutdown": {"executed_lines": [192, 194, 196, 197, 201, 203, 207, 208, 209, 210, 211, 212], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_shutdown.Loop.call_soon": {"executed_lines": [198, 199], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_invalid_token_other_endpoints": {"executed_lines": [234, 235, 236, 237, 238, 239, 240], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 7, 9, 12, 13, 19, 20, 28, 29, 39, 40, 53, 54, 66, 67, 79, 80, 92, 93, 122, 123, 143, 144, 161, 162, 178, 179, 190, 191, 215, 216, 233], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_shutdown.Loop": {"executed_lines": [198, 199], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 7, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 36, 39, 40, 41, 42, 47, 48, 49, 50, 53, 54, 55, 56, 60, 61, 62, 63, 66, 67, 68, 69, 73, 74, 75, 76, 79, 80, 81, 82, 86, 87, 88, 89, 92, 93, 94, 95, 97, 102, 103, 105, 110, 111, 113, 114, 115, 117, 118, 119, 122, 123, 124, 125, 127, 128, 130, 131, 132, 137, 138, 139, 140, 143, 144, 145, 146, 147, 150, 151, 156, 157, 158, 161, 162, 163, 164, 165, 166, 167, 172, 173, 174, 175, 178, 179, 180, 181, 182, 187, 190, 191, 192, 194, 196, 197, 201, 203, 207, 208, 209, 210, 211, 212, 215, 216, 233, 234, 235, 236, 237, 238, 239, 240], "summary": {"covered_lines": 135, "num_statements": 135, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_api_new_endpoints.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 16, 17, 19, 20, 21, 23, 24, 26, 27, 28, 29, 31, 32, 45, 46, 47, 57, 62, 63, 64, 65, 68, 69, 70, 71, 73, 74, 75, 77, 78, 80, 81, 82, 84, 85, 90, 91, 92, 94, 99, 100, 101, 104, 105, 106, 108, 109, 111, 112, 113, 114, 115, 118, 119, 120, 121, 123, 124, 126, 127, 128, 133, 134, 135, 138, 139, 140, 141, 142, 143, 144, 145, 146, 149, 150, 151, 152, 155, 156, 157, 158, 159, 160, 161, 168, 169, 170, 171, 174, 177, 178, 179, 180, 182, 183, 186, 188, 190, 191, 192, 193, 195, 196, 197, 198, 200, 205, 206, 207, 210, 211, 212, 213, 215, 216, 220, 222, 223, 224, 225, 227, 228, 229, 230, 233, 234, 235, 236, 238, 239, 241, 242, 243, 246, 247, 249, 250, 255, 256, 257, 258, 261, 262, 263, 264, 266, 267, 269, 270, 271, 272, 274, 275, 276, 281, 282, 283, 284, 287, 288, 289, 290, 291, 292, 296, 297, 302, 305, 306, 307, 308, 309, 310, 311, 313, 314, 319, 322, 323, 324, 325, 327, 328, 329, 331, 332, 334, 335, 336, 337, 338, 339, 340, 343, 344, 347, 348, 349, 350, 352, 353, 355, 356, 358, 359, 361, 362, 367, 368, 369, 370, 373, 374, 375, 376, 377, 379, 381, 385, 386, 387, 389, 392, 395, 396, 397, 398, 399, 400, 404, 405, 409, 414, 415, 416, 418, 423, 426, 427, 428, 429, 430, 431, 432, 436, 441, 444, 445, 446, 447, 448, 450, 451, 453, 455, 456, 458, 459, 460, 465, 468, 469, 471, 473, 474, 475, 477, 478, 479, 481, 484, 485, 486, 488, 489, 490, 491, 494, 495, 496, 498, 499, 500, 502, 503, 506, 508, 511, 513, 514, 519, 520, 521, 524, 525, 526, 528, 529, 530, 532, 533, 536, 538, 541, 543, 544, 545, 550, 551, 552, 553], "summary": {"covered_lines": 323, "num_statements": 323, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_create_and_modify_totp_entry": {"executed_lines": [16, 17, 19, 23, 26, 27, 28, 29, 31, 32, 45, 46, 47, 57, 62, 63, 64, 65], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_create_and_modify_totp_entry.add_totp": {"executed_lines": [20, 21], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_create_and_modify_totp_entry.modify": {"executed_lines": [24], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_create_and_modify_ssh_entry": {"executed_lines": [70, 71, 73, 77, 80, 81, 82, 84, 85, 90, 91, 92, 94, 99, 100, 101], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_create_and_modify_ssh_entry.add_ssh": {"executed_lines": [74, 75], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_create_and_modify_ssh_entry.modify": {"executed_lines": [78], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_entry_error": {"executed_lines": [106, 108, 111, 112, 113, 114, 115], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_entry_error.modify": {"executed_lines": [109], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_config_secret_mode": {"executed_lines": [120, 121, 123, 126, 127, 128, 133, 134, 135], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_config_secret_mode.set_secret": {"executed_lines": [124], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_totp_export_endpoint": {"executed_lines": [140, 141, 142, 143, 144, 145, 146], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_totp_codes_endpoint": {"executed_lines": [151, 152, 155, 156, 157, 158, 159, 160, 161], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_parent_seed_endpoint_removed": {"executed_lines": [170, 171, 174], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fingerprint_endpoints": {"executed_lines": [179, 180, 182, 183, 186, 188, 190, 191, 192, 193, 195, 196, 197, 198, 200, 205, 206, 207], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_checksum_endpoints": {"executed_lines": [212, 213, 215, 216, 220, 222, 223, 224, 225, 227, 228, 229, 230], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_via_path": {"executed_lines": [235, 236, 238, 241, 242, 243, 246, 247, 249, 250, 255, 256, 257, 258], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_via_path.import_db": {"executed_lines": [239], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_via_upload": {"executed_lines": [263, 264, 266, 269, 270, 271, 272, 274, 275, 276, 281, 282, 283, 284], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_via_upload.import_db": {"executed_lines": [267], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_invalid_extension": {"executed_lines": [289, 290, 291, 292, 296, 297, 302], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_path_traversal_blocked": {"executed_lines": [307, 308, 309, 310, 311, 313, 314, 319], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_lock_endpoint": {"executed_lines": [324, 325, 327, 331, 332, 334, 335, 336, 337, 338, 339, 340, 343, 344], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_lock_endpoint.lock": {"executed_lines": [328, 329], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_secret_mode_endpoint": {"executed_lines": [349, 350, 352, 355, 358, 359, 361, 362, 367, 368, 369, 370], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_secret_mode_endpoint.set_secret": {"executed_lines": [353], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_secret_mode_endpoint.set_delay": {"executed_lines": [356], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_export_endpoint": {"executed_lines": [375, 376, 377, 379, 381, 385, 386, 387, 389, 392], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_backup_parent_seed_endpoint": {"executed_lines": [397, 398, 399, 400, 404, 405, 409, 414, 415, 416, 418, 423], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_backup_parent_seed_path_traversal_blocked": {"executed_lines": [428, 429, 430, 431, 432, 436, 441], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_relay_management_endpoints": {"executed_lines": [446, 447, 448, 450, 453, 455, 458, 459, 460, 465, 468, 469, 471, 473, 474, 475, 477, 478, 479, 481, 484, 485, 486, 488, 489, 490, 491], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_relay_management_endpoints.load_config": {"executed_lines": [451], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_relay_management_endpoints.set_relays": {"executed_lines": [456], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_no_special_chars": {"executed_lines": [496, 498, 499, 502, 503, 508, 511, 513, 514, 519, 520, 521], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_no_special_chars.DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [500], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_no_special_chars.DummyBIP85.derive_entropy": {"executed_lines": [506], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_allowed_chars": {"executed_lines": [526, 528, 529, 532, 533, 538, 541, 543, 544, 545, 550, 551, 552, 553], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_allowed_chars.DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [530], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_allowed_chars.DummyBIP85.derive_entropy": {"executed_lines": [536], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 68, 69, 104, 105, 118, 119, 138, 139, 149, 150, 168, 169, 177, 178, 210, 211, 233, 234, 261, 262, 287, 288, 305, 306, 322, 323, 347, 348, 373, 374, 395, 396, 426, 427, 444, 445, 494, 495, 524, 525], "summary": {"covered_lines": 52, "num_statements": 52, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_generate_password_no_special_chars.DummyEnc": {"executed_lines": [500], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_no_special_chars.DummyBIP85": {"executed_lines": [506], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_allowed_chars.DummyEnc": {"executed_lines": [530], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_allowed_chars.DummyBIP85": {"executed_lines": [536], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 16, 17, 19, 20, 21, 23, 24, 26, 27, 28, 29, 31, 32, 45, 46, 47, 57, 62, 63, 64, 65, 68, 69, 70, 71, 73, 74, 75, 77, 78, 80, 81, 82, 84, 85, 90, 91, 92, 94, 99, 100, 101, 104, 105, 106, 108, 109, 111, 112, 113, 114, 115, 118, 119, 120, 121, 123, 124, 126, 127, 128, 133, 134, 135, 138, 139, 140, 141, 142, 143, 144, 145, 146, 149, 150, 151, 152, 155, 156, 157, 158, 159, 160, 161, 168, 169, 170, 171, 174, 177, 178, 179, 180, 182, 183, 186, 188, 190, 191, 192, 193, 195, 196, 197, 198, 200, 205, 206, 207, 210, 211, 212, 213, 215, 216, 220, 222, 223, 224, 225, 227, 228, 229, 230, 233, 234, 235, 236, 238, 239, 241, 242, 243, 246, 247, 249, 250, 255, 256, 257, 258, 261, 262, 263, 264, 266, 267, 269, 270, 271, 272, 274, 275, 276, 281, 282, 283, 284, 287, 288, 289, 290, 291, 292, 296, 297, 302, 305, 306, 307, 308, 309, 310, 311, 313, 314, 319, 322, 323, 324, 325, 327, 328, 329, 331, 332, 334, 335, 336, 337, 338, 339, 340, 343, 344, 347, 348, 349, 350, 352, 353, 355, 356, 358, 359, 361, 362, 367, 368, 369, 370, 373, 374, 375, 376, 377, 379, 381, 385, 386, 387, 389, 392, 395, 396, 397, 398, 399, 400, 404, 405, 409, 414, 415, 416, 418, 423, 426, 427, 428, 429, 430, 431, 432, 436, 441, 444, 445, 446, 447, 448, 450, 451, 453, 455, 456, 458, 459, 460, 465, 468, 469, 471, 473, 474, 475, 477, 478, 479, 481, 484, 485, 486, 488, 489, 490, 491, 494, 495, 496, 498, 499, 502, 503, 508, 511, 513, 514, 519, 520, 521, 524, 525, 526, 528, 529, 532, 533, 538, 541, 543, 544, 545, 550, 551, 552, 553], "summary": {"covered_lines": 319, "num_statements": 319, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_api_notifications.py": {"executed_lines": [1, 2, 3, 4, 7, 8, 9, 10, 11, 12, 13, 16, 17, 21, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 38, 41, 42, 43, 44, 45, 46, 47, 48, 52, 55, 56, 57, 58], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_notifications_endpoint": {"executed_lines": [9, 10, 11, 12, 13, 16, 17, 21], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_notifications_endpoint_clears_queue": {"executed_lines": [26, 27, 28, 29, 32, 33, 34, 35, 38], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_notifications_endpoint_does_not_clear_current": {"executed_lines": [43, 44, 45, 46, 47, 48, 52, 55, 56, 57, 58], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 7, 8, 24, 25, 41, 42], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 7, 8, 9, 10, 11, 12, 13, 16, 17, 21, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 38, 41, 42, 43, 44, 45, 46, 47, 48, 52, 55, 56, 57, 58], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_api_profile_stats.py": {"executed_lines": [1, 4, 5, 6, 7, 8, 10, 11, 12, 13], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_profile_stats_endpoint": {"executed_lines": [6, 7, 8, 10, 11, 12, 13], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 4, 5], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 4, 5, 6, 7, 8, 10, 11, 12, 13], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_api_rate_limit.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 13, 14, 15, 16, 17, 19, 21, 34, 35, 36, 37, 38, 40, 41, 44, 46, 47], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_rate_limit_exceeded": {"executed_lines": [15, 16, 17, 19, 21, 34, 35, 36, 37, 38, 40, 41, 44, 46, 47], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 13, 14], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 13, 14, 15, 16, 17, 19, 21, 34, 35, 36, 37, 38, 40, 41, 44, 46, 47], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_api_reload_relays.py": {"executed_lines": [1, 2, 4, 7, 8, 9, 11, 12, 14, 21, 23, 24, 26, 27, 28, 29], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_reload_relays_logs_errors": {"executed_lines": [8, 11, 14, 21, 23, 24, 26, 27, 28, 29], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_reload_relays_logs_errors.close": {"executed_lines": [9], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_reload_relays_logs_errors.init": {"executed_lines": [12], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 7], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 7, 8, 9, 11, 12, 14, 21, 23, 24, 26, 27, 28, 29], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_archive_from_retrieve.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 45, 46, 48, 50, 53, 55, 56, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 76, 78, 79, 81, 83], "summary": {"covered_lines": 63, "num_statements": 63, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakePasswordGenerator.generate_password": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_archive_entry_from_retrieve": {"executed_lines": [23, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 45, 46, 48, 50], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_restore_entry_from_retrieve": {"executed_lines": [55, 56, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 76, 78, 79, 81, 83], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 17, 18, 22, 53], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakePasswordGenerator": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 17, 18, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 45, 46, 48, 50, 53, 55, 56, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 76, 78, 79, 81, 83], "summary": {"covered_lines": 62, "num_statements": 62, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_archive_nonpassword.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 29, 30, 34, 35, 36, 37, 40, 44, 45, 46, 47], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_entry_mgr": {"executed_lines": [16, 17, 18, 19], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_archive_nonpassword_list_search": {"executed_lines": [23, 24, 25, 26, 27, 29, 30, 34, 35, 36, 37, 40, 44, 45, 46, 47], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 22], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 29, 30, 34, 35, 36, 37, 40, 44, 45, 46, 47], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_archive_restore.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 27, 28, 29, 30, 31, 33, 34, 38, 39, 40, 41, 44, 48, 49, 50, 51, 56, 57, 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 78, 79, 80, 82, 83, 84, 85, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 108, 110, 111, 112, 114, 115, 116, 117, 118, 119, 122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 142, 144, 145, 146, 148, 149, 150, 151, 153, 154, 155, 156, 157, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 180, 181, 184, 185, 186, 187, 190, 191, 192, 193, 194, 195, 198, 199, 200, 201, 202, 203, 204, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 218, 219, 220, 222, 227, 228, 229, 231, 233, 234, 235, 236], "summary": {"covered_lines": 179, "num_statements": 179, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_entry_mgr": {"executed_lines": [21, 22, 23, 24], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_archive_restore_affects_listing_and_search": {"executed_lines": [28, 29, 30, 31, 33, 34, 38, 39, 40, 41, 44, 48, 49, 50, 51], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_view_archived_entries_cli": {"executed_lines": [57, 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 78, 79, 80, 82, 83, 84, 85], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_view_archived_entries_view_only": {"executed_lines": [89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 108, 110, 111, 112, 114, 115, 116, 117, 118, 119], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_view_archived_entries_removed_after_restore": {"executed_lines": [123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 142, 144, 145, 146, 148, 149, 150, 151, 153, 154, 155, 156, 157], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_archived_entries_menu_hides_active": {"executed_lines": [161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 180, 181, 184, 185, 186, 187, 190, 191, 192, 193, 194, 195], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_view_archived_entries_refreshes_after_view_action": {"executed_lines": [199, 200, 201, 202, 203, 204, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 218, 219, 220, 222, 227, 228, 229, 231, 233, 234, 235, 236], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 13, 14, 15, 16, 17, 20, 27, 56, 88, 122, 160, 198], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 27, 28, 29, 30, 31, 33, 34, 38, 39, 40, 41, 44, 48, 49, 50, 51, 56, 57, 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 78, 79, 80, 82, 83, 84, 85, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 108, 110, 111, 112, 114, 115, 116, 117, 118, 119, 122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 142, 144, 145, 146, 148, 149, 150, 151, 153, 154, 155, 156, 157, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 180, 181, 184, 185, 186, 187, 190, 191, 192, 193, 194, 195, 198, 199, 200, 201, 202, 203, 204, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 218, 219, 220, 222, 227, 228, 229, 231, 233, 234, 235, 236], "summary": {"covered_lines": 179, "num_statements": 179, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_atomic_write.py": {"executed_lines": [1, 2, 3, 5, 8, 13, 16, 17, 19, 23, 24, 25, 26, 28, 29, 30], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [9, 10], "excluded_lines": [], "functions": {"_writer": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [9, 10], "excluded_lines": []}, "test_atomic_write_concurrent": {"executed_lines": [16, 17, 19, 23, 24, 25, 26, 28, 29, 30], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 8, 13], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 8, 13, 16, 17, 19, 23, 24, 25, 26, 28, 29, 30], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [9, 10], "excluded_lines": []}}}, "src/tests/test_audit_logger.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 11, 12, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 33, 35, 36, 37, 38, 39, 40, 42, 43, 46, 47, 49, 50, 51, 52, 53, 54, 57, 58, 59, 60, 61, 62, 63, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85], "summary": {"covered_lines": 67, "num_statements": 67, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_audit_logger_records_events": {"executed_lines": [16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 33, 35, 36, 37, 38, 39, 40, 42, 43, 46, 47, 49, 50, 51, 52, 53, 54], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_verify_chain": {"executed_lines": [58, 59, 60, 61, 62, 63, 66, 67, 68, 69], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_audit_log_tamper_evident": {"executed_lines": [73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 11, 12, 15, 57, 72], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 11, 12, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 33, 35, 36, 37, 38, 39, 40, 42, 43, 46, 47, 49, 50, 51, 52, 53, 54, 57, 58, 59, 60, 61, 62, 63, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85], "summary": {"covered_lines": 67, "num_statements": 67, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_auto_sync.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13, 14, 30, 32, 34, 36, 37, 39, 40, 42, 43], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_auto_sync_triggers_post": {"executed_lines": [14, 30, 32, 36, 37, 39, 40, 42, 43], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_auto_sync_triggers_post.fake_post": {"executed_lines": [34], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13, 14, 30, 32, 34, 36, 37, 39, 40, 42, 43], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_background_error_reporting.py": {"executed_lines": [1, 2, 4, 7, 8, 9, 10, 11, 12, 15, 16, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 36, 39, 40, 42, 43, 44, 46, 48, 49, 51, 52, 54, 55, 56], "summary": {"covered_lines": 37, "num_statements": 37, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [8, 9, 10, 11, 12, 15, 16], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_sync_error": {"executed_lines": [20, 22, 25, 26, 28, 29, 31, 32, 34, 35, 36], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_sync_error.failing_sync": {"executed_lines": [23], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_relay_check_error": {"executed_lines": [40, 42, 43, 46, 48, 49, 51, 52, 54, 55, 56], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_relay_check_error.DummyClient.check_relay_health": {"executed_lines": [44], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 7, 19, 39], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_start_background_relay_check_error.DummyClient": {"executed_lines": [44], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 7, 8, 9, 10, 11, 12, 15, 16, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 36, 39, 40, 42, 43, 46, 48, 49, 51, 52, 54, 55, 56], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_background_relay_check.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 13, 14, 15, 16, 17, 18, 23, 24, 26, 29, 30, 31, 32, 33, 34, 36, 37, 39, 40, 41], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_background_relay_check_runs_async": {"executed_lines": [14, 15, 16, 17, 18, 23, 24, 26], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_background_relay_check_warns_when_unhealthy": {"executed_lines": [30, 31, 32, 33, 34, 36, 37, 39, 40, 41], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 13, 29], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 13, 14, 15, 16, 17, 18, 23, 24, 26, 29, 30, 31, 32, 33, 34, 36, 37, 39, 40, 41], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_background_sync_always.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 13, 14, 19, 20, 21, 22, 23, 25, 26, 29, 30, 31, 33, 35, 36, 38, 40, 41, 44, 45, 46, 47, 49, 50, 53, 54, 55, 56, 58, 60, 61, 63, 65, 66], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_switch_fingerprint_triggers_bg_sync": {"executed_lines": [12, 13, 14, 19, 20, 21, 22, 23, 25, 26, 29, 30, 31, 33, 35, 38, 40, 41], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_switch_fingerprint_triggers_bg_sync.fake_bg": {"executed_lines": [36], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_exit_managed_account_triggers_bg_sync": {"executed_lines": [45, 46, 47, 49, 50, 53, 54, 55, 56, 58, 60, 63, 65, 66], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_exit_managed_account_triggers_bg_sync.fake_bg": {"executed_lines": [61], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 44], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 13, 14, 19, 20, 21, 22, 23, 25, 26, 29, 30, 31, 33, 35, 36, 38, 40, 41, 44, 45, 46, 47, 49, 50, 53, 54, 55, 56, 58, 60, 61, 63, 65, 66], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_backup_interval.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 13, 14, 15, 16, 17, 19, 21, 22, 23, 24, 26, 27, 28, 29, 31, 32, 33, 34], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_backup_interval": {"executed_lines": [12, 13, 14, 15, 16, 17, 19, 21, 22, 23, 24, 26, 27, 28, 29, 31, 32, 33, 34], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 11], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 13, 14, 15, 16, 17, 19, 21, 22, 23, 24, 26, 27, 28, 29, 31, 32, 33, 34], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_backup_restore.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 15, 16, 17, 18, 19, 20, 22, 24, 39, 40, 42, 43, 44, 45, 46, 47, 49, 64, 65, 67, 68, 69, 70, 71, 72, 74, 75, 76, 78, 79, 80, 82, 83, 84, 85, 88, 89, 90, 91, 92, 93, 94, 96, 98, 99, 101, 102, 104, 105, 106, 107], "summary": {"covered_lines": 60, "num_statements": 60, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_backup_restore_workflow": {"executed_lines": [16, 17, 18, 19, 20, 22, 24, 39, 40, 42, 43, 44, 45, 46, 47, 49, 64, 65, 67, 68, 69, 70, 71, 72, 74, 75, 76, 78, 79, 80, 82, 83, 84, 85], "summary": {"covered_lines": 34, "num_statements": 34, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_additional_backup_location": {"executed_lines": [89, 90, 91, 92, 93, 94, 96, 98, 99, 101, 102, 104, 105, 106, 107], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 15, 88], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 15, 16, 17, 18, 19, 20, 22, 24, 39, 40, 42, 43, 44, 45, 46, 47, 49, 64, 65, 67, 68, 69, 70, 71, 72, 74, 75, 76, 78, 79, 80, 82, 83, 84, 85, 88, 89, 90, 91, 92, 93, 94, 96, 98, 99, 101, 102, 104, 105, 106, 107], "summary": {"covered_lines": 60, "num_statements": 60, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_backup_restore_startup.py": {"executed_lines": [1, 2, 5, 6, 7, 8, 10, 11, 13, 14, 15, 16, 17, 19, 20, 21, 23, 24, 25, 26, 27, 28, 31, 32, 33, 34, 36, 37, 39, 40, 41, 42, 43, 45, 46, 47, 48, 49, 51, 52, 53, 54, 55, 56], "summary": {"covered_lines": 44, "num_statements": 44, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_cli_flag_restores_before_init": {"executed_lines": [6, 7, 8, 10, 13, 14, 19, 20, 21, 23, 24, 25, 26, 27, 28], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_flag_restores_before_init.fake_restore": {"executed_lines": [11], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_flag_restores_before_init.DummyPM.__init__": {"executed_lines": [15, 16, 17], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_option_restores_before_init": {"executed_lines": [32, 33, 34, 36, 39, 40, 45, 46, 47, 48, 49, 51, 52, 53, 54, 55, 56], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_option_restores_before_init.fake_restore": {"executed_lines": [37], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_option_restores_before_init.DummyPM.__init__": {"executed_lines": [41, 42, 43], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 31], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_cli_flag_restores_before_init.DummyPM": {"executed_lines": [15, 16, 17], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_option_restores_before_init.DummyPM": {"executed_lines": [41, 42, 43], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 7, 8, 10, 11, 13, 14, 19, 20, 21, 23, 24, 25, 26, 27, 28, 31, 32, 33, 34, 36, 37, 39, 40, 45, 46, 47, 48, 49, 51, 52, 53, 54, 55, 56], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_bip85_derivation_path.py": {"executed_lines": [1, 4, 5, 6, 8, 9, 11, 12, 15, 16, 17, 19, 20, 21, 24, 25, 26, 27, 29, 35, 36, 42, 45, 46, 47, 48, 50, 52], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"DummyChild.PrivateKey": {"executed_lines": [6], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyChild.Raw": {"executed_lines": [9], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyChild.ToBytes": {"executed_lines": [12], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyCtx.__init__": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyCtx.DerivePath": {"executed_lines": [20, 21], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_derivation_paths_for_entropy_lengths": {"executed_lines": [25, 26, 27, 29, 35, 36, 42], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_default_word_count_from_entropy_bytes": {"executed_lines": [46, 47, 48, 50, 52], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 4, 5, 8, 11, 15, 16, 19, 24, 45], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyChild": {"executed_lines": [6, 9, 12], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyCtx": {"executed_lines": [17, 20, 21], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 4, 5, 8, 11, 15, 16, 19, 24, 25, 26, 27, 29, 35, 36, 42, 45, 46, 47, 48, 50, 52], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_bip85_init.py": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 11, 14, 15, 16, 17, 20, 21, 22, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 38, 39], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_init_with_seed_bytes": {"executed_lines": [15, 16, 17], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_init_with_xprv": {"executed_lines": [21, 22], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_initialize_bip85_works_while_locked": {"executed_lines": [26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 38, 39], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 11, 14, 20, 25], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 11, 14, 15, 16, 17, 20, 21, 22, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 38, 39], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_bip85_vectors.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 12, 14, 16, 18, 20, 21, 22, 25, 26, 27, 30, 31, 34, 35, 38, 39, 42, 43, 46, 47, 50, 51, 54, 55, 56, 57, 58], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"bip85": {"executed_lines": [27], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_bip85_mnemonic_12": {"executed_lines": [31], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_bip85_mnemonic_24": {"executed_lines": [35], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_bip85_symmetric_key": {"executed_lines": [39], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_derive_totp_secret": {"executed_lines": [43], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_derive_ssh_key": {"executed_lines": [47], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_derive_seed_phrase": {"executed_lines": [51], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_invalid_params": {"executed_lines": [55, 56, 57, 58], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 12, 14, 16, 18, 20, 21, 22, 25, 26, 30, 34, 38, 42, 46, 50, 54], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 12, 14, 16, 18, 20, 21, 22, 25, 26, 27, 30, 31, 34, 35, 38, 39, 42, 43, 46, 47, 50, 51, 54, 55, 56, 57, 58], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_check_critical_coverage.py": {"executed_lines": [1, 3, 4, 5, 7, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 26, 27, 30, 31, 34, 44, 45, 46, 49, 50, 56, 57, 60, 61, 62, 78, 81, 82, 83, 84], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_load_module": {"executed_lines": [11, 12, 13, 16, 17, 18, 19, 20], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_parse_threshold_overrides_valid": {"executed_lines": [27, 30, 31], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_parse_threshold_overrides_invalid": {"executed_lines": [45, 46], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_find_file_payload_accepts_absolute_path_suffix": {"executed_lines": [50, 56, 57], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_compute_function_coverage_reports_uncovered": {"executed_lines": [61, 62, 78, 81, 82, 83, 84], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 10, 23, 26, 34, 44, 49, 60], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 7, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 26, 27, 30, 31, 34, 44, 45, 46, 49, 50, 56, 57, 60, 61, 62, 78, 81, 82, 83, 84], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_checksum_utils.py": {"executed_lines": [1, 2, 3, 5, 8, 9, 10, 13, 16, 17, 18, 19, 20, 21, 22, 25, 26, 27, 30, 31, 32, 33, 34, 36, 37, 38, 41, 42, 43, 44, 45, 46, 47], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_json_checksum": {"executed_lines": [9, 10, 13], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_calculate_checksum": {"executed_lines": [17, 18, 19, 20, 21, 22], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_calculate_checksum_missing": {"executed_lines": [26, 27], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_verify_and_update": {"executed_lines": [31, 32, 33, 34, 36, 37, 38], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_initialize_checksum": {"executed_lines": [42, 43, 44, 45, 46, 47], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 8, 16, 25, 30, 41], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 8, 9, 10, 13, 16, 17, 18, 19, 20, 21, 22, 25, 26, 27, 30, 31, 32, 33, 34, 36, 37, 38, 41, 42, 43, 44, 45, 46, 47], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_clipboard_flag.py": {"executed_lines": [1, 3, 4, 5, 7, 10, 11, 12, 13, 15, 16, 18, 19, 20, 21, 23, 26, 27, 30, 31, 32, 35, 36, 39, 42, 43], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_stub_service": {"executed_lines": [11, 12, 15, 18, 23], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_stub_service.Service.search_entries": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_stub_service.Service.retrieve_entry": {"executed_lines": [16], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_stub_service.Service.generate_password": {"executed_lines": [19, 20, 21], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_get_handles_missing_clipboard": {"executed_lines": [27, 30, 31, 32], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_get_no_clipboard_flag": {"executed_lines": [36, 39, 42, 43], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 10, 26, 35], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"_stub_service.Service": {"executed_lines": [13, 16, 19, 20, 21], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 10, 11, 12, 15, 18, 23, 26, 27, 30, 31, 32, 35, 36, 39, 42, 43], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_config_set_extra.py": {"executed_lines": [1, 2, 3, 5, 6, 8, 11, 31, 32, 34, 35, 36, 38, 42, 44, 46, 47, 48, 49, 50], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_config_set_variants": {"executed_lines": [32, 34, 38, 42, 44, 46, 47, 48, 49, 50], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_config_set_variants.func": {"executed_lines": [35, 36], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 8, 11, 31], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 8, 11, 31, 32, 34, 35, 36, 38, 42, 44, 46, 47, 48, 49, 50], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_core_services.py": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 14, 15, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 30, 31, 33, 34, 35, 37, 38, 39, 41, 42, 43, 45, 53, 56, 57, 58, 59, 60, 63, 66, 67, 68, 71, 72, 73, 74], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_cli_vault_unlock": {"executed_lines": [15, 17, 21, 22, 23, 24, 25, 26, 27], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_vault_unlock.unlock_vault": {"executed_lines": [18, 19], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_entry_add_search_sync": {"executed_lines": [31, 33, 37, 41, 45, 53, 56, 57, 58, 59, 60, 63, 66, 67, 68, 71, 72, 73, 74], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_entry_add_search_sync.add_entry": {"executed_lines": [34, 35], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_entry_add_search_sync.search_entries": {"executed_lines": [38, 39], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_entry_add_search_sync.start_background_vault_sync": {"executed_lines": [42, 43], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 14, 30], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 6, 7, 8, 9, 11, 14, 15, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 30, 31, 33, 34, 35, 37, 38, 39, 41, 42, 43, 45, 53, 56, 57, 58, 59, 60, 63, 66, 67, 68, 71, 72, 73, 74], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_doc_examples.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 16, 17, 18, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 57, 60, 65, 66, 82, 83, 84, 87, 88, 89, 90, 91, 92, 93, 94, 95, 98, 101, 102, 103, 104, 105, 108, 111, 114, 115, 116, 117, 118], "summary": {"covered_lines": 56, "num_statements": 56, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"DummyPM.__init__": {"executed_lines": [18, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 57, 60, 65, 66, 82, 83, 84], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "load_doc_commands": {"executed_lines": [88, 89, 90, 91, 92, 93, 94, 95], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_setup": {"executed_lines": [102, 103, 104, 105, 108], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_doc_cli_examples": {"executed_lines": [116, 117, 118], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 16, 17, 87, 98, 101, 111, 114, 115], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyPM": {"executed_lines": [18, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 57, 60, 65, 66, 82, 83, 84], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 16, 17, 87, 88, 89, 90, 91, 92, 93, 94, 95, 98, 101, 102, 103, 104, 105, 108, 111, 114, 115, 116, 117, 118], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_entry_add_commands.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 12, 138, 141, 143, 144, 145, 146, 148, 149, 151, 157, 158, 159, 160, 161, 162, 163], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_entry_add_commands": {"executed_lines": [141, 143, 148, 151, 157, 158, 159, 160, 161, 162, 163], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_add_commands.func": {"executed_lines": [144, 145, 146], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_add_commands.start_background_vault_sync": {"executed_lines": [149], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 12, 138], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 12, 138, 141, 143, 144, 145, 146, 148, 149, 151, 157, 158, 159, 160, 161, 162, 163], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_export_import.py": {"executed_lines": [1, 2, 4, 6, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 28, 31, 32, 33, 46, 48, 49, 50, 51, 53, 54, 55, 56, 59, 60, 61, 74, 76, 77, 84, 86, 87, 88, 89, 91, 92, 93, 96, 97, 98, 111, 113, 114, 115, 116, 118, 119, 120, 121, 123, 124, 125, 126], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_setup_pm": {"executed_lines": [16, 17, 18, 19, 28], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_export_creates_file": {"executed_lines": [32, 33, 46, 48, 49, 50, 51, 53, 54, 55, 56], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_import_round_trip": {"executed_lines": [60, 61, 74, 76, 77, 84, 86, 87, 88, 89, 91, 92, 93], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_export_import_unencrypted": {"executed_lines": [97, 98, 111, 113, 114, 115, 116, 118, 119, 120, 121, 123, 124, 125, 126], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 8, 9, 10, 11, 12, 15, 31, 59, 96], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 28, 31, 32, 33, 46, 48, 49, 50, 51, 53, 54, 55, 56, 59, 60, 61, 74, 76, 77, 84, 86, 87, 88, 89, 91, 92, 93, 96, 97, 98, 111, 113, 114, 115, 116, 118, 119, 120, 121, 123, 124, 125, 126], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_integration.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 29, 32, 33, 34, 37, 42, 47, 51, 56, 57, 59, 61, 63, 65, 66, 67, 68, 69, 71], "summary": {"covered_lines": 40, "num_statements": 41, "percent_covered": 97.5609756097561, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [52], "excluded_lines": [], "functions": {"test_cli_integration": {"executed_lines": [17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 29, 32, 33, 34, 37, 42, 47, 51, 56, 57, 59, 61, 63, 65, 66, 67, 68, 69, 71], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_integration.auto_add": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [52], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 29, 32, 33, 34, 37, 42, 47, 51, 56, 57, 59, 61, 63, 65, 66, 67, 68, 69, 71], "summary": {"covered_lines": 40, "num_statements": 41, "percent_covered": 97.5609756097561, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [52], "excluded_lines": []}}}, "src/tests/test_cli_invalid_input.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13, 14, 15, 17, 20, 23, 26, 27, 29, 30, 32, 33, 34, 36, 52, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104], "summary": {"covered_lines": 66, "num_statements": 69, "percent_covered": 95.65217391304348, "percent_covered_display": "96", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [18, 21, 24], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [14, 15, 17, 20, 23, 26, 29, 32, 36, 52], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_make_pm.add": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [18], "excluded_lines": []}, "_make_pm.retrieve": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [21], "excluded_lines": []}, "_make_pm.modify": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [24], "excluded_lines": []}, "_make_pm.update": {"executed_lines": [27], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_make_pm.lock": {"executed_lines": [30], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_make_pm.unlock": {"executed_lines": [33, 34], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_empty_and_non_numeric_choice": {"executed_lines": [56, 57, 58, 59, 60, 61, 62, 63, 64], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_out_of_range_menu": {"executed_lines": [68, 69, 70, 71, 72, 73, 74, 75, 76], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_invalid_add_entry_submenu": {"executed_lines": [80, 81, 82, 83, 84, 85, 86, 87, 88, 89], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_inactivity_timeout_loop": {"executed_lines": [93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13, 55, 67, 79, 92], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13, 14, 15, 17, 20, 23, 26, 27, 29, 30, 32, 33, 34, 36, 52, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104], "summary": {"covered_lines": 66, "num_statements": 69, "percent_covered": 95.65217391304348, "percent_covered_display": "96", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [18, 21, 24], "excluded_lines": []}}}, "src/tests/test_cli_relays.py": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 12, 15, 16, 18, 19, 21, 23, 24, 26, 28, 31, 34, 35, 37, 38, 40, 41, 43, 44, 46, 47, 48, 49, 51, 52, 53], "summary": {"covered_lines": 33, "num_statements": 37, "percent_covered": 89.1891891891892, "percent_covered_display": "89", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [13, 20, 25, 27], "excluded_lines": [], "functions": {"DummyService.__init__": {"executed_lines": [10], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyService.get_pubkey": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [13], "excluded_lines": []}, "DummyService.list_relays": {"executed_lines": [16], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyService.add_relay": {"executed_lines": [19, 21], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [20], "excluded_lines": []}, "DummyService.remove_relay": {"executed_lines": [24, 26, 28], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [25, 27], "excluded_lines": []}, "test_cli_relay_crud": {"executed_lines": [35, 37, 40, 41, 43, 44, 46, 47, 48, 49, 51, 52, 53], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_relay_crud.pm_factory": {"executed_lines": [38], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8, 9, 12, 15, 18, 23, 31, 34], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyService": {"executed_lines": [10, 16, 19, 21, 24, 26, 28], "summary": {"covered_lines": 7, "num_statements": 11, "percent_covered": 63.63636363636363, "percent_covered_display": "64", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [13, 20, 25, 27], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8, 9, 12, 15, 18, 23, 31, 34, 35, 37, 38, 40, 41, 43, 44, 46, 47, 48, 49, 51, 52, 53], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_subcommands.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 17, 18, 26, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 58, 59, 60, 61, 62, 65, 66, 67, 68, 69, 70, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 85, 86, 90, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 114, 115, 119, 120, 121, 122, 123, 124, 125, 126, 127, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 143, 145, 147, 148, 149, 151, 152, 153, 154, 156, 157, 158], "summary": {"covered_lines": 113, "num_statements": 113, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"make_pm": {"executed_lines": [12, 17, 18, 26], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_command": {"executed_lines": [30, 31, 32, 33, 34, 35, 36, 37, 38], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_command": {"executed_lines": [42, 43, 44, 45, 46, 47, 48, 49, 50, 51], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_totp_command": {"executed_lines": [55, 56, 57, 58, 59, 60, 61, 62, 65, 66, 67, 68, 69, 70], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_command_no_results": {"executed_lines": [74, 75, 76, 77, 78, 79, 80, 81, 82], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_command_multiple_matches": {"executed_lines": [86, 90, 91, 92, 93, 94, 95, 96, 97, 98], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_command_wrong_type": {"executed_lines": [102, 103, 104, 105, 106, 107, 108, 109, 110, 111], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_totp_command_multiple_matches": {"executed_lines": [115, 119, 120, 121, 122, 123, 124, 125, 126, 127], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_totp_command_wrong_type": {"executed_lines": [131, 132, 133, 134, 135, 136, 137, 138, 139, 140], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_main_fingerprint_option": {"executed_lines": [145, 147, 151, 152, 153, 154, 156, 157, 158], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_main_fingerprint_option.fake_pm": {"executed_lines": [148, 149], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 29, 41, 54, 73, 85, 101, 114, 130, 143], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 17, 18, 26, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 58, 59, 60, 61, 62, 65, 66, 67, 68, 69, 70, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 85, 86, 90, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 114, 115, 119, 120, 121, 122, 123, 124, 125, 126, 127, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 143, 145, 147, 148, 149, 151, 152, 153, 154, 156, 157, 158], "summary": {"covered_lines": 113, "num_statements": 113, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_toggle_offline_mode.py": {"executed_lines": [1, 2, 4, 5, 7, 10, 11, 15, 20, 23, 24, 25, 26, 27, 28, 29, 30, 33, 34, 35, 36, 37, 38, 39, 40], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [11, 15, 20], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_toggle_offline_updates": {"executed_lines": [24, 25, 26, 27, 28, 29, 30], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_toggle_offline_keep": {"executed_lines": [34, 35, 36, 37, 38, 39, 40], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 7, 10, 23, 33], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 7, 10, 11, 15, 20, 23, 24, 25, 26, 27, 28, 29, 30, 33, 34, 35, 36, 37, 38, 39, 40], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_toggle_secret_mode.py": {"executed_lines": [1, 2, 3, 5, 6, 8, 11, 12, 18, 24, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 44], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [12, 18, 24], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_toggle_secret_mode_updates": {"executed_lines": [28, 29, 30, 31, 32, 33, 34], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_toggle_secret_mode_keep": {"executed_lines": [38, 39, 40, 41, 42, 43, 44], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 8, 11, 27, 37], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 8, 11, 12, 18, 24, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 44], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_cli_vault_stats.py": {"executed_lines": [1, 2, 3, 5, 6, 8, 11, 12, 16, 19, 20, 21, 22, 24, 25], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_vault_stats_command": {"executed_lines": [12, 16, 19, 20, 21, 22, 24, 25], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 8, 11], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 8, 11, 12, 16, 19, 20, 21, 22, 24, 25], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_clipboard_utils.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 15, 16, 18, 19, 21, 22, 24, 26, 27, 28, 29, 31, 32, 34, 35, 36, 38, 39, 40, 41, 42, 43, 46, 47, 49, 50, 52, 53, 55, 57, 58, 59, 61, 62, 64, 65, 66, 68, 69, 70, 71, 74, 75, 76, 78, 79, 80, 82, 83], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_copy_to_clipboard_clears": {"executed_lines": [16, 18, 21, 24, 26, 27, 31, 34, 35, 36, 38, 39, 40, 41, 42, 43], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_clears.fake_copy": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_clears.fake_paste": {"executed_lines": [22], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_clears.DummyTimer.__init__": {"executed_lines": [28, 29], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_clears.DummyTimer.start": {"executed_lines": [32], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_does_not_clear_if_changed": {"executed_lines": [47, 49, 52, 55, 57, 58, 61, 64, 65, 66, 68, 69, 70, 71], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_does_not_clear_if_changed.fake_copy": {"executed_lines": [50], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_does_not_clear_if_changed.fake_paste": {"executed_lines": [53], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_does_not_clear_if_changed.DummyTimer.__init__": {"executed_lines": [59], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_does_not_clear_if_changed.DummyTimer.start": {"executed_lines": [62], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_missing_dependency": {"executed_lines": [75, 78, 79, 80, 82, 83], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_missing_dependency.fail_copy": {"executed_lines": [76], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 15, 46, 74], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_copy_to_clipboard_clears.DummyTimer": {"executed_lines": [28, 29, 32], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_copy_to_clipboard_does_not_clear_if_changed.DummyTimer": {"executed_lines": [59, 62], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 15, 16, 18, 19, 21, 22, 24, 26, 27, 31, 34, 35, 36, 38, 39, 40, 41, 42, 43, 46, 47, 49, 50, 52, 53, 55, 57, 58, 61, 64, 65, 66, 68, 69, 70, 71, 74, 75, 76, 78, 79, 80, 82, 83], "summary": {"covered_lines": 52, "num_statements": 52, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_concurrency_stress.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 17, 29, 39, 51, 52, 53, 54, 55, 56, 57, 58, 59, 61, 62, 70, 71, 72, 73, 75, 76, 79, 81, 82], "summary": {"covered_lines": 35, "num_statements": 55, "percent_covered": 63.63636363636363, "percent_covered_display": "64", "missing_lines": 20, "excluded_lines": 6}, "missing_lines": [18, 19, 20, 21, 22, 23, 24, 30, 31, 32, 33, 34, 40, 41, 42, 43, 44, 45, 46, 77], "excluded_lines": [25, 26, 35, 36, 47, 48], "functions": {"_writer": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 2}, "missing_lines": [18, 19, 20, 21, 22, 23, 24], "excluded_lines": [25, 26]}, "_reader": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 2}, "missing_lines": [30, 31, 32, 33, 34], "excluded_lines": [35, 36]}, "_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 2}, "missing_lines": [40, 41, 42, 43, 44, 45, 46], "excluded_lines": [47, 48]}, "test_concurrency_stress": {"executed_lines": [54, 55, 56, 57, 58, 59, 61, 62, 70, 71, 72, 73, 75, 76, 79, 81, 82], "summary": {"covered_lines": 17, "num_statements": 18, "percent_covered": 94.44444444444444, "percent_covered_display": "94", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [77], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 17, 29, 39, 51, 52, 53], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 17, 29, 39, 51, 52, 53, 54, 55, 56, 57, 58, 59, 61, 62, 70, 71, 72, 73, 75, 76, 79, 81, 82], "summary": {"covered_lines": 35, "num_statements": 55, "percent_covered": 63.63636363636363, "percent_covered_display": "64", "missing_lines": 20, "excluded_lines": 6}, "missing_lines": [18, 19, 20, 21, 22, 23, 24, 30, 31, 32, 33, 34, 40, 41, 42, 43, 44, 45, 46, 77], "excluded_lines": [25, 26, 35, 36, 47, 48]}}}, "src/tests/test_config_manager.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 29, 30, 32, 33, 34, 37, 38, 39, 40, 42, 43, 44, 45, 46, 49, 52, 53, 54, 55, 57, 58, 60, 61, 62, 64, 65, 66, 67, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 84, 87, 88, 89, 90, 92, 93, 95, 96, 97, 100, 101, 102, 105, 106, 108, 109, 111, 112, 114, 115, 116, 119, 120, 121, 122, 125, 127, 128, 129, 130, 132, 133, 134, 137, 138, 139, 140, 142, 143, 144, 146, 147, 148, 149, 150, 153, 154, 155, 156, 158, 160, 161, 164, 165, 166, 167, 169, 171, 172, 175, 176, 177, 178, 180, 182, 183, 186, 187, 188, 189, 191, 192, 193, 195, 196, 197, 198, 201, 202, 203, 204, 206, 207, 208, 209, 210, 212, 213, 214, 215, 217, 218, 219, 220, 221, 224, 225, 226, 227, 229, 230, 231, 232, 234, 235, 236, 237, 238], "summary": {"covered_lines": 171, "num_statements": 171, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_config_defaults_and_round_trip": {"executed_lines": [17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 29, 30, 32, 33, 34], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_pin_verification_and_change": {"executed_lines": [38, 39, 40, 42, 43, 44, 45, 46], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_config_file_encrypted_after_save": {"executed_lines": [53, 54, 55, 57, 58, 60, 61, 62, 64, 65, 66, 67], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_set_relays_persists_changes": {"executed_lines": [71, 72, 73, 74, 75, 76], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_set_relays_requires_at_least_one": {"executed_lines": [80, 81, 82, 83, 84], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_inactivity_timeout_round_trip": {"executed_lines": [88, 89, 90, 92, 93, 95, 96, 97], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_password_hash_migrates_from_file": {"executed_lines": [101, 102, 105, 106, 108, 109, 111, 112, 114, 115, 116], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_additional_backup_path_round_trip": {"executed_lines": [120, 121, 122, 125, 127, 128, 129, 130, 132, 133, 134], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_secret_mode_round_trip": {"executed_lines": [138, 139, 140, 142, 143, 144, 146, 147, 148, 149, 150], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_kdf_iterations_round_trip": {"executed_lines": [154, 155, 156, 158, 160, 161], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_backup_interval_round_trip": {"executed_lines": [165, 166, 167, 169, 171, 172], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_quick_unlock_round_trip": {"executed_lines": [176, 177, 178, 180, 182, 183], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_nostr_retry_settings_round_trip": {"executed_lines": [187, 188, 189, 191, 192, 193, 195, 196, 197, 198], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_special_char_settings_round_trip": {"executed_lines": [202, 203, 204, 206, 207, 208, 209, 210, 212, 213, 214, 215, 217, 218, 219, 220, 221], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_password_policy_extended_fields": {"executed_lines": [225, 226, 227, 229, 230, 231, 232, 234, 235, 236, 237, 238], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 16, 37, 49, 52, 70, 79, 87, 100, 119, 137, 153, 164, 175, 186, 201, 224], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 29, 30, 32, 33, 34, 37, 38, 39, 40, 42, 43, 44, 45, 46, 49, 52, 53, 54, 55, 57, 58, 60, 61, 62, 64, 65, 66, 67, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 84, 87, 88, 89, 90, 92, 93, 95, 96, 97, 100, 101, 102, 105, 106, 108, 109, 111, 112, 114, 115, 116, 119, 120, 121, 122, 125, 127, 128, 129, 130, 132, 133, 134, 137, 138, 139, 140, 142, 143, 144, 146, 147, 148, 149, 150, 153, 154, 155, 156, 158, 160, 161, 164, 165, 166, 167, 169, 171, 172, 175, 176, 177, 178, 180, 182, 183, 186, 187, 188, 189, 191, 192, 193, 195, 196, 197, 198, 201, 202, 203, 204, 206, 207, 208, 209, 210, 212, 213, 214, 215, 217, 218, 219, 220, 221, 224, 225, 226, 227, 229, 230, 231, 232, 234, 235, 236, 237, 238], "summary": {"covered_lines": 171, "num_statements": 171, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_core_api_services.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 30, 31, 34, 35, 36, 37, 40, 41, 43, 46, 47, 48, 49, 50, 51, 52, 53, 56, 57, 58, 60, 63, 64, 66, 67, 70, 71, 72, 73, 75, 76, 77, 79, 80, 82, 83, 84, 86, 87, 89, 90, 91, 92, 94, 96, 97, 100, 103, 105, 106, 107, 108, 112, 114, 117, 120, 122, 123, 124, 126, 128, 129, 130, 131, 133, 134, 136, 137, 138, 140, 141, 142, 144, 148, 149, 150, 152, 154, 155, 158, 159, 160, 161, 163, 164, 165, 167, 168, 170, 171, 172, 174, 175, 177, 178, 179, 181, 185, 186, 187, 189, 192, 193, 194, 195, 197, 198, 199, 201, 203, 206, 207, 209, 210, 212, 214, 217, 219, 220, 221, 223, 224, 225, 228, 229, 230, 231, 233, 234, 235, 237, 240, 242, 243, 244, 246, 249, 251, 252, 253, 254, 256, 257, 259, 261, 262, 263, 265, 267, 268, 270, 272, 273, 275, 277, 278, 280, 281, 282, 284, 286, 287, 289, 290, 292, 294, 295, 296, 298, 299, 301, 303, 304, 305, 307, 308, 310, 312, 313, 314, 316, 317, 319, 321, 322, 323, 325, 326, 328, 330, 331, 332, 334, 335, 337, 339, 340, 341, 343, 344, 346, 348, 349, 350, 352, 353, 355, 357, 358, 359, 361, 362, 364, 375, 377, 378, 380, 381, 383, 384, 386, 387, 389, 390, 392, 394, 395, 397, 398, 399, 402, 403, 404, 405, 407, 408, 409, 411, 414, 416, 417, 418, 420, 421, 422, 426, 433, 434, 438, 439, 440, 442, 443, 444, 446, 447, 448, 450, 451, 453, 456, 459, 460, 462, 463, 464, 466, 467, 469, 470, 473, 474, 475, 476, 478, 479, 482, 483, 485, 489, 490, 493, 495, 496, 497, 499, 500, 501, 504, 505, 506, 507, 509, 510, 511, 513, 514, 515, 517, 518, 519, 521, 522, 524, 525, 526, 528, 529], "summary": {"covered_lines": 315, "num_statements": 315, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"mock_manager": {"executed_lines": [43, 46, 47, 48, 49, 50, 51, 52, 53, 56, 57, 58, 60], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "mock_bus": {"executed_lines": [66, 67], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.service": {"executed_lines": [73], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_export_vault": {"executed_lines": [76, 77, 79, 80], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_import_vault": {"executed_lines": [83, 84, 86, 87], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_export_profile": {"executed_lines": [90, 91, 92, 94, 96, 97, 100, 103], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_import_profile": {"executed_lines": [106, 107, 108, 112, 114, 117, 120], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_change_password": {"executed_lines": [123, 124, 126], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_unlock": {"executed_lines": [129, 130, 131, 133, 134], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_lock": {"executed_lines": [137, 138], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_backup_parent_seed": {"executed_lines": [141, 142, 144], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService.test_stats": {"executed_lines": [149, 150, 152, 154, 155], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestProfileService.service": {"executed_lines": [161], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestProfileService.test_list_profiles": {"executed_lines": [164, 165, 167, 168], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestProfileService.test_add_profile": {"executed_lines": [171, 172, 174, 175], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestProfileService.test_remove_profile": {"executed_lines": [178, 179, 181], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestProfileService.test_switch_profile": {"executed_lines": [186, 187, 189], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestSyncService.service": {"executed_lines": [195], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestSyncService.test_sync": {"executed_lines": [198, 199, 201, 203, 206, 207], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestSyncService.test_sync_none": {"executed_lines": [210, 212, 214, 217], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestSyncService.test_start_background_sync": {"executed_lines": [220, 221], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestSyncService.test_start_background_vault_sync": {"executed_lines": [224, 225], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.service": {"executed_lines": [231], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_list_entries": {"executed_lines": [234, 235, 237, 240], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_search_entries": {"executed_lines": [243, 244, 246, 249], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_retrieve_entry": {"executed_lines": [252, 253, 254, 256, 257], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_generate_password_default": {"executed_lines": [261, 262, 263, 265, 267, 268], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_generate_password_custom": {"executed_lines": [272, 273, 275, 277, 278], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_get_totp_code": {"executed_lines": [281, 282, 284, 286, 287], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_add_entry": {"executed_lines": [290, 292, 294, 295, 296], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_add_totp": {"executed_lines": [299, 301, 303, 304, 305], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_add_ssh_key": {"executed_lines": [308, 310, 312, 313, 314], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_add_pgp_key": {"executed_lines": [317, 319, 321, 322, 323], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_add_nostr_key": {"executed_lines": [326, 328, 330, 331, 332], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_add_seed": {"executed_lines": [335, 337, 339, 340, 341], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_add_key_value": {"executed_lines": [344, 346, 348, 349, 350], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_add_managed_account": {"executed_lines": [353, 355, 357, 358, 359], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_modify_entry": {"executed_lines": [362, 364, 375], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_archive_entry": {"executed_lines": [378, 380, 381], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_restore_entry": {"executed_lines": [384, 386, 387], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_export_totp_entries": {"executed_lines": [390, 392, 394, 395], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService.test_display_totp_codes": {"executed_lines": [398, 399], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.service": {"executed_lines": [405], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_get": {"executed_lines": [408, 409, 411, 414], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_set_simple": {"executed_lines": [417, 418], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_set_bool": {"executed_lines": [421, 422], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_set_relays": {"executed_lines": [433, 434], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_set_invalid_key": {"executed_lines": [439, 440], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_get_secret_mode_enabled": {"executed_lines": [443, 444], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_get_clipboard_clear_delay": {"executed_lines": [447, 448], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_set_secret_mode": {"executed_lines": [451, 453, 456, 459, 460], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_get_offline_mode": {"executed_lines": [463, 464], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService.test_set_offline_mode": {"executed_lines": [467, 469, 470], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestUtilityService.service": {"executed_lines": [476], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestUtilityService.test_generate_password": {"executed_lines": [479, 482, 483, 485, 489, 490, 493], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestUtilityService.test_verify_checksum": {"executed_lines": [496, 497], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestUtilityService.test_update_checksum": {"executed_lines": [500, 501], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestNostrService.service": {"executed_lines": [507], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestNostrService.test_get_pubkey": {"executed_lines": [510, 511], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestNostrService.test_list_relays": {"executed_lines": [514, 515], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestNostrService.test_add_relay": {"executed_lines": [518, 519, 521, 522], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestNostrService.test_remove_relay": {"executed_lines": [525, 526, 528, 529], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 30, 31, 34, 35, 36, 37, 40, 41, 63, 64, 70, 71, 72, 75, 82, 89, 105, 122, 128, 136, 140, 148, 158, 159, 160, 163, 170, 177, 185, 192, 193, 194, 197, 209, 219, 223, 228, 229, 230, 233, 242, 251, 259, 270, 280, 289, 298, 307, 316, 325, 334, 343, 352, 361, 377, 383, 389, 397, 402, 403, 404, 407, 416, 420, 426, 438, 442, 446, 450, 462, 466, 473, 474, 475, 478, 495, 499, 504, 505, 506, 509, 513, 517, 524], "summary": {"covered_lines": 91, "num_statements": 91, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"MockPolicy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestVaultService": {"executed_lines": [73, 76, 77, 79, 80, 83, 84, 86, 87, 90, 91, 92, 94, 96, 97, 100, 103, 106, 107, 108, 112, 114, 117, 120, 123, 124, 126, 129, 130, 131, 133, 134, 137, 138, 141, 142, 144, 149, 150, 152, 154, 155], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestProfileService": {"executed_lines": [161, 164, 165, 167, 168, 171, 172, 174, 175, 178, 179, 181, 186, 187, 189], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestSyncService": {"executed_lines": [195, 198, 199, 201, 203, 206, 207, 210, 212, 214, 217, 220, 221, 224, 225], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestEntryService": {"executed_lines": [231, 234, 235, 237, 240, 243, 244, 246, 249, 252, 253, 254, 256, 257, 261, 262, 263, 265, 267, 268, 272, 273, 275, 277, 278, 281, 282, 284, 286, 287, 290, 292, 294, 295, 296, 299, 301, 303, 304, 305, 308, 310, 312, 313, 314, 317, 319, 321, 322, 323, 326, 328, 330, 331, 332, 335, 337, 339, 340, 341, 344, 346, 348, 349, 350, 353, 355, 357, 358, 359, 362, 364, 375, 378, 380, 381, 384, 386, 387, 390, 392, 394, 395, 398, 399], "summary": {"covered_lines": 85, "num_statements": 85, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestConfigService": {"executed_lines": [405, 408, 409, 411, 414, 417, 418, 421, 422, 433, 434, 439, 440, 443, 444, 447, 448, 451, 453, 456, 459, 460, 463, 464, 467, 469, 470], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestUtilityService": {"executed_lines": [476, 479, 482, 483, 485, 489, 490, 493, 496, 497, 500, 501], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "TestNostrService": {"executed_lines": [507, 510, 511, 514, 515, 518, 519, 521, 522, 525, 526, 528, 529], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 30, 31, 34, 35, 36, 37, 40, 41, 43, 46, 47, 48, 49, 50, 51, 52, 53, 56, 57, 58, 60, 63, 64, 66, 67, 70, 71, 72, 75, 82, 89, 105, 122, 128, 136, 140, 148, 158, 159, 160, 163, 170, 177, 185, 192, 193, 194, 197, 209, 219, 223, 228, 229, 230, 233, 242, 251, 259, 270, 280, 289, 298, 307, 316, 325, 334, 343, 352, 361, 377, 383, 389, 397, 402, 403, 404, 407, 416, 420, 426, 438, 442, 446, 450, 462, 466, 473, 474, 475, 478, 495, 499, 504, 505, 506, 509, 513, 517, 524], "summary": {"covered_lines": 106, "num_statements": 106, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_core_services.py": {"executed_lines": [1, 2, 4, 5, 8, 9, 11, 12, 13, 15, 16, 17, 18, 19, 22, 23, 25, 26, 27, 29, 30, 31, 33, 34, 36, 37, 38, 44, 45, 46, 47, 48, 50, 51, 52, 55, 56, 58, 59, 60, 66, 67, 68, 69, 70, 71, 72], "summary": {"covered_lines": 47, "num_statements": 47, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_vault_service_unlock": {"executed_lines": [9, 11, 15, 16, 17, 18, 19], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_service_unlock.unlock_vault": {"executed_lines": [12, 13], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_service_add_entry_and_search": {"executed_lines": [23, 25, 29, 33, 36, 37, 38, 44, 45, 46, 47, 48, 50, 51, 52], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_service_add_entry_and_search.add_entry": {"executed_lines": [26, 27], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_service_add_entry_and_search.search_entries": {"executed_lines": [30, 31], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_service_add_entry_and_search.start_background_vault_sync": {"executed_lines": [34], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sync_service_sync": {"executed_lines": [56, 58, 66, 67, 68, 69, 70, 71, 72], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sync_service_sync.sync_vault": {"executed_lines": [59, 60], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8, 22, 55], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 8, 9, 11, 12, 13, 15, 16, 17, 18, 19, 22, 23, 25, 26, 27, 29, 30, 31, 33, 34, 36, 37, 38, 44, 45, 46, 47, 48, 50, 51, 52, 55, 56, 58, 59, 60, 66, 67, 68, 69, 70, 71, 72], "summary": {"covered_lines": 47, "num_statements": 47, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_custom_fields_display.py": {"executed_lines": [1, 2, 3, 5, 8, 9, 10, 11, 13, 22, 23, 25, 26, 27, 28, 29, 30], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_retrieve_entry_shows_custom_fields": {"executed_lines": [9, 10, 11, 13, 22, 23, 25, 26, 27, 28, 29, 30], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 8], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 8, 9, 10, 11, 13, 22, 23, 25, 26, 27, 28, 29, 30], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_decrypt_messages.py": {"executed_lines": [1, 2, 3, 5, 6, 8, 9, 13, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 30, 31, 32, 33, 34, 36, 40, 41, 42, 44, 45, 46, 47, 50, 51, 52, 53, 54, 56, 57, 58], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_wrong_password_message": {"executed_lines": [17, 18, 19, 21, 22, 23, 25, 26, 27], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_file_requires_migration_message": {"executed_lines": [31, 36, 40, 41, 42, 44, 45, 46, 47], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_file_requires_migration_message._fast_legacy_key": {"executed_lines": [32, 33, 34], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_corrupted_data_message": {"executed_lines": [51, 52, 53, 54, 56, 57, 58], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 8, 9, 13, 16, 30, 50], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 8, 9, 13, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 30, 31, 32, 33, 34, 36, 40, 41, 42, 44, 45, 46, 47, 50, 51, 52, 53, 54, 56, 57, 58], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_default_encryption_mode.py": {"executed_lines": [1, 2, 4, 6, 7, 9, 10, 13, 14, 26, 28, 29], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_default_encryption_mode": {"executed_lines": [14, 26, 28, 29], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 9, 10, 13], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 7, 9, 10, 13, 14, 26, 28, 29], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_delta_merge.py": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 25, 26, 29, 30, 31, 32, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 46, 47, 48, 49], "summary": {"covered_lines": 37, "num_statements": 37, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_setup_mgr": {"executed_lines": [13, 14, 15, 16], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_merge_modified_ts": {"executed_lines": [20, 21, 22, 23, 25, 26, 29, 30, 31, 32, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 46, 47, 48, 49], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 19], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 25, 26, 29, 30, 31, 32, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 46, 47, 48, 49], "summary": {"covered_lines": 37, "num_statements": 37, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_duplicate_seed_profile_creation.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 12, 13, 14, 15, 16, 17, 18, 22, 23, 24, 26, 27, 29, 30, 31, 34, 35, 36, 37, 38, 39, 42, 43, 44, 45, 47, 48, 49, 51, 52, 53], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_setup_pm": {"executed_lines": [13, 14, 15, 16, 17, 18, 22, 23, 26, 29, 30, 31, 34, 35, 36, 37, 38, 39], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_setup_pm.DummyEnc.__init__": {"executed_lines": [24], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_setup_pm.DummyEnc.encrypt_parent_seed": {"executed_lines": [27], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_duplicate_seed_profile_creation": {"executed_lines": [43, 44, 45, 47, 48, 49, 51, 52, 53], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 12, 42], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"_setup_pm.DummyEnc": {"executed_lines": [24, 27], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 12, 13, 14, 15, 16, 17, 18, 22, 23, 26, 29, 30, 31, 34, 35, 36, 37, 38, 39, 42, 43, 44, 45, 47, 48, 49, 51, 52, 53], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_edit_tags_from_retrieve.py": {"executed_lines": [1, 2, 3, 5, 8, 9, 10, 13, 14, 15, 16, 18, 20, 21, 23, 25, 26], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakePasswordGenerator.generate_password": {"executed_lines": [10], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_edit_tags_from_retrieve": {"executed_lines": [14, 15, 16, 18, 20, 21, 23, 25, 26], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 8, 9, 13], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakePasswordGenerator": {"executed_lines": [10], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 8, 9, 13, 14, 15, 16, 18, 20, 21, 23, 25, 26], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_encryption_checksum.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 10, 12, 13, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 39, 40, 41, 43, 45, 46, 48, 50, 51, 53, 54, 56, 57], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_encryption_checksum_workflow": {"executed_lines": [17, 18, 19, 20, 22, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_checksum_removes_legacy": {"executed_lines": [40, 41, 43, 45, 46, 48, 50, 51, 53, 54, 56, 57], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 10, 12, 13, 16, 39], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 10, 12, 13, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 39, 40, 41, 43, 45, 46, 48, 50, 51, 53, 54, 56, 57], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_encryption_files.py": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 10, 12, 15, 16, 17, 18, 20, 21, 22, 23, 25, 26, 27, 30, 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 46, 47, 48, 49, 51, 52, 54, 55], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_json_save_and_load_round_trip": {"executed_lines": [16, 17, 18, 20, 21, 22, 23, 25, 26, 27], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_encrypt_and_decrypt_file_binary_round_trip": {"executed_lines": [31, 32, 33, 35, 36, 37, 38, 39, 41, 42, 43], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_encrypt_file_rejects_traversal": {"executed_lines": [47, 48, 49, 51, 52, 54, 55], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 10, 12, 15, 30, 46], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 10, 12, 15, 16, 17, 18, 20, 21, 22, 23, 25, 26, 27, 30, 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 46, 47, 48, 49, 51, 52, 54, 55], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_encryption_fuzz.py": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 15, 17, 18, 19, 20, 23, 24, 29, 31, 32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_encrypt_decrypt_roundtrip": {"executed_lines": [17, 18, 19, 20], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_corrupted_ciphertext_fails": {"executed_lines": [31, 32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 15, 23, 24, 29], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 15, 17, 18, 19, 20, 23, 24, 29, 31, 32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_encryption_validate_seed.py": {"executed_lines": [1, 2, 4, 5, 7, 9, 12, 13, 14, 17, 18, 19, 20, 21, 22, 25, 26, 27, 28, 29, 30], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"make_manager": {"executed_lines": [13, 14], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_validate_seed_valid_mnemonic": {"executed_lines": [18, 19, 20, 21, 22], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_validate_seed_invalid_mnemonic": {"executed_lines": [26, 27, 28, 29, 30], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 7, 9, 12, 17, 25], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 7, 9, 12, 13, 14, 17, 18, 19, 20, 21, 22, 25, 26, 27, 28, 29, 30], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_entries_empty.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 21, 22], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_list_entries_empty": {"executed_lines": [15, 16, 17, 18, 19, 21, 22], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 21, 22], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_entry_add.py": {"executed_lines": [1, 2, 3, 4, 6, 7, 9, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 24, 29, 30, 32, 45, 46, 47, 48, 49, 52, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 87, 88, 89, 90, 91, 92, 95, 96, 97, 98, 99, 100, 102, 104, 105, 106, 108, 109, 112, 125, 126, 127, 128, 129, 130, 132, 133, 134, 136, 138, 139], "summary": {"covered_lines": 77, "num_statements": 78, "percent_covered": 98.71794871794872, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [85], "excluded_lines": [], "functions": {"test_add_and_retrieve_entry": {"executed_lines": [18, 19, 20, 21, 22, 24, 29, 30, 32, 45, 46, 47, 48, 49], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_round_trip_entry_types": {"executed_lines": [64, 65, 66, 67, 68, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 87, 88, 89, 90, 91, 92], "summary": {"covered_lines": 24, "num_statements": 25, "percent_covered": 96.0, "percent_covered_display": "96", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [85], "excluded_lines": []}, "test_legacy_entry_defaults_to_password": {"executed_lines": [96, 97, 98, 99, 100, 102, 104, 105, 106, 108, 109], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_default_archived_false": {"executed_lines": [126, 127, 128, 129, 130, 132, 133, 134, 136, 138, 139], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 9, 11, 12, 13, 14, 17, 52, 63, 95, 112, 125], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 7, 9, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 24, 29, 30, 32, 45, 46, 47, 48, 49, 52, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 87, 88, 89, 90, 91, 92, 95, 96, 97, 98, 99, 100, 102, 104, 105, 106, 108, 109, 112, 125, 126, 127, 128, 129, 130, 132, 133, 134, 136, 138, 139], "summary": {"covered_lines": 77, "num_statements": 78, "percent_covered": 98.71794871794872, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [85], "excluded_lines": []}}}, "src/tests/test_entry_management_checksum_path.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 23, 24, 26, 27, 30, 31, 32, 33, 34, 35, 36, 38, 39, 41, 42, 43], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_update_checksum_writes_to_expected_path": {"executed_lines": [15, 16, 17, 18, 19, 20, 23, 24, 26, 27], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_backup_index_file_creates_backup_in_directory": {"executed_lines": [31, 32, 33, 34, 35, 36, 38, 39, 41, 42, 43], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14, 30], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 23, 24, 26, 27, 30, 31, 32, 33, 34, 35, 36, 38, 39, 41, 42, 43], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_entry_policy_override.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 15, 18, 19, 23, 24, 25, 28, 29, 30, 31, 32, 34, 35, 36, 37, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 58, 64, 65, 66, 67], "summary": {"covered_lines": 46, "num_statements": 47, "percent_covered": 97.87234042553192, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [20], "excluded_lines": [], "functions": {"DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [20], "excluded_lines": []}, "DummyBIP85.derive_entropy": {"executed_lines": [25], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_manager": {"executed_lines": [29, 30, 31, 32, 34, 35, 36, 37, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_policy_override_changes_password": {"executed_lines": [55, 56, 57, 58, 64, 65, 66, 67], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 15, 18, 19, 23, 24, 28, 54], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEnc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [20], "excluded_lines": []}, "DummyBIP85": {"executed_lines": [25], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 15, 18, 19, 23, 24, 28, 29, 30, 31, 32, 34, 35, 36, 37, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 58, 64, 65, 66, 67], "summary": {"covered_lines": 45, "num_statements": 45, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_export_totp_codes.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 15, 18, 19, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 40, 41, 43, 44, 45, 47, 49, 50, 51, 52, 54, 55], "summary": {"covered_lines": 39, "num_statements": 40, "percent_covered": 97.5, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [20], "excluded_lines": [], "functions": {"FakeNostrClient.publish_snapshot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [20], "excluded_lines": []}, "test_handle_export_totp_codes": {"executed_lines": [24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 40, 41, 43, 44, 45, 47, 49, 50, 51, 52, 54, 55], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 15, 18, 19, 23], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeNostrClient": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [20], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 15, 18, 19, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 40, 41, 43, 44, 45, 47, 49, 50, 51, 52, 54, 55], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_file_lock.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 17, 23, 27, 28, 33, 34, 38, 39, 41, 42, 44, 45, 46, 47, 49, 50, 56], "summary": {"covered_lines": 24, "num_statements": 31, "percent_covered": 77.41935483870968, "percent_covered_display": "77", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [12, 13, 14, 18, 19, 20, 36], "excluded_lines": [], "functions": {"_hold_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [12, 13, 14], "excluded_lines": []}, "_try_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [18, 19, 20], "excluded_lines": []}, "test_exclusive_lock_blocks_until_released": {"executed_lines": [28, 33, 34, 38, 39, 41, 42, 44, 45, 46, 47, 49, 50, 56], "summary": {"covered_lines": 14, "num_statements": 15, "percent_covered": 93.33333333333333, "percent_covered_display": "93", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [36], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 17, 23, 27], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 17, 23, 27, 28, 33, 34, 38, 39, 41, 42, 44, 45, 46, 47, 49, 50, 56], "summary": {"covered_lines": 24, "num_statements": 31, "percent_covered": 77.41935483870968, "percent_covered_display": "77", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [12, 13, 14, 18, 19, 20, 36], "excluded_lines": []}}}, "src/tests/test_file_locking.py": {"executed_lines": [1, 2, 3, 5, 8, 9, 10, 11, 16, 17, 18, 19, 24, 27, 28, 29, 30, 32, 33, 34, 35, 38, 40, 41, 42, 43, 45, 46, 47], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 4}, "missing_lines": [], "excluded_lines": [12, 13, 20, 21], "functions": {"_writer": {"executed_lines": [9, 10, 11], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [12, 13]}, "_reader": {"executed_lines": [17, 18, 19], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [20, 21]}, "test_concurrent_shared_and_exclusive_lock": {"executed_lines": [29, 30, 32, 33, 34, 35, 38, 40, 41, 42, 43, 45, 46, 47], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 8, 16, 24, 27, 28], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 8, 9, 10, 11, 16, 17, 18, 19, 24, 27, 28, 29, 30, 32, 33, 34, 35, 38, 40, 41, 42, 43, 45, 46, 47], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 4}, "missing_lines": [], "excluded_lines": [12, 13, 20, 21]}}}, "src/tests/test_fingerprint_encryption.py": {"executed_lines": [1, 2, 3, 4, 6, 7, 9, 11, 12, 15, 16, 17, 20, 21, 22, 23, 26, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_generate_fingerprint_deterministic": {"executed_lines": [16, 17, 20, 21, 22, 23], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_encryption_round_trip": {"executed_lines": [27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 9, 11, 12, 15, 26], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 7, 9, 11, 12, 15, 16, 17, 20, 21, 22, 23, 26, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_fingerprint_manager_utils.py": {"executed_lines": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_add_and_remove_fingerprint": {"executed_lines": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_remove_nonexistent_fingerprint": {"executed_lines": [19, 20], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 4, 18], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_full_sync_roundtrip.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 51, 52, 53, 56, 57, 58, 59, 60, 63, 64, 65, 66], "summary": {"covered_lines": 50, "num_statements": 50, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_init_pm": {"executed_lines": [14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_full_sync_roundtrip": {"executed_lines": [33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 51, 52, 53, 56, 57, 58, 59, 60, 63, 64, 65, 66], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 32], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 51, 52, 53, 56, 57, 58, 59, 60, 63, 64, 65, 66], "summary": {"covered_lines": 50, "num_statements": 50, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_full_sync_roundtrip_new.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 51, 52, 53, 56, 57, 58, 59, 60, 63, 64, 65, 66], "summary": {"covered_lines": 50, "num_statements": 50, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_init_pm": {"executed_lines": [14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_full_sync_roundtrip": {"executed_lines": [33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 51, 52, 53, 56, 57, 58, 59, 60, 63, 64, 65, 66], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 32], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 51, 52, 53, 56, 57, 58, 59, 60, 63, 64, 65, 66], "summary": {"covered_lines": 50, "num_statements": 50, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_fuzz_key_derivation.py": {"executed_lines": [1, 2, 4, 5, 6, 7, 8, 10, 16, 17, 19, 26, 32, 37, 39, 40, 41, 42, 48, 50, 51, 59, 62, 63, 66, 67, 68, 71, 72, 73, 76, 77, 78, 79], "summary": {"covered_lines": 34, "num_statements": 34, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_fuzz_key_round_trip": {"executed_lines": [39, 40, 41, 42, 48, 50, 51, 59, 62, 63, 66, 67, 68, 71, 72, 73, 76, 77, 78, 79], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 6, 7, 8, 10, 16, 17, 19, 26, 32, 37], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 6, 7, 8, 10, 16, 17, 19, 26, 32, 37, 39, 40, 41, 42, 48, 50, 51, 59, 62, 63, 66, 67, 68, 71, 72, 73, 76, 77, 78, 79], "summary": {"covered_lines": 34, "num_statements": 34, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_generate_test_profile.py": {"executed_lines": [1, 2, 3, 4, 7, 8, 9, 11, 14, 15, 17, 20, 23, 24, 25, 27, 28, 30, 31, 32, 33], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_initialize_profile_creates_directories": {"executed_lines": [8, 9, 11, 14, 15, 17, 20, 23, 24, 25, 27, 28, 30, 31, 32, 33], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 7], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 7, 8, 9, 11, 14, 15, 17, 20, 23, 24, 25, 27, 28, 30, 31, 32, 33], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_generate_test_profile_sync.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 26, 27, 28, 30, 32, 33, 35, 36, 42, 44, 46, 47, 48, 50, 53, 54, 55, 57, 58, 64, 66, 67, 68, 69, 70], "summary": {"covered_lines": 43, "num_statements": 44, "percent_covered": 97.72727272727273, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [51], "excluded_lines": [], "functions": {"load_script": {"executed_lines": [10, 13, 14, 15, 16, 17], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_test_profile_sync": {"executed_lines": [21, 22, 23, 24, 26, 27, 28, 30, 32, 33, 35, 36, 42, 44, 46, 47, 50, 53, 54, 57, 58, 64, 66, 67, 68, 69, 70], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_test_profile_sync.DummyKeys.private_key_hex": {"executed_lines": [48], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_test_profile_sync.DummyKeys.public_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [51], "excluded_lines": []}, "test_generate_test_profile_sync.DummyKeyManager.__init__": {"executed_lines": [55], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 9, 20], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_generate_test_profile_sync.DummyKeys": {"executed_lines": [48], "summary": {"covered_lines": 1, "num_statements": 2, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [51], "excluded_lines": []}, "test_generate_test_profile_sync.DummyKeyManager": {"executed_lines": [55], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 26, 27, 28, 30, 32, 33, 35, 36, 42, 44, 46, 47, 50, 53, 54, 57, 58, 64, 66, 67, 68, 69, 70], "summary": {"covered_lines": 41, "num_statements": 41, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_get_entry_summaries_archived_view.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 38, 39, 40, 41, 43, 44, 46, 47, 48, 49, 50], "summary": {"covered_lines": 41, "num_statements": 41, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_get_entry_summaries_excludes_archived_and_view_handler": {"executed_lines": [15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 38, 39, 40, 41, 43, 44, 46, 47, 48, 49, 50], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 38, 39, 40, 41, 43, 44, 46, 47, 48, 49, 50], "summary": {"covered_lines": 41, "num_statements": 41, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_get_entry_summaries_updates.py": {"executed_lines": [1, 2, 4, 6, 7, 8, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 24, 25, 27, 28, 29, 32, 33, 34, 35, 36, 37, 39, 40, 42, 43, 44, 46, 47, 48], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_create_entry_manager": {"executed_lines": [12, 13, 14, 15], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_entry_summaries_updates_label": {"executed_lines": [19, 20, 21, 22, 24, 25, 27, 28, 29], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_entry_summaries_updates_archive_restore": {"executed_lines": [33, 34, 35, 36, 37, 39, 40, 42, 43, 44, 46, 47, 48], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 8, 11, 18, 32], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 7, 8, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 24, 25, 27, 28, 29, 32, 33, 34, 35, 36, 37, 39, 40, 42, 43, 44, 46, 47, 48], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_gui_features.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 18, 21, 24, 28, 29, 33, 38, 41, 44, 48, 49, 57, 58, 65, 78, 94], "summary": {"covered_lines": 26, "num_statements": 83, "percent_covered": 31.325301204819276, "percent_covered_display": "31", "missing_lines": 57, "excluded_lines": 0}, "missing_lines": [16, 19, 22, 25, 30, 31, 34, 35, 36, 39, 42, 45, 50, 51, 52, 53, 54, 59, 60, 62, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 95, 96, 97, 98, 99, 100, 101, 104, 108, 109, 112, 113, 114, 115], "excluded_lines": [], "functions": {"DummyNostr.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [16], "excluded_lines": []}, "DummyNostr.list_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [19], "excluded_lines": []}, "DummyNostr.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": []}, "DummyNostr.remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [25], "excluded_lines": []}, "DummyEntries.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [30, 31], "excluded_lines": []}, "DummyEntries.list_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [34, 35, 36], "excluded_lines": []}, "DummyEntries.search_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [39], "excluded_lines": []}, "DummyEntries.retrieve_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [42], "excluded_lines": []}, "DummyEntries.get_totp_code": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [45], "excluded_lines": []}, "DummyController.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [50, 51, 52, 53, 54], "excluded_lines": []}, "set_backend": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [59, 60, 62], "excluded_lines": []}, "test_relay_manager_add_remove": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [66, 67, 68, 69, 70, 71, 72, 73, 74, 75], "excluded_lines": []}, "test_status_bar_updates_and_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91], "excluded_lines": []}, "test_totp_viewer_refresh_on_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [95, 96, 97, 98, 99, 100, 101, 104, 108, 109, 112, 113, 114, 115], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 18, 21, 24, 28, 29, 33, 38, 41, 44, 48, 49, 57, 58, 65, 78, 94], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyNostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [16, 19, 22, 25], "excluded_lines": []}, "DummyEntries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [30, 31, 34, 35, 36, 39, 42, 45], "excluded_lines": []}, "DummyController": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [50, 51, 52, 53, 54], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 18, 21, 24, 28, 29, 33, 38, 41, 44, 48, 49, 57, 58, 65, 78, 94], "summary": {"covered_lines": 26, "num_statements": 66, "percent_covered": 39.39393939393939, "percent_covered_display": "39", "missing_lines": 40, "excluded_lines": 0}, "missing_lines": [59, 60, 62, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 95, 96, 97, 98, 99, 100, 101, 104, 108, 109, 112, 113, 114, 115], "excluded_lines": []}}}, "src/tests/test_gui_headless.py": {"executed_lines": [1, 2, 3, 5, 6, 8, 10, 13, 14, 15, 17, 18, 21, 22, 23, 24, 26, 27, 29, 32, 33, 34, 36, 39, 40, 42, 43, 44, 46, 47, 48, 50, 51, 52, 54, 55, 56, 58, 59, 60, 62, 63, 64, 66, 69, 72, 73, 74, 76, 79, 80, 83, 86, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, 101, 104, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 135, 136, 137, 138, 141, 149, 150, 151, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170], "summary": {"covered_lines": 105, "num_statements": 109, "percent_covered": 96.3302752293578, "percent_covered_display": "96", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [30, 81, 84, 87], "excluded_lines": [], "functions": {"FakeVault.__init__": {"executed_lines": [15], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeVault.unlock": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.__init__": {"executed_lines": [23, 24], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.list_entries": {"executed_lines": [27], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.search_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [30], "excluded_lines": []}, "FakeEntries.add_entry": {"executed_lines": [33, 34], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.add_totp": {"executed_lines": [39, 40], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.add_ssh_key": {"executed_lines": [43, 44], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.add_seed": {"executed_lines": [47, 48], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.add_pgp_key": {"executed_lines": [51, 52], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.add_nostr_key": {"executed_lines": [55, 56], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.add_key_value": {"executed_lines": [59, 60], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.add_managed_account": {"executed_lines": [63, 64], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries.modify_entry": {"executed_lines": [69], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "setup_module": {"executed_lines": [73, 74, 76], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostr.list_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [81], "excluded_lines": []}, "FakeNostr.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [84], "excluded_lines": []}, "FakeNostr.remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [87], "excluded_lines": []}, "test_unlock_creates_main_window": {"executed_lines": [91, 92, 93, 94, 95, 96, 97, 99, 100, 101], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entrydialog_add_calls_service": {"executed_lines": [118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 135, 136, 137, 138], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entrydialog_edit_calls_service": {"executed_lines": [150, 151, 153, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entrydialog_edit_calls_service.retrieve": {"executed_lines": [154], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 8, 10, 13, 14, 17, 21, 22, 26, 29, 32, 36, 42, 46, 50, 54, 58, 62, 66, 72, 79, 80, 83, 86, 90, 104, 117, 141, 149], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeVault": {"executed_lines": [15, 18], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEntries": {"executed_lines": [23, 24, 27, 33, 34, 39, 40, 43, 44, 47, 48, 51, 52, 55, 56, 59, 60, 63, 64, 69], "summary": {"covered_lines": 20, "num_statements": 21, "percent_covered": 95.23809523809524, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [30], "excluded_lines": []}, "FakeNostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [81, 84, 87], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 8, 10, 13, 14, 17, 21, 22, 26, 29, 32, 36, 42, 46, 50, 54, 58, 62, 66, 72, 73, 74, 76, 79, 80, 83, 86, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, 101, 104, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 135, 136, 137, 138, 141, 149, 150, 151, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170], "summary": {"covered_lines": 83, "num_statements": 83, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_gui_sync.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 11, 12, 13, 15, 19, 20, 21, 23, 24, 26, 30, 31, 32, 33, 34, 35, 36, 37, 40, 41, 42, 43, 46, 47, 49, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62, 63, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77], "summary": {"covered_lines": 54, "num_statements": 56, "percent_covered": 96.42857142857143, "percent_covered_display": "96", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [16, 27], "excluded_lines": [], "functions": {"DummyEntries.list_entries": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEntries.search_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [16], "excluded_lines": []}, "DummyNostr.__init__": {"executed_lines": [21], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyNostr.start_background_vault_sync": {"executed_lines": [24], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyNostr.list_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [27], "excluded_lines": []}, "DummyController.__init__": {"executed_lines": [32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "set_backend": {"executed_lines": [42, 43], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_vault_sync_schedules_task": {"executed_lines": [47, 49, 51, 54, 55, 56, 57, 59, 60, 61, 62, 63], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_vault_sync_schedules_task.create_task": {"executed_lines": [52], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_status_updates_on_bus_events": {"executed_lines": [67, 68, 69, 70, 71, 73, 74, 75, 76, 77], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 11, 12, 15, 19, 20, 23, 26, 30, 31, 40, 41, 46, 66], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEntries": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 2, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [16], "excluded_lines": []}, "DummyNostr": {"executed_lines": [21, 24], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [27], "excluded_lines": []}, "DummyController": {"executed_lines": [32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 11, 12, 15, 19, 20, 23, 26, 30, 31, 40, 41, 42, 43, 46, 47, 49, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62, 63, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77], "summary": {"covered_lines": 45, "num_statements": 45, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_handle_switch_fingerprint.py": {"executed_lines": [1, 4, 5, 6, 7, 9, 10, 12, 13, 15, 16, 17, 18, 19, 21, 25, 26, 28, 30, 31, 32], "summary": {"covered_lines": 21, "num_statements": 23, "percent_covered": 91.30434782608695, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [22, 23], "excluded_lines": [], "functions": {"test_handle_switch_fingerprint_active_profile": {"executed_lines": [5, 6, 9, 12, 15, 16, 21, 25, 26, 28, 30, 31, 32], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_switch_fingerprint_active_profile.DummyFingerprintManager.__init__": {"executed_lines": [7], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_switch_fingerprint_active_profile.DummyFingerprintManager.list_fingerprints": {"executed_lines": [10], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_switch_fingerprint_active_profile.DummyFingerprintManager.display_name": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_switch_fingerprint_active_profile.DummyPM.__init__": {"executed_lines": [17, 18, 19], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_switch_fingerprint_active_profile.DummyPM.select_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [22, 23], "excluded_lines": []}, "": {"executed_lines": [1, 4], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_handle_switch_fingerprint_active_profile.DummyFingerprintManager": {"executed_lines": [7, 10, 13], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_switch_fingerprint_active_profile.DummyPM": {"executed_lines": [17, 18, 19], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [22, 23], "excluded_lines": []}, "": {"executed_lines": [1, 4, 5, 6, 9, 12, 15, 16, 21, 25, 26, 28, 30, 31, 32], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_import.py": {"executed_lines": [3, 4, 6], "summary": {"covered_lines": 3, "num_statements": 7, "percent_covered": 42.857142857142854, "percent_covered_display": "43", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [7, 8, 9, 10], "excluded_lines": [], "functions": {"": {"executed_lines": [3, 4, 6], "summary": {"covered_lines": 3, "num_statements": 7, "percent_covered": 42.857142857142854, "percent_covered_display": "43", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [7, 8, 9, 10], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 4, 6], "summary": {"covered_lines": 3, "num_statements": 7, "percent_covered": 42.857142857142854, "percent_covered_display": "43", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [7, 8, 9, 10], "excluded_lines": []}}}, "src/tests/test_inactivity_lock.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13, 14, 16, 17, 19, 20, 22, 23, 24, 26, 41, 43, 44, 46, 47, 50, 52, 54, 55, 57, 58, 60, 61, 62, 64, 79, 81, 82, 83, 84, 85, 87, 89, 90, 92, 93, 96, 98, 100, 101, 103, 104, 105, 106, 107, 109, 110, 111, 113, 114, 116, 117, 118, 120, 121, 122], "summary": {"covered_lines": 63, "num_statements": 63, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_inactivity_triggers_lock": {"executed_lines": [14, 16, 19, 22, 26, 41, 43, 44, 46, 47], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_inactivity_triggers_lock.update_activity": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_inactivity_triggers_lock.lock_vault": {"executed_lines": [20], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_inactivity_triggers_lock.unlock_vault": {"executed_lines": [23, 24], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_input_timeout_triggers_lock": {"executed_lines": [52, 54, 57, 60, 64, 79, 81, 87, 89, 90, 92, 93], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_input_timeout_triggers_lock.update_activity": {"executed_lines": [55], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_input_timeout_triggers_lock.lock_vault": {"executed_lines": [58], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_input_timeout_triggers_lock.unlock_vault": {"executed_lines": [61, 62], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_input_timeout_triggers_lock.fake_input": {"executed_lines": [82, 83, 84, 85], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_activity_checks_timeout": {"executed_lines": [98, 100, 101, 103, 104, 105, 106, 107, 109, 113, 114, 116, 117, 118, 120, 121, 122], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_activity_checks_timeout.lock": {"executed_lines": [110, 111], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13, 50, 96], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 13, 14, 16, 17, 19, 20, 22, 23, 24, 26, 41, 43, 44, 46, 47, 50, 52, 54, 55, 57, 58, 60, 61, 62, 64, 79, 81, 82, 83, 84, 85, 87, 89, 90, 92, 93, 96, 98, 100, 101, 103, 104, 105, 106, 107, 109, 110, 111, 113, 114, 116, 117, 118, 120, 121, 122], "summary": {"covered_lines": 63, "num_statements": 63, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_index_cache.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 19, 20, 22, 23, 24, 26, 27, 28, 30, 31, 32, 33], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_index_caching": {"executed_lines": [12, 13, 14, 15, 16, 19, 20, 22, 23, 24, 26, 27, 28, 30, 31, 32, 33], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 11], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 19, 20, 22, 23, 24, 26, 27, 28, 30, 31, 32, 33], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_index_import_export.py": {"executed_lines": [1, 2, 4, 5, 6, 7, 9, 11, 12, 13, 15, 16, 19, 20, 21, 22, 23, 25, 26, 27, 30, 31, 32, 33, 35, 48, 50, 51, 53, 68, 70, 71, 74, 75, 76], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_vault": {"executed_lines": [20, 21, 22, 23, 25, 26, 27], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_index_export_import_round_trip": {"executed_lines": [31, 32, 33, 35, 48, 50, 51, 53, 68, 70, 71], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_encrypted_index_missing_file": {"executed_lines": [75, 76], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 6, 7, 9, 11, 12, 13, 15, 16, 19, 30, 74], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 6, 7, 9, 11, 12, 13, 15, 16, 19, 20, 21, 22, 23, 25, 26, 27, 30, 31, 32, 33, 35, 48, 50, 51, 53, 68, 70, 71, 74, 75, 76], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_invalid_password_message.py": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_invalid_password_shows_friendly_message_once": {"executed_lines": [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_kdf_iteration_fallback.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 21, 22, 24, 25, 26, 27, 28, 29, 32, 33, 35, 36, 38, 39, 40, 41, 42, 43, 45, 49, 50, 51], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_kdf_iteration_fallback": {"executed_lines": [15, 16, 17, 18, 19, 21, 22, 24, 25, 26, 27, 28, 29, 32, 33, 35, 36, 38, 39, 40, 41, 42, 43, 45, 49, 50, 51], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 14], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 21, 22, 24, 25, 26, 27, 28, 29, 32, 33, 35, 36, 38, 39, 40, 41, 42, 43, 45, 49, 50, 51], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_kdf_modes.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 14, 15, 16, 17, 19, 20, 23, 24, 25, 26, 27, 33, 34, 36, 37, 44, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 60, 61, 62, 63, 64, 65, 66, 67, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 83, 84, 90, 91, 94, 95, 98, 99, 103, 104, 105, 106, 107, 110, 111, 112, 113, 114, 115, 116, 117, 118], "summary": {"covered_lines": 73, "num_statements": 73, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_setup_profile": {"executed_lines": [24, 25, 26, 27, 33, 34, 36, 37, 44, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_make_pm": {"executed_lines": [61, 62, 63, 64, 65, 66, 67], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_setup_encryption_manager_kdf_modes": {"executed_lines": [71, 72, 73, 74, 75, 76, 77, 78, 79, 83, 84, 90, 91, 94, 95], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_kdf_param_round_trip": {"executed_lines": [99, 103, 104, 105, 106, 107], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_kdf_migration": {"executed_lines": [111, 112, 113, 114, 115, 116, 117, 118], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 14, 15, 16, 17, 19, 20, 23, 60, 70, 98, 110], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 14, 15, 16, 17, 19, 20, 23, 24, 25, 26, 27, 33, 34, 36, 37, 44, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 60, 61, 62, 63, 64, 65, 66, 67, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 83, 84, 90, 91, 94, 95, 98, 99, 103, 104, 105, 106, 107, 110, 111, 112, 113, 114, 115, 116, 117, 118], "summary": {"covered_lines": 73, "num_statements": 73, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_kdf_strength_slider.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_kdf_strength_slider_persists": {"executed_lines": [11, 12, 13, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 10], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_key_derivation.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 28, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 45, 46, 47, 50, 51, 52, 53, 55, 59, 63, 64, 65, 67, 68, 69], "summary": {"covered_lines": 43, "num_statements": 43, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_pbkdf2_fingerprint_affects_key": {"executed_lines": [17, 18, 19, 21, 22, 23, 25, 26, 27, 28], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_derive_key_empty_password_error": {"executed_lines": [32, 33, 34], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_seed_only_key_deterministic": {"executed_lines": [38, 39, 40, 41, 42], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_derive_index_key_seed_only": {"executed_lines": [46, 47], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_argon2_fingerprint_affects_key": {"executed_lines": [51, 52, 53, 55, 59, 63, 64, 65, 67, 68, 69], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 16, 31, 37, 45, 50], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 28, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 45, 46, 47, 50, 51, 52, 53, 55, 59, 63, 64, 65, 67, 68, 69], "summary": {"covered_lines": 43, "num_statements": 43, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_key_hierarchy.py": {"executed_lines": [1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_kd_distinct_infos": {"executed_lines": [8, 9, 10, 11], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_derive_index_key_matches_hierarchy": {"executed_lines": [15, 16, 17, 18, 19], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 7, 14], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_key_manager_helpers.py": {"executed_lines": [1, 2, 4, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19, 21, 23, 24, 26, 29], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_key_manager_getters": {"executed_lines": [8, 9, 11, 12, 15, 18, 19, 21, 23, 24, 26, 29], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_key_manager_getters.DummyKeys.public_key_hex": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_key_manager_getters.DummyKeys.private_key_hex": {"executed_lines": [16], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 7], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_key_manager_getters.DummyKeys": {"executed_lines": [13, 16], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 7, 8, 9, 11, 12, 15, 18, 19, 21, 23, 24, 26, 29], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_key_validation_failures.py": {"executed_lines": [1, 2, 4, 6, 7, 8, 11, 12, 13, 14, 15, 18, 19, 20, 21, 24, 25, 26, 29, 30, 33, 34, 35, 38, 39, 42, 43, 44, 47, 48, 51, 52, 53, 56, 57, 60, 61, 62, 65, 66], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_mgr": {"executed_lines": [12, 13, 14, 15], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_totp_invalid_secret": {"executed_lines": [19, 20, 21], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_ssh_key_validation_failure": {"executed_lines": [25, 26, 29, 30], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_pgp_key_validation_failure": {"executed_lines": [34, 35, 38, 39], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_nostr_key_validation_failure": {"executed_lines": [43, 44, 47, 48], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_seed_validation_failure": {"executed_lines": [52, 53, 56, 57], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_managed_account_validation_failure": {"executed_lines": [61, 62, 65, 66], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 8, 11, 18, 24, 33, 42, 51, 60], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 7, 8, 11, 12, 13, 14, 15, 18, 19, 20, 21, 24, 25, 26, 29, 30, 33, 34, 35, 38, 39, 42, 43, 44, 47, 48, 51, 52, 53, 56, 57, 60, 61, 62, 65, 66], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_key_value_entry.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 24, 26, 27, 28, 41, 44, 45, 46, 47, 50, 51, 52, 53, 54, 59, 60, 61, 62, 65, 66], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_entry_mgr": {"executed_lines": [15, 16, 17, 18], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_and_modify_key_value": {"executed_lines": [22, 23, 24, 26, 27, 28, 41, 44, 45, 46, 47, 50, 51, 52, 53, 54, 59, 60, 61, 62, 65, 66], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 21], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 24, 26, 27, 28, 41, 44, 45, 46, 47, 50, 51, 52, 53, 54, 59, 60, 61, 62, 65, 66], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_last_used_fingerprint.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 13, 14, 15, 16, 18, 19, 21, 22, 23, 26, 27, 29, 30, 32, 35, 40, 43, 46, 51, 54, 59, 60], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_last_used_fingerprint": {"executed_lines": [14, 15, 16, 18, 19, 21, 22, 23, 26, 27, 29, 32, 35, 40, 43, 46, 51, 54, 59, 60], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_last_used_fingerprint.init_fm": {"executed_lines": [30], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 13], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 13, 14, 15, 16, 18, 19, 21, 22, 23, 26, 27, 29, 30, 32, 35, 40, 43, 46, 51, 54, 59, 60], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_legacy_format_exception.py": {"executed_lines": [1, 2, 4, 5, 7, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 29, 30, 31, 33, 34, 36, 37, 41, 42, 43], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_decrypt_data_raises_legacy_exception": {"executed_lines": [16, 17, 18, 19], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_handles_legacy_exception": {"executed_lines": [23, 24, 25, 26, 29, 30, 31, 33, 34, 36, 37, 41, 42, 43], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 7, 12, 15, 22], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 7, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 29, 30, 31, 33, 34, 36, 37, 41, 42, 43], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_legacy_migration.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 13, 15, 16, 17, 20, 21, 23, 24, 39, 40, 41, 42, 46, 48, 49, 51, 52, 53, 54, 55, 56, 59, 60, 62, 63, 64, 65, 66, 67, 68, 70, 72, 75, 77, 78, 81, 82, 83, 84, 87, 88, 90, 91, 92, 93, 94, 95, 99, 101, 103, 104, 105, 106, 109, 110, 112, 113, 114, 116, 117, 118, 122, 123, 125, 128, 129, 130, 133, 134, 136, 137, 138, 141, 142, 144, 145, 146, 147, 148, 150, 152, 153, 154, 155, 156, 157, 158, 159, 160, 162, 163, 164, 165, 166, 167, 169, 170, 176, 179, 181, 182, 183, 186, 187, 189, 190, 191, 192, 193, 195, 197, 198, 199, 200, 201, 202, 203, 204, 206, 207, 213, 216, 218, 219, 220, 223, 224, 226, 227, 228, 229, 231, 232, 233, 234, 235, 237, 238, 240, 244, 247, 248, 249, 250, 251, 252, 253, 254, 255, 257, 259, 260, 261, 263, 264, 266, 267, 268, 269, 272, 273, 275, 276, 277, 278, 279, 281, 283, 284, 285, 286, 287, 288, 289, 290, 291, 293, 297, 298, 304, 306, 307, 309, 310, 313, 314, 316, 317, 318, 319, 321, 322, 323, 324, 325, 326, 327, 328, 329, 331, 332, 333, 334, 335, 336, 338, 340, 346, 350, 354, 356, 357, 358, 359, 362, 363, 365, 366, 367, 368, 369, 371, 373, 374, 375, 376, 377, 378, 379, 380, 382, 384, 388, 390, 391, 393, 396, 397, 399, 400, 401, 402, 403, 405, 407, 408, 410, 412, 413, 414, 415, 416, 417, 418, 419, 421, 423, 427, 429, 430, 432], "summary": {"covered_lines": 271, "num_statements": 279, "percent_covered": 97.1326164874552, "percent_covered_display": "97", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [73, 245, 351, 352, 385, 386, 424, 425], "excluded_lines": [], "functions": {"test_legacy_index_migrates": {"executed_lines": [21, 23, 24, 39, 40, 41, 42, 46, 48, 49, 51, 52, 53, 54, 55, 56], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_failed_migration_restores_legacy": {"executed_lines": [60, 62, 63, 64, 65, 66, 67, 68, 70, 72, 75, 77, 78, 81, 82, 83, 84], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_failed_migration_restores_legacy.bad_load_json": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [73], "excluded_lines": []}, "test_migrated_index_has_v3_prefix": {"executed_lines": [88, 90, 91, 92, 93, 94, 95, 99, 101, 103, 104, 105, 106], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_index_migration_removes_strays": {"executed_lines": [110, 112, 113, 114, 116, 117, 118, 122, 123, 125, 128, 129, 130, 133, 134, 136, 137, 138], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migration_syncs_when_confirmed": {"executed_lines": [142, 144, 145, 146, 147, 148, 150, 152, 153, 154, 155, 156, 157, 158, 159, 160, 162, 163, 164, 165, 166, 167, 169, 170, 176, 179, 181, 182, 183], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migration_declines_sync": {"executed_lines": [187, 189, 190, 191, 192, 193, 195, 197, 198, 199, 200, 201, 202, 203, 204, 206, 207, 213, 216, 218, 219, 220], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_nostr_payload_syncs_when_confirmed": {"executed_lines": [224, 226, 227, 228, 229, 231, 232, 237, 244, 247, 248, 249, 250, 251, 252, 253, 254, 255, 257, 259, 263, 264, 266, 267, 268, 269], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_nostr_payload_syncs_when_confirmed.DummyClient.__init__": {"executed_lines": [233, 234, 235], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_nostr_payload_syncs_when_confirmed.DummyClient.fetch_latest_snapshot": {"executed_lines": [238, 240], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_nostr_payload_syncs_when_confirmed.DummyClient.fetch_deltas_since": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [245], "excluded_lines": []}, "test_legacy_nostr_payload_syncs_when_confirmed.fake_sync_vault_async": {"executed_lines": [260, 261], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_index_reinit_syncs_once_when_confirmed": {"executed_lines": [273, 275, 276, 277, 278, 279, 281, 283, 284, 285, 286, 287, 288, 289, 290, 291, 293, 297, 298, 304, 306, 307, 309, 310], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_schema_migration_no_sync_prompt": {"executed_lines": [314, 316, 317, 318, 319, 321, 322, 323, 324, 325, 326, 327, 328, 329, 331, 332, 333, 334, 335, 336, 338, 340, 346, 350, 354, 356, 357, 358, 359], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_schema_migration_no_sync_prompt.fake_confirm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [351, 352], "excluded_lines": []}, "test_declined_migration_no_sync_prompt": {"executed_lines": [363, 365, 366, 367, 368, 369, 371, 373, 374, 375, 376, 377, 378, 379, 380, 382, 384, 388, 390, 391, 393], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_declined_migration_no_sync_prompt.fake_confirm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [385, 386], "excluded_lines": []}, "test_failed_migration_no_sync_prompt": {"executed_lines": [397, 399, 400, 401, 402, 403, 405, 407, 410, 412, 413, 414, 415, 416, 417, 418, 419, 421, 423, 427, 429, 430, 432], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_failed_migration_no_sync_prompt.fail": {"executed_lines": [408], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_failed_migration_no_sync_prompt.fake_confirm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [424, 425], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 13, 15, 16, 17, 20, 59, 87, 109, 141, 186, 223, 272, 313, 362, 396], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_legacy_nostr_payload_syncs_when_confirmed.DummyClient": {"executed_lines": [233, 234, 235, 238, 240], "summary": {"covered_lines": 5, "num_statements": 6, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [245], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 13, 15, 16, 17, 20, 21, 23, 24, 39, 40, 41, 42, 46, 48, 49, 51, 52, 53, 54, 55, 56, 59, 60, 62, 63, 64, 65, 66, 67, 68, 70, 72, 75, 77, 78, 81, 82, 83, 84, 87, 88, 90, 91, 92, 93, 94, 95, 99, 101, 103, 104, 105, 106, 109, 110, 112, 113, 114, 116, 117, 118, 122, 123, 125, 128, 129, 130, 133, 134, 136, 137, 138, 141, 142, 144, 145, 146, 147, 148, 150, 152, 153, 154, 155, 156, 157, 158, 159, 160, 162, 163, 164, 165, 166, 167, 169, 170, 176, 179, 181, 182, 183, 186, 187, 189, 190, 191, 192, 193, 195, 197, 198, 199, 200, 201, 202, 203, 204, 206, 207, 213, 216, 218, 219, 220, 223, 224, 226, 227, 228, 229, 231, 232, 237, 244, 247, 248, 249, 250, 251, 252, 253, 254, 255, 257, 259, 260, 261, 263, 264, 266, 267, 268, 269, 272, 273, 275, 276, 277, 278, 279, 281, 283, 284, 285, 286, 287, 288, 289, 290, 291, 293, 297, 298, 304, 306, 307, 309, 310, 313, 314, 316, 317, 318, 319, 321, 322, 323, 324, 325, 326, 327, 328, 329, 331, 332, 333, 334, 335, 336, 338, 340, 346, 350, 354, 356, 357, 358, 359, 362, 363, 365, 366, 367, 368, 369, 371, 373, 374, 375, 376, 377, 378, 379, 380, 382, 384, 388, 390, 391, 393, 396, 397, 399, 400, 401, 402, 403, 405, 407, 408, 410, 412, 413, 414, 415, 416, 417, 418, 419, 421, 423, 427, 429, 430, 432], "summary": {"covered_lines": 266, "num_statements": 273, "percent_covered": 97.43589743589743, "percent_covered_display": "97", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [73, 351, 352, 385, 386, 424, 425], "excluded_lines": []}}}, "src/tests/test_legacy_migration_iterations.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 31, 32, 33, 35, 36, 37, 39, 41, 42, 43, 45, 46, 47, 49, 50, 52, 53, 54, 56, 58, 60, 62, 63, 64, 66, 67, 69, 70], "summary": {"covered_lines": 48, "num_statements": 48, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_setup_legacy_file": {"executed_lines": [23, 24, 25, 26, 27, 28], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migrate_iterations": {"executed_lines": [33, 35, 36, 37, 39, 41, 45, 46, 47, 49, 50, 52, 56, 58, 60, 62, 63, 64, 66, 67, 69, 70], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migrate_iterations.fake_prompt": {"executed_lines": [42, 43], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migrate_iterations.tracking_derive": {"executed_lines": [53, 54], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 17, 18, 19, 22, 31, 32], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 31, 32, 33, 35, 36, 37, 39, 41, 42, 43, 45, 46, 47, 49, 50, 52, 53, 54, 56, 58, 60, 62, 63, 64, 66, 67, 69, 70], "summary": {"covered_lines": 48, "num_statements": 48, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_legacy_migration_prompt.py": {"executed_lines": [1, 2, 3, 5, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 25, 26, 27, 28, 29, 30, 31, 34, 35, 36, 37, 38, 41, 42, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 55], "summary": {"covered_lines": 41, "num_statements": 41, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_setup_legacy_file": {"executed_lines": [15, 16, 17, 18, 19, 20, 21, 22], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_open_legacy_without_migrating": {"executed_lines": [26, 27, 28, 29, 30, 31, 34, 35, 36, 37, 38], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migrate_legacy_sets_flag": {"executed_lines": [42, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 55], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 9, 10, 11, 14, 25, 41], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 25, 26, 27, 28, 29, 30, 31, 34, 35, 36, 37, 38, 41, 42, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 55], "summary": {"covered_lines": 41, "num_statements": 41, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_legacy_migration_second_session.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 32, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 58, 59, 63, 64, 65], "summary": {"covered_lines": 45, "num_statements": 45, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [55, 56], "functions": {"test_legacy_migration_second_session": {"executed_lines": [18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 32, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 58, 59, 63, 64, 65], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [55]}, "test_legacy_migration_second_session.fail_prompt": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [56]}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 17], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 32, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 58, 59, 63, 64, 65], "summary": {"covered_lines": 45, "num_statements": 45, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [55, 56]}}}, "src/tests/test_list_entries_all_types.py": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 44, 45, 48, 49, 50, 51, 52, 54, 55, 63, 65, 66, 67, 68, 69, 70, 73, 74, 75, 76, 77, 79, 80, 82, 83, 84, 85], "summary": {"covered_lines": 62, "num_statements": 62, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_setup_manager": {"executed_lines": [19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_create_all_entries": {"executed_lines": [38, 39, 40, 41, 42, 43, 44, 45], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_list_all_types": {"executed_lines": [49, 50, 51, 52, 54, 63, 65, 66, 67, 68, 69, 70], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_cli_list_all_types.fake_get_entry_service": {"executed_lines": [55], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_list_all_types": {"executed_lines": [74, 75, 76, 77, 79, 80, 82, 83, 84, 85], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 15, 18, 37, 48, 73], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 44, 45, 48, 49, 50, 51, 52, 54, 55, 63, 65, 66, 67, 68, 69, 70, 73, 74, 75, 76, 77, 79, 80, 82, 83, 84, 85], "summary": {"covered_lines": 62, "num_statements": 62, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_list_entries_sort_filter.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 47, 48, 54, 55, 56, 57, 58, 59, 60, 61], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_entry_manager": {"executed_lines": [16, 17, 18, 19], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sort_by_label": {"executed_lines": [23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sort_by_updated": {"executed_lines": [36, 37, 38, 39, 40, 42, 43, 44, 45, 47, 48], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_filter_by_type": {"executed_lines": [55, 56, 57, 58, 59, 60, 61], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 22, 35, 54], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 47, 48, 54, 55, 56, 57, 58, 59, 60, 61], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_load_global_config.py": {"executed_lines": [1, 3, 4, 6, 8, 11, 13, 14, 15, 16, 18, 20, 21, 23, 24], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_load_global_config_invalid_toml": {"executed_lines": [13, 14, 15, 16, 18, 20, 21, 23, 24], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 6, 8, 11], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 6, 8, 11, 13, 14, 15, 16, 18, 20, 21, 23, 24], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_managed_account.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 12, 13, 14, 17, 18, 19, 20, 21, 24, 25, 26, 27, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 46, 47, 48, 49, 50, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 78, 79, 80, 81, 83, 85, 86, 87], "summary": {"covered_lines": 69, "num_statements": 69, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_entry_manager": {"executed_lines": [18, 19, 20, 21], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_managed_account_fields_and_dir": {"executed_lines": [25, 26, 27, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_load_and_exit_managed_account": {"executed_lines": [47, 48, 49, 50, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 78, 79, 80, 81, 83, 85, 86, 87], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 12, 13, 14, 17, 24, 46], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 12, 13, 14, 17, 18, 19, 20, 21, 24, 25, 26, 27, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 46, 47, 48, 49, 50, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 78, 79, 80, 81, 83, 85, 86, 87], "summary": {"covered_lines": 69, "num_statements": 69, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_managed_account_entry.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 12, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 45, 47, 48, 49, 51, 52, 53, 54, 55, 58, 59, 60, 61, 62, 67, 68, 69, 70, 71, 72, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 105, 107, 108, 109, 110, 112, 114, 115, 116], "summary": {"covered_lines": 90, "num_statements": 90, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_mgr": {"executed_lines": [21, 22, 23, 24], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_and_get_managed_account_seed": {"executed_lines": [28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 45, 47, 48, 49, 51, 52, 53, 54, 55, 58, 59, 60, 61, 62, 67, 68, 69, 70, 71, 72], "summary": {"covered_lines": 34, "num_statements": 34, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_load_and_exit_managed_account": {"executed_lines": [76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 105, 107, 108, 109, 110, 112, 114, 115, 116], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 12, 13, 14, 15, 16, 17, 20, 27, 75], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 12, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 45, 47, 48, 49, 51, 52, 53, 54, 55, 58, 59, 60, 61, 62, 67, 68, 69, 70, 71, 72, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 105, 107, 108, 109, 110, 112, 114, 115, 116], "summary": {"covered_lines": 90, "num_statements": 90, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_add_password.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 13, 14, 15, 16, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 66, 67, 68, 70, 71, 73, 74, 76, 77, 90, 93, 94, 95, 96, 97, 98, 99, 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 136, 137, 138, 140, 141, 146, 147, 149, 150, 151, 154, 155, 156, 157, 158, 159, 160, 161, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 176, 186, 187, 188, 190, 191, 193, 194, 196, 197, 210, 213, 216, 217, 218, 219, 220, 221, 222, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 237, 249, 250, 251, 253, 254, 256, 257, 258, 259, 260, 261, 264, 267, 268, 269, 270, 271, 272, 273, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 288, 299, 300, 301, 303, 304, 306, 307, 308, 311, 312, 313, 314, 315, 316, 317, 318, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 333, 334, 335, 337, 338], "summary": {"covered_lines": 195, "num_statements": 195, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakePasswordGenerator.generate_password": {"executed_lines": [21], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_add_password": {"executed_lines": [25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 66, 67, 68, 70, 71, 73, 74, 76, 77, 90], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_add_password_secret_mode": {"executed_lines": [94, 95, 96, 97, 98, 99, 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 136, 137, 138, 140, 141, 146, 147, 149, 150, 151], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_add_password_quick_mode": {"executed_lines": [155, 156, 157, 158, 159, 160, 161, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 176, 186, 187, 188, 190, 191, 193, 194, 196, 197, 210], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_add_password_quick_mode_reprompts_invalid_length": {"executed_lines": [216, 217, 218, 219, 220, 221, 222, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 237, 249, 250, 251, 253, 254, 256, 257, 258, 259, 260, 261], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_add_password_reprompts_invalid_mode": {"executed_lines": [267, 268, 269, 270, 271, 272, 273, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 288, 299, 300, 301, 303, 304, 306, 307, 308], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_add_password_empty_mode_cancels": {"executed_lines": [312, 313, 314, 315, 316, 317, 318, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 333, 334, 335, 337, 338], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 13, 14, 15, 16, 19, 20, 24, 93, 154, 213, 264, 311], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakePasswordGenerator": {"executed_lines": [21], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 13, 14, 15, 16, 19, 20, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 66, 67, 68, 70, 71, 73, 74, 76, 77, 90, 93, 94, 95, 96, 97, 98, 99, 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 136, 137, 138, 140, 141, 146, 147, 149, 150, 151, 154, 155, 156, 157, 158, 159, 160, 161, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 176, 186, 187, 188, 190, 191, 193, 194, 196, 197, 210, 213, 216, 217, 218, 219, 220, 221, 222, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 237, 249, 250, 251, 253, 254, 256, 257, 258, 259, 260, 261, 264, 267, 268, 269, 270, 271, 272, 273, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 288, 299, 300, 301, 303, 304, 306, 307, 308, 311, 312, 313, 314, 315, 316, 317, 318, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 333, 334, 335, 337, 338], "summary": {"covered_lines": 194, "num_statements": 194, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_add_totp.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 18, 20, 21, 22, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 54, 55, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70], "summary": {"covered_lines": 47, "num_statements": 47, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakeNostrClient.__init__": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostrClient.publish_snapshot": {"executed_lines": [21, 22], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_add_totp": {"executed_lines": [26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 54, 55, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 20, 25], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeNostrClient": {"executed_lines": [18, 21, 22], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 20, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 54, 55, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70], "summary": {"covered_lines": 44, "num_statements": 44, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_checksum_backup.py": {"executed_lines": [1, 2, 4, 6, 7, 10, 11, 12, 14, 15, 17, 18, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 41, 42, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 56, 57, 59, 60, 61, 62, 63, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77], "summary": {"covered_lines": 59, "num_statements": 59, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakeBackupManager.__init__": {"executed_lines": [12], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeBackupManager.create_backup": {"executed_lines": [15], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeBackupManager.restore_latest_backup": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_make_pm": {"executed_lines": [22, 23, 24, 25], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_verify_checksum_success": {"executed_lines": [29, 30, 31, 32, 33, 34, 35, 36], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_verify_checksum_failure": {"executed_lines": [40, 41, 42, 43, 44, 45, 46, 47], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_verify_checksum_missing": {"executed_lines": [51, 52, 53, 54, 56, 59, 60, 61, 62, 63], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_verify_checksum_missing.raise_missing": {"executed_lines": [57], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_backup_and_restore_database": {"executed_lines": [67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 10, 11, 14, 17, 21, 28, 39, 50, 66], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeBackupManager": {"executed_lines": [12, 15, 18], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 10, 11, 14, 17, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 41, 42, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 56, 57, 59, 60, 61, 62, 63, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77], "summary": {"covered_lines": 56, "num_statements": 56, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_current_notification.py": {"executed_lines": [1, 3, 4, 6, 8, 9, 12, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 38, 39, 41, 42, 44, 45], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [13, 14, 15, 16, 17], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_notify_sets_current": {"executed_lines": [21, 22, 23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_get_current_notification_ttl": {"executed_lines": [33, 34, 35, 36, 38, 39, 41, 42, 44, 45], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 6, 8, 9, 12, 20, 32], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 6, 8, 9, 12, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 38, 39, 41, 42, 44, 45], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_display_totp_codes.py": {"executed_lines": [1, 2, 4, 6, 9, 10, 11, 13, 18, 19, 20, 22, 24, 28, 31, 36, 37, 38, 39, 40, 43, 44, 45, 47, 48, 49, 51, 55, 57, 62, 63, 64, 65], "summary": {"covered_lines": 33, "num_statements": 35, "percent_covered": 94.28571428571429, "percent_covered_display": "94", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [14, 15], "excluded_lines": [], "functions": {"FakeNostrClient.__init__": {"executed_lines": [11], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostrClient.publish_snapshot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [14, 15], "excluded_lines": []}, "test_handle_display_totp_codes": {"executed_lines": [19, 20, 22, 24, 28, 31, 36, 37, 38, 39, 40], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_display_totp_codes_excludes_archived": {"executed_lines": [44, 45, 47, 48, 49, 51, 55, 57, 62, 63, 64, 65], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 9, 10, 13, 18, 43], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeNostrClient": {"executed_lines": [11], "summary": {"covered_lines": 1, "num_statements": 3, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [14, 15], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 9, 10, 13, 18, 19, 20, 22, 24, 28, 31, 36, 37, 38, 39, 40, 43, 44, 45, 47, 48, 49, 51, 55, 57, 62, 63, 64, 65], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_edit_totp.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 19, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 46, 47, 48, 49, 52, 53, 55, 56, 57], "summary": {"covered_lines": 41, "num_statements": 43, "percent_covered": 95.34883720930233, "percent_covered_display": "95", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [20, 21], "excluded_lines": [], "functions": {"FakeNostrClient.__init__": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostrClient.publish_snapshot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [20, 21], "excluded_lines": []}, "test_edit_totp_period_from_retrieve": {"executed_lines": [25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 46, 47, 48, 49, 52, 53, 55, 56, 57], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 19, 24], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeNostrClient": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 3, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [20, 21], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 19, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 46, 47, 48, 49, 52, 53, 55, 56, 57], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_import_database.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 28, 31, 32, 36, 37, 38, 39, 42, 43, 45, 46, 48, 49, 53, 54, 55], "summary": {"covered_lines": 36, "num_statements": 37, "percent_covered": 97.29729729729729, "percent_covered_display": "97", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [29], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [12, 13, 14, 15, 16, 17, 18, 19, 20, 21], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_import_non_backup_file": {"executed_lines": [25, 26, 28, 31, 32, 36, 37, 38, 39], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_import_non_backup_file.fake_import": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [29], "excluded_lines": []}, "test_import_missing_file": {"executed_lines": [43, 45, 48, 49, 53, 54, 55], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_import_missing_file.raise_missing": {"executed_lines": [46], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 24, 42], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 28, 31, 32, 36, 37, 38, 39, 42, 43, 45, 46, 48, 49, 53, 54, 55], "summary": {"covered_lines": 36, "num_statements": 37, "percent_covered": 97.29729729729729, "percent_covered_display": "97", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [29], "excluded_lines": []}}}, "src/tests/test_manager_list_entries.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 47, 48, 49, 50, 51, 52, 55, 56, 57, 58, 59, 60, 61, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 78, 79, 82, 83, 88, 89, 91, 92, 93, 94, 95, 96, 99, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113, 114, 115, 116, 118, 120, 121, 126, 127, 132, 137, 138, 141, 142, 144, 146, 147, 150, 151, 152, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 169, 170, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 190, 192, 194, 195, 196, 197, 198, 199, 200, 203, 204, 205, 206, 207, 208, 209, 210, 211, 213, 215, 216, 217, 218, 219, 220, 221, 222, 225, 226, 227, 228, 229, 230, 232, 234, 235, 236, 237, 238, 239, 240, 241, 242, 245, 246, 247, 248, 249, 251, 253, 254, 255, 256, 257, 258, 261, 262, 263, 264, 265, 266, 268, 270, 271, 272, 273, 274, 275, 276, 277, 280, 293, 295, 296, 297, 298, 300, 303, 306, 307, 308, 311, 315, 317, 318, 320, 321, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 352, 355, 356, 357, 358, 360, 361, 363, 364, 365, 366, 367, 368, 371, 374, 376, 377, 378, 380, 381, 382, 383, 384, 385, 386, 390, 393, 395, 396, 398, 399, 400, 402, 403, 404, 405, 406], "summary": {"covered_lines": 282, "num_statements": 282, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_handle_list_entries": {"executed_lines": [21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 47, 48, 49, 50, 51, 52], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_list_entries_show_details": {"executed_lines": [56, 57, 58, 59, 60, 61, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 78, 79, 82, 83, 88, 89, 91, 92, 93, 94, 95, 96], "summary": {"covered_lines": 31, "num_statements": 31, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_entry_details_by_index": {"executed_lines": [101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113, 114, 115, 116, 118, 120, 121, 126, 127, 132, 137, 138, 141, 142, 144, 146, 147], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_setup_manager": {"executed_lines": [151, 152, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_detail_common": {"executed_lines": [170, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_seed_entry_details": {"executed_lines": [187, 188, 189, 190, 192, 194, 195, 196, 197, 198, 199, 200], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_ssh_entry_details": {"executed_lines": [204, 205, 206, 207, 208, 209, 210, 211, 213, 215, 216, 217, 218, 219, 220, 221, 222], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_pgp_entry_details": {"executed_lines": [226, 227, 228, 229, 230, 232, 234, 235, 236, 237, 238, 239, 240, 241, 242], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_nostr_entry_details": {"executed_lines": [246, 247, 248, 249, 251, 253, 254, 255, 256, 257, 258], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_managed_account_entry_details": {"executed_lines": [262, 263, 264, 265, 266, 268, 270, 271, 272, 273, 274, 275, 276, 277], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_entry_details_sensitive": {"executed_lines": [295, 296, 297, 298, 300, 303, 306, 307, 308, 311, 315, 317, 318, 320, 321, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 352, 355, 356, 357, 358, 360, 361, 363, 364, 365, 366, 367, 368], "summary": {"covered_lines": 52, "num_statements": 52, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_entry_details_with_enum_type": {"executed_lines": [376, 377, 378, 380, 381, 382, 383, 384, 385, 386, 390, 393, 395, 396, 398, 399, 400, 402, 403, 404, 405, 406], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 13, 14, 15, 16, 17, 20, 55, 99, 150, 169, 186, 203, 225, 245, 261, 280, 293, 371, 374], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 47, 48, 49, 50, 51, 52, 55, 56, 57, 58, 59, 60, 61, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 78, 79, 82, 83, 88, 89, 91, 92, 93, 94, 95, 96, 99, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113, 114, 115, 116, 118, 120, 121, 126, 127, 132, 137, 138, 141, 142, 144, 146, 147, 150, 151, 152, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 169, 170, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 190, 192, 194, 195, 196, 197, 198, 199, 200, 203, 204, 205, 206, 207, 208, 209, 210, 211, 213, 215, 216, 217, 218, 219, 220, 221, 222, 225, 226, 227, 228, 229, 230, 232, 234, 235, 236, 237, 238, 239, 240, 241, 242, 245, 246, 247, 248, 249, 251, 253, 254, 255, 256, 257, 258, 261, 262, 263, 264, 265, 266, 268, 270, 271, 272, 273, 274, 275, 276, 277, 280, 293, 295, 296, 297, 298, 300, 303, 306, 307, 308, 311, 315, 317, 318, 320, 321, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 352, 355, 356, 357, 358, 360, 361, 363, 364, 365, 366, 367, 368, 371, 374, 376, 377, 378, 380, 381, 382, 383, 384, 385, 386, 390, 393, 395, 396, 398, 399, 400, 402, 403, 404, 405, 406], "summary": {"covered_lines": 282, "num_statements": 282, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_retrieve_totp.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 19, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 46, 47, 48, 52, 55, 56, 61, 62, 63, 64], "summary": {"covered_lines": 42, "num_statements": 44, "percent_covered": 95.45454545454545, "percent_covered_display": "95", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [20, 21], "excluded_lines": [], "functions": {"FakeNostrClient.__init__": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostrClient.publish_snapshot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [20, 21], "excluded_lines": []}, "test_handle_retrieve_totp_entry": {"executed_lines": [25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 46, 47, 48, 52, 55, 56, 61, 62, 63, 64], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 19, 24], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeNostrClient": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 3, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [20, 21], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 19, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 46, 47, 48, 52, 55, 56, 61, 62, 63, 64], "summary": {"covered_lines": 41, "num_statements": 41, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_search_display.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 37, 38, 41, 42, 44, 45, 47, 48, 49, 50, 51], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_search_entries_prompt_for_details": {"executed_lines": [17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 37, 38, 41, 42, 44, 45, 47, 48, 49, 50, 51], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 37, 38, 41, 42, 44, 45, 47, 48, 49, 50, 51], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_seed_setup.py": {"executed_lines": [1, 2, 3, 4, 7, 8, 9, 10, 13, 14, 16, 19, 20, 21, 22, 25, 26, 27, 28, 29, 30, 35, 36, 38, 39, 41, 42, 45, 46, 47, 49, 51, 52, 53, 55, 56, 62, 63, 65, 66, 67, 70, 71, 72, 74, 76, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91], "summary": {"covered_lines": 56, "num_statements": 56, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_validate_bip85_seed_invalid_word": {"executed_lines": [8, 9, 10], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_validate_bip85_seed_checksum_failure": {"executed_lines": [14, 16, 19, 20, 21, 22], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_setup_existing_seed_words": {"executed_lines": [26, 27, 28, 29, 30, 35, 36, 38, 39, 41, 42], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_setup_existing_seed_paste": {"executed_lines": [46, 47, 49, 51, 55, 56, 62, 63, 65, 66, 67], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_setup_existing_seed_paste.fake_masked_input": {"executed_lines": [52, 53], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_setup_existing_seed_with_args": {"executed_lines": [71, 72, 74, 76, 81, 86, 87, 88, 89, 90, 91], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_setup_existing_seed_with_args.finalize": {"executed_lines": [82, 83, 84], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 7, 13, 25, 45, 70], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 7, 8, 9, 10, 13, 14, 16, 19, 20, 21, 22, 25, 26, 27, 28, 29, 30, 35, 36, 38, 39, 41, 42, 45, 46, 47, 49, 51, 52, 53, 55, 56, 62, 63, 65, 66, 67, 70, 71, 72, 74, 76, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91], "summary": {"covered_lines": 56, "num_statements": 56, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_warning_notifications.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 34, 35, 36, 39, 40, 42, 43, 44, 45], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_search_entries_no_query": {"executed_lines": [35, 36, 39, 40, 42, 43, 44, 45], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 34], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 34, 35, 36, 39, 40, 42, 43, 44, 45], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manager_workflow.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 16, 17, 20, 21, 22, 24, 25, 26, 29, 30, 31, 32, 33, 34, 35, 37, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 81, 83, 89, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111], "summary": {"covered_lines": 62, "num_statements": 62, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakePasswordGenerator.generate_password": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostrClient.__init__": {"executed_lines": [22], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostrClient.publish_snapshot": {"executed_lines": [25, 26], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_manager_workflow": {"executed_lines": [30, 31, 32, 33, 34, 35, 37, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 81, 83, 89, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 16, 20, 21, 24, 29], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakePasswordGenerator": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostrClient": {"executed_lines": [22, 25, 26], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 16, 20, 21, 24, 29, 30, 31, 32, 33, 34, 35, 37, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 81, 83, 89, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111], "summary": {"covered_lines": 58, "num_statements": 58, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manifest_id_privacy.py": {"executed_lines": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_published_events_no_fingerprint": {"executed_lines": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 4], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_manifest_state_restore.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 68, 69, 70], "summary": {"covered_lines": 58, "num_statements": 58, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_init_pm": {"executed_lines": [15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_manifest_state_restored": {"executed_lines": [38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 68, 69, 70], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 14, 37], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 68, 69, 70], "summary": {"covered_lines": 58, "num_statements": 58, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_memory_protection.py": {"executed_lines": [1, 2, 4, 6, 8, 11, 12, 13, 14, 15, 18, 19, 20, 23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_inmemory_secret_round_trip_bytes_and_str": {"executed_lines": [12, 13, 14, 15], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_inmemory_secret_invalid_type": {"executed_lines": [19, 20], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_inmemory_secret_wipe_clears_attributes": {"executed_lines": [24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 8, 11, 18, 23], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 8, 11, 12, 13, 14, 15, 18, 19, 20, 23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_menu_navigation.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 38, 39, 40, 42, 43, 45, 46, 47, 48, 49], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_navigate_all_main_menu_options": {"executed_lines": [39, 40, 42, 43, 45, 46, 47, 48, 49], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 38], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 38, 39, 40, 42, 43, 45, 46, 47, 48, 49], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_menu_notifications.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 13, 14, 15, 16, 17, 42, 43, 44, 45, 53, 54, 55, 56, 57, 58, 61, 62, 63, 64, 65, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [14, 15, 16, 17], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_display_menu_prints_notifications": {"executed_lines": [43, 44, 45, 53, 54, 55, 56, 57, 58], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_display_menu_reuses_notification_line": {"executed_lines": [62, 63, 64, 65, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 13, 42, 61], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 13, 14, 15, 16, 17, 42, 43, 44, 45, 53, 54, 55, 56, 57, 58, 61, 62, 63, 64, 65, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_menu_options.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_totp_option": {"executed_lines": [33, 34, 35, 36, 37, 38, 39, 40], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_settings_option": {"executed_lines": [44, 45, 46, 47, 48, 49, 50, 51], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 32, 43], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_menu_search.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 29, 32, 33, 34, 35, 36, 37, 38, 39, 40], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [13, 29], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_search_option": {"executed_lines": [33, 34, 35, 36, 37, 38, 39, 40], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 32], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 29, 32, 33, 34, 35, 36, 37, 38, 39, 40], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_migrations.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 31, 34, 35, 36, 37, 38, 39, 40, 49, 52, 53, 54, 60, 61, 62, 63, 72, 75, 76, 77, 78, 79, 80, 83, 84, 85, 98, 99, 100, 101, 102, 104, 105, 106], "summary": {"covered_lines": 50, "num_statements": 50, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup": {"executed_lines": [12, 13], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migrate_v0_to_v4": {"executed_lines": [17, 18, 19, 20, 21, 22, 31], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migrate_v1_to_v4": {"executed_lines": [35, 36, 37, 38, 39, 40, 49], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_migrate_v2_to_v4": {"executed_lines": [53, 54, 60, 61, 62, 63, 72], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_error_on_future_version": {"executed_lines": [76, 77, 78, 79, 80], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_schema_migration_persisted_once": {"executed_lines": [84, 85, 98, 99, 100, 101, 102, 104, 105, 106], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 16, 34, 52, 75, 83], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 31, 34, 35, 36, 37, 38, 39, 40, 49, 52, 53, 54, 60, 61, 62, 63, 72, 75, 76, 77, 78, 79, 80, 83, 84, 85, 98, 99, 100, 101, 102, 104, 105, 106], "summary": {"covered_lines": 50, "num_statements": 50, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_modify_ssh_managed_entries.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 24, 26, 27, 28, 30, 31, 32, 33, 36, 37, 38, 39, 41, 42, 50, 52, 53, 54, 55, 56], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_mgr": {"executed_lines": [15, 16, 17, 18], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_modify_ssh_entry": {"executed_lines": [22, 23, 24, 26, 27, 28, 30, 31, 32, 33], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_modify_managed_account_entry": {"executed_lines": [37, 38, 39, 41, 42, 50, 52, 53, 54, 55, 56], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 21, 36], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 24, 26, 27, 28, 30, 31, 32, 33, 36, 37, 38, 39, 41, 42, 50, 52, 53, 54, 55, 56], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_modify_totp_entry.py": {"executed_lines": [1, 2, 4, 5, 6, 9, 10, 11, 12, 13, 15, 16, 18, 19, 20, 21, 24, 25, 26, 27, 28, 30, 31, 32], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_modify_totp_entry_period_digits_and_archive": {"executed_lines": [10, 11, 12, 13, 15, 16, 18, 19, 20, 21], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_modify_totp_entry_invalid_field": {"executed_lines": [25, 26, 27, 28, 30, 31, 32], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 6, 9, 24], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 6, 9, 10, 11, 12, 13, 15, 16, 18, 19, 20, 21, 24, 25, 26, 27, 28, 30, 31, 32], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_multiple_deltas_sync.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 53, 54, 55, 57, 58, 59, 62, 63, 64, 65, 68, 69, 70, 71, 72, 73, 74, 75, 77, 78, 80, 81, 82, 84, 85, 86, 88, 89, 90, 93, 94, 95, 96], "summary": {"covered_lines": 71, "num_statements": 71, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_init_pm": {"executed_lines": [14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sync_applies_multiple_deltas": {"executed_lines": [33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 53, 54, 55, 57, 58, 59, 62, 63, 64, 65], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_initial_sync_applies_multiple_deltas": {"executed_lines": [69, 70, 71, 72, 73, 74, 75, 77, 78, 80, 81, 82, 84, 85, 86, 88, 89, 90, 93, 94, 95, 96], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 32, 68], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 46, 47, 50, 53, 54, 55, 57, 58, 59, 62, 63, 64, 65, 68, 69, 70, 71, 72, 73, 74, 75, 77, 78, 80, 81, 82, 84, 85, 86, 88, 89, 90, 93, 94, 95, 96], "summary": {"covered_lines": 71, "num_statements": 71, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_multiple_fingerprint_prompt.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 11, 16, 17, 18, 19, 21, 22, 24, 25, 26, 28, 29, 31, 34, 39, 42, 45, 50, 54, 56, 57, 58, 60, 62, 63, 64], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_prompt_when_multiple_fingerprints": {"executed_lines": [17, 18, 19, 21, 22, 24, 25, 26, 28, 31, 34, 39, 42, 45, 50, 54, 56, 60, 62, 63, 64], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_prompt_when_multiple_fingerprints.init_fm": {"executed_lines": [29], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_prompt_when_multiple_fingerprints.fake_input": {"executed_lines": [57, 58], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 11, 16], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 9, 11, 16, 17, 18, 19, 21, 22, 24, 25, 26, 28, 29, 31, 34, 39, 42, 45, 50, 54, 56, 57, 58, 60, 62, 63, 64], "summary": {"covered_lines": 33, "num_statements": 33, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_new_seed_profile_creation.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 13, 14, 15, 16, 17, 18, 19, 20, 24, 25, 26, 28, 29, 31, 32, 33, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 50, 52, 53, 54, 55], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_pm": {"executed_lines": [14, 15, 16, 17, 18, 19, 20, 24, 25, 28, 31, 32, 33, 36, 37, 38, 39, 40], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "setup_pm.DummyEnc.__init__": {"executed_lines": [26], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "setup_pm.DummyEnc.encrypt_parent_seed": {"executed_lines": [29], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_new_seed_creates_profile": {"executed_lines": [44, 45, 46, 47, 48, 50, 52, 53, 54, 55], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 13, 43], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"setup_pm.DummyEnc": {"executed_lines": [26, 29], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 13, 14, 15, 16, 17, 18, 19, 20, 24, 25, 28, 31, 32, 33, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 50, 52, 53, 54, 55], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nonce_uniqueness.py": {"executed_lines": [1, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_nonce_uniqueness": {"executed_lines": [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 8], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_noninteractive_init_unlock.py": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 28, 30, 32, 33, 34, 36, 39, 42, 46, 47, 50, 51, 52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 66, 67, 68, 69, 70, 72, 73, 75, 78, 81, 83, 84], "summary": {"covered_lines": 55, "num_statements": 55, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_init_with_password": {"executed_lines": [14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 28, 30, 32, 36, 39, 42, 46, 47], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_init_with_password.fake_setup": {"executed_lines": [33, 34], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_unlock_with_password": {"executed_lines": [51, 52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 66, 67, 68, 69, 70, 72, 75, 78, 81, 83, 84], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_unlock_with_password.fake_setup": {"executed_lines": [73], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 10, 13, 50], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 28, 30, 32, 33, 34, 36, 39, 42, 46, 47, 50, 51, 52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 66, 67, 68, 69, 70, 72, 73, 75, 78, 81, 83, 84], "summary": {"covered_lines": 55, "num_statements": 55, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_backup.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 30, 40, 41, 42, 44, 45], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_backup_and_publish_to_nostr": {"executed_lines": [18, 19, 20, 21, 22, 23, 26, 27, 28, 30, 40, 41, 42, 44, 45], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 17], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 30, 40, 41, 42, 44, 45], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_client.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 14, 15, 18, 19, 20, 21, 22, 24, 27, 28, 29, 31, 34, 35, 36, 37, 39, 40, 42, 43, 46, 47, 48, 49, 51, 52, 54, 55, 58, 59, 60, 62, 63, 65, 66, 68, 69, 71, 72, 73, 77, 78, 79, 81, 84, 85, 86, 87, 90, 91, 92, 93, 94, 95, 98, 99, 100, 101, 102, 103, 106, 107, 109, 111, 112, 113, 115, 116, 118, 119, 122, 123, 125, 127, 128, 130, 132, 134, 137, 138, 140, 142, 144, 145, 147, 149, 150, 152, 153, 154, 157, 158, 160, 161, 162, 163, 164, 165, 167, 169, 170, 172, 174, 175, 177, 179, 181, 182, 185, 186, 188, 189, 191, 192, 194, 195, 197, 198, 199, 201, 202, 203, 204, 205, 207], "summary": {"covered_lines": 136, "num_statements": 137, "percent_covered": 99.27007299270073, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [74], "excluded_lines": [], "functions": {"test_nostr_client_uses_custom_relays": {"executed_lines": [19, 20, 21, 22, 24, 27, 28, 29, 31], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeAddRelaysClient.__init__": {"executed_lines": [36, 37], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeAddRelaysClient.add_relays": {"executed_lines": [40], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeAddRelaysClient.connect": {"executed_lines": [43], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeAddRelayClient.__init__": {"executed_lines": [48, 49], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeAddRelayClient.add_relay": {"executed_lines": [52], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeAddRelayClient.connect": {"executed_lines": [55], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeWebSocket.__init__": {"executed_lines": [60], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeWebSocket.__aenter__": {"executed_lines": [63], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeWebSocket.__aexit__": {"executed_lines": [66], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeWebSocket.send": {"executed_lines": [69], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeWebSocket.recv": {"executed_lines": [72, 73], "summary": {"covered_lines": 2, "num_statements": 3, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [74], "excluded_lines": []}, "_setup_client": {"executed_lines": [78, 79, 81, 84, 85, 86, 87], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_initialize_client_pool_add_relays_used": {"executed_lines": [91, 92, 93, 94, 95], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_initialize_client_pool_add_relay_fallback": {"executed_lines": [99, 100, 101, 102, 103], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_check_relay_health_runs_async": {"executed_lines": [107, 109, 111, 115, 116, 118, 119], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_check_relay_health_runs_async.fake_check": {"executed_lines": [112, 113], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_ping_relay_accepts_eose": {"executed_lines": [123, 125, 127, 130, 132, 134], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_ping_relay_accepts_eose.fake_connect": {"executed_lines": [128], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_relays_reinitializes_pool": {"executed_lines": [138, 140, 142, 144, 147, 149, 150, 152, 153, 154], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_relays_reinitializes_pool.fake_init": {"executed_lines": [145], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_retrieve_json_sync_backoff": {"executed_lines": [158, 160, 161, 162, 163, 164, 165, 167, 169, 172, 174, 177, 179, 181, 182], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_retrieve_json_sync_backoff.fake_sleep": {"executed_lines": [170], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_retrieve_json_sync_backoff.fake_async": {"executed_lines": [175], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_client_methods_run_in_event_loop": {"executed_lines": [186, 188, 191, 194, 197, 198, 199, 201, 207], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_client_methods_run_in_event_loop.fake_init": {"executed_lines": [189], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_client_methods_run_in_event_loop.fake_send_event": {"executed_lines": [192], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_client_methods_run_in_event_loop.fake_retrieve": {"executed_lines": [195], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_client_methods_run_in_event_loop.run_all": {"executed_lines": [202, 203, 204, 205], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 14, 15, 18, 34, 35, 39, 42, 46, 47, 51, 54, 58, 59, 62, 65, 68, 71, 77, 90, 98, 106, 122, 137, 157, 185], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeAddRelaysClient": {"executed_lines": [36, 37, 40, 43], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeAddRelayClient": {"executed_lines": [48, 49, 52, 55], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeWebSocket": {"executed_lines": [60, 63, 66, 69, 72, 73], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [74], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 14, 15, 18, 19, 20, 21, 22, 24, 27, 28, 29, 31, 34, 35, 39, 42, 46, 47, 51, 54, 58, 59, 62, 65, 68, 71, 77, 78, 79, 81, 84, 85, 86, 87, 90, 91, 92, 93, 94, 95, 98, 99, 100, 101, 102, 103, 106, 107, 109, 111, 112, 113, 115, 116, 118, 119, 122, 123, 125, 127, 128, 130, 132, 134, 137, 138, 140, 142, 144, 145, 147, 149, 150, 152, 153, 154, 157, 158, 160, 161, 162, 163, 164, 165, 167, 169, 170, 172, 174, 175, 177, 179, 181, 182, 185, 186, 188, 189, 191, 192, 194, 195, 197, 198, 199, 201, 202, 203, 204, 205, 207], "summary": {"covered_lines": 122, "num_statements": 122, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_contract.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 15, 16, 17, 20, 21, 22, 23, 25, 26, 28, 31, 32, 34, 37, 38, 40, 41, 42, 44, 45, 46, 48, 50, 51, 52, 54, 55, 56, 58, 59, 61, 64, 65, 66, 68, 71, 72, 73, 74, 75, 78, 79, 80, 81, 82, 83, 84], "summary": {"covered_lines": 57, "num_statements": 59, "percent_covered": 96.61016949152543, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [29, 35], "excluded_lines": [], "functions": {"MockNostrServer.__init__": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.__init__": {"executed_lines": [22, 23], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.add_relays": {"executed_lines": [26], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [29], "excluded_lines": []}, "MockClient.connect": {"executed_lines": [32], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.disconnect": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [35], "excluded_lines": []}, "MockClient.send_event": {"executed_lines": [38, 40, 41, 44, 45, 48], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.send_event.FakeId.to_hex": {"executed_lines": [42], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.send_event.FakeOutput.__init__": {"executed_lines": [46], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.fetch_events": {"executed_lines": [51, 52, 54, 55, 58, 61], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.fetch_events.FakeEvents.__init__": {"executed_lines": [56], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.fetch_events.FakeEvents.to_vec": {"executed_lines": [59], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "setup_client": {"executed_lines": [65, 66, 68, 71, 72, 73, 74, 75], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_and_retrieve": {"executed_lines": [79, 80, 81, 82, 83, 84], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 15, 16, 20, 21, 25, 28, 31, 34, 37, 50, 64, 78], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"MockNostrServer": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient": {"executed_lines": [22, 23, 26, 32, 38, 40, 41, 44, 45, 48, 51, 52, 54, 55, 58, 61], "summary": {"covered_lines": 16, "num_statements": 18, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [29, 35], "excluded_lines": []}, "MockClient.send_event.FakeId": {"executed_lines": [42], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.send_event.FakeOutput": {"executed_lines": [46], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "MockClient.fetch_events.FakeEvents": {"executed_lines": [56, 59], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 15, 16, 20, 21, 25, 28, 31, 34, 37, 50, 64, 65, 66, 68, 71, 72, 73, 74, 75, 78, 79, 80, 81, 82, 83, 84], "summary": {"covered_lines": 36, "num_statements": 36, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_dummy_client.py": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 34, 35, 37, 38, 39, 40, 41, 42, 43, 44, 45, 48, 49, 50, 51, 52, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 88, 90, 91, 93, 94, 96, 97, 98, 99, 101, 103, 105, 107, 116, 117, 120, 121, 122, 124, 126, 127, 130, 131, 133, 135, 137, 139, 144, 147, 148, 150, 151, 152, 154, 156, 157, 158, 160, 163, 164, 165, 167, 168, 169, 170, 172, 173, 174, 175, 176, 178, 179, 180, 182, 184, 185], "summary": {"covered_lines": 128, "num_statements": 129, "percent_covered": 99.2248062015504, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [161], "excluded_lines": [], "functions": {"test_manifest_generation": {"executed_lines": [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_retrieve_multi_chunk_snapshot": {"executed_lines": [35, 37, 38, 39, 40, 41, 42, 43, 44, 45, 48, 49, 50, 51, 52], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_and_fetch_deltas": {"executed_lines": [56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fetch_snapshot_fallback_on_missing_chunk": {"executed_lines": [73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 85, 88, 90, 91, 93, 94, 96, 97, 98, 99, 101, 103, 105, 107, 116, 117], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fetch_snapshot_fallback_on_missing_chunk.fake_sleep": {"executed_lines": [86], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fetch_snapshot_uses_event_ids": {"executed_lines": [121, 122, 124, 126, 127, 130, 131, 133, 135, 137, 139, 144], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_delta_aborts_if_outdated": {"executed_lines": [148, 150, 151, 152, 154, 156, 157, 160, 163, 164, 167, 168, 169, 170, 172, 173, 174, 175, 176, 178, 179, 180, 182, 184, 185], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_delta_aborts_if_outdated.DummyKeys.private_key_hex": {"executed_lines": [158], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_delta_aborts_if_outdated.DummyKeys.public_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [161], "excluded_lines": []}, "test_publish_delta_aborts_if_outdated.DummyKeyManager.__init__": {"executed_lines": [165], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 15, 34, 55, 72, 120, 147], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_publish_delta_aborts_if_outdated.DummyKeys": {"executed_lines": [158], "summary": {"covered_lines": 1, "num_statements": 2, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [161], "excluded_lines": []}, "test_publish_delta_aborts_if_outdated.DummyKeyManager": {"executed_lines": [165], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 34, 35, 37, 38, 39, 40, 41, 42, 43, 44, 45, 48, 49, 50, 51, 52, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 88, 90, 91, 93, 94, 96, 97, 98, 99, 101, 103, 105, 107, 116, 117, 120, 121, 122, 124, 126, 127, 130, 131, 133, 135, 137, 139, 144, 147, 148, 150, 151, 152, 154, 156, 157, 160, 163, 164, 167, 168, 169, 170, 172, 173, 174, 175, 176, 178, 179, 180, 182, 184, 185], "summary": {"covered_lines": 126, "num_statements": 126, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_entry.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 49, 50], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_nostr_key_determinism": {"executed_lines": [18, 19, 20, 21, 22, 23, 25, 26, 27, 37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 49, 50], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 17], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 49, 50], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_index_size.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 14, 16, 18, 19, 20, 21, 22, 23, 26, 27, 28], "summary": {"covered_lines": 22, "num_statements": 84, "percent_covered": 26.19047619047619, "percent_covered_display": "26", "missing_lines": 62, "excluded_lines": 0}, "missing_lines": [30, 34, 35, 36, 37, 38, 39, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 67, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 82, 83, 84, 85, 86, 87, 90, 91, 92, 93, 94, 96, 97, 99, 100, 101, 103, 105, 106, 107, 108, 109, 110, 111, 113, 114], "excluded_lines": [], "functions": {"test_nostr_index_size_limits": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 62, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 62, "excluded_lines": 0}, "missing_lines": [30, 34, 35, 36, 37, 38, 39, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 67, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 82, 83, 84, 85, 86, 87, 90, 91, 92, 93, 94, 96, 97, 99, 100, 101, 103, 105, 106, 107, 108, 109, 110, 111, 113, 114], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 14, 16, 18, 19, 20, 21, 22, 23, 26, 27, 28], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 14, 16, 18, 19, 20, 21, 22, 23, 26, 27, 28], "summary": {"covered_lines": 22, "num_statements": 84, "percent_covered": 26.19047619047619, "percent_covered_display": "26", "missing_lines": 62, "excluded_lines": 0}, "missing_lines": [30, 34, 35, 36, 37, 38, 39, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 67, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 82, 83, 84, 85, 86, 87, 90, 91, 92, 93, 94, 96, 97, 99, 100, 101, 103, 105, 106, 107, 108, 109, 110, 111, 113, 114], "excluded_lines": []}}}, "src/tests/test_nostr_legacy_decrypt_fallback.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 12, 13, 15, 16, 17, 18, 19, 22, 25, 29, 30, 31, 32, 34, 35, 36, 37, 38], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_legacy_password_only_fallback": {"executed_lines": [13, 15, 22, 25, 29, 30, 31, 32, 34, 35, 36, 37, 38], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_password_only_fallback._fast_legacy_key": {"executed_lines": [16, 17, 18, 19], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 12], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 12, 13, 15, 16, 17, 18, 19, 22, 25, 29, 30, 31, 32, 34, 35, 36, 37, 38], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_legacy_key_fallback.py": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 11, 12, 15, 17, 18, 19, 21, 24, 25, 26, 28, 32, 34, 35, 36, 37, 39, 41, 42, 43, 57, 58, 64, 66, 67, 68, 69, 70, 71, 72, 74, 76, 78, 79, 80, 81, 82, 83], "summary": {"covered_lines": 45, "num_statements": 46, "percent_covered": 97.82608695652173, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": [], "functions": {"test_fetch_snapshot_legacy_key_fallback": {"executed_lines": [12, 15, 17, 18, 21, 24, 28, 32, 34, 35, 39, 41, 42, 43, 57, 58, 64, 66, 76, 78, 79, 80, 81, 82, 83], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fetch_snapshot_legacy_key_fallback.LegacyKeys.private_key_hex": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fetch_snapshot_legacy_key_fallback.LegacyKeys.public_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": []}, "test_fetch_snapshot_legacy_key_fallback.fake_generate": {"executed_lines": [25, 26], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fetch_snapshot_legacy_key_fallback.RecordingFilter.author": {"executed_lines": [36, 37], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fetch_snapshot_legacy_key_fallback.fake_fetch_events": {"executed_lines": [67, 68, 69, 70, 71, 72, 74], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 11], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_fetch_snapshot_legacy_key_fallback.LegacyKeys": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 2, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": []}, "test_fetch_snapshot_legacy_key_fallback.RecordingFilter": {"executed_lines": [36, 37], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 11, 12, 15, 17, 18, 21, 24, 25, 26, 28, 32, 34, 35, 39, 41, 42, 43, 57, 58, 64, 66, 67, 68, 69, 70, 71, 72, 74, 76, 78, 79, 80, 81, 82, 83], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_qr.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 16, 17, 18, 20, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 45, 46, 48, 49, 50, 51, 56, 57, 60, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 81, 82, 84, 85, 86, 87, 92, 93, 94, 95, 98, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 119, 120, 123, 124, 125, 126, 127, 129, 130, 131, 132, 137, 138], "summary": {"covered_lines": 99, "num_statements": 101, "percent_covered": 98.01980198019803, "percent_covered_display": "98", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [21, 22], "excluded_lines": [], "functions": {"FakeNostrClient.__init__": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeNostrClient.publish_snapshot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [21, 22], "excluded_lines": []}, "test_show_qr_for_nostr_keys": {"executed_lines": [26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 45, 46, 48, 49, 50, 51, 56, 57], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_show_private_key_qr": {"executed_lines": [62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 81, 82, 84, 85, 86, 87, 92, 93, 94, 95], "summary": {"covered_lines": 27, "num_statements": 27, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_qr_menu_case_insensitive": {"executed_lines": [100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 119, 120, 123, 124, 125, 126, 127, 129, 130, 131, 132, 137, 138], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 16, 17, 20, 25, 60, 98], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeNostrClient": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 3, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [21, 22], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 16, 17, 20, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 45, 46, 48, 49, 50, 51, 56, 57, 60, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 81, 82, 84, 85, 86, 87, 92, 93, 94, 95, 98, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 119, 120, 123, 124, 125, 126, 127, 129, 130, 131, 132, 137, 138], "summary": {"covered_lines": 98, "num_statements": 98, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_real.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 14, 16, 17, 20, 21, 22], "summary": {"covered_lines": 17, "num_statements": 29, "percent_covered": 58.62068965517241, "percent_covered_display": "59", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [23, 27, 28, 31, 32, 37, 38, 39, 40, 41, 42, 43], "excluded_lines": [], "functions": {"test_nostr_publish_and_retrieve": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [23, 27, 28, 31, 32, 37, 38, 39, 40, 41, 42, 43], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 14, 16, 17, 20, 21, 22], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 14, 16, 17, 20, 21, 22], "summary": {"covered_lines": 17, "num_statements": 29, "percent_covered": 58.62068965517241, "percent_covered_display": "59", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [23, 27, 28, 31, 32, 37, 38, 39, 40, 41, 42, 43], "excluded_lines": []}}}, "src/tests/test_nostr_restore_flow.py": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, 32, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 46, 48, 49], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_init_pm": {"executed_lines": [12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_restore_flow_from_snapshot": {"executed_lines": [32, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 46, 48, 49], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 11, 31], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, 32, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 46, 48, 49], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_sdk_workflow.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 30, 31, 32, 33, 35, 38, 39, 40, 41, 43, 45, 46, 47, 49, 51, 52, 57, 58, 59, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71], "summary": {"covered_lines": 52, "num_statements": 52, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakeRelay.__init__": {"executed_lines": [14], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeRelay.handler": {"executed_lines": [17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "run_relay": {"executed_lines": [31, 35], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "run_relay.main": {"executed_lines": [32, 33], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_nostr_sdk_send_receive": {"executed_lines": [39, 40, 41, 43, 45, 46, 47, 49, 51, 52, 57, 58, 59, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 12, 13, 16, 30, 38], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeRelay": {"executed_lines": [14, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 12, 13, 16, 30, 31, 32, 33, 35, 38, 39, 40, 41, 43, 45, 46, 47, 49, 51, 52, 57, 58, 59, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_nostr_snapshot.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 30, 31, 34, 35, 36, 37, 39, 40, 42, 45, 46, 48, 51, 54, 55, 56, 58, 59, 60, 62, 63, 65, 68, 69, 70, 71, 72, 73, 81, 85, 86, 87, 90, 95, 96, 97, 98, 99, 101, 102, 103], "summary": {"covered_lines": 64, "num_statements": 67, "percent_covered": 95.5223880597015, "percent_covered_display": "96", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [43, 49, 52], "excluded_lines": [], "functions": {"test_prepare_snapshot_roundtrip": {"executed_lines": [16, 17, 18, 19, 20, 21, 22, 23], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEvent.__init__": {"executed_lines": [28], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEvent.content": {"executed_lines": [31], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyClient.__init__": {"executed_lines": [36, 37], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyClient.add_relays": {"executed_lines": [40], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyClient.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [43], "excluded_lines": []}, "DummyClient.connect": {"executed_lines": [46], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyClient.disconnect": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [49], "excluded_lines": []}, "DummyClient.send_event": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [52], "excluded_lines": []}, "DummyClient.fetch_events": {"executed_lines": [55, 56, 58, 59, 62, 65], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyClient.fetch_events.E.__init__": {"executed_lines": [60], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyClient.fetch_events.E.to_vec": {"executed_lines": [63], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fetch_latest_snapshot": {"executed_lines": [69, 70, 71, 72, 73, 81, 85, 86, 87, 90, 95, 96, 97, 98, 99, 101, 102, 103], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 26, 27, 30, 34, 35, 39, 42, 45, 48, 51, 54, 68], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEvent": {"executed_lines": [28, 31], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyClient": {"executed_lines": [36, 37, 40, 46, 55, 56, 58, 59, 62, 65], "summary": {"covered_lines": 10, "num_statements": 13, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [43, 49, 52], "excluded_lines": []}, "DummyClient.fetch_events.E": {"executed_lines": [60, 63], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 26, 27, 30, 34, 35, 39, 42, 45, 48, 51, 54, 68, 69, 70, 71, 72, 73, 81, 85, 86, 87, 90, 95, 96, 97, 98, 99, 101, 102, 103], "summary": {"covered_lines": 50, "num_statements": 50, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_offline_mode_behavior.py": {"executed_lines": [1, 2, 4, 7, 8, 9, 10, 11, 12, 15, 16, 17, 20, 21, 22, 23, 24, 25, 26, 27], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_sync_vault_skips_network": {"executed_lines": [8, 9, 10, 11, 12, 15, 16, 17], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_sync_offline": {"executed_lines": [21, 22, 23, 24, 25, 26, 27], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 7, 20], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 7, 8, 9, 10, 11, 12, 15, 16, 17, 20, 21, 22, 23, 24, 25, 26, 27], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_offline_mode_default_enabled.py": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_offline_mode_default_enabled": {"executed_lines": [9, 10, 11, 12, 13, 14], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_offline_mode_profile_creation.py": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29, 30, 31, 32], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_toggle_offline_mode_after_profile_creation": {"executed_lines": [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29, 30, 31, 32], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29, 30, 31, 32], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_parent_seed_backup.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 27, 28, 31, 33, 34, 36, 37, 39, 40, 42, 43, 44, 47, 48, 50, 51, 52, 56, 57, 59, 60, 63, 64, 65, 66, 67, 68], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [14, 15, 16, 17, 18, 19, 20, 21], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_backup_reveal_parent_seed_confirm": {"executed_lines": [25, 27, 28, 31, 33, 36, 37, 39, 40, 42, 43, 44], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_backup_reveal_parent_seed_confirm.fake_save": {"executed_lines": [34], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_backup_reveal_parent_seed_cancel": {"executed_lines": [48, 50, 51, 52, 56, 57, 59, 60], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_is_valid_filename": {"executed_lines": [64, 65, 66, 67, 68], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 13, 24, 47, 63], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 10, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 27, 28, 31, 33, 34, 36, 37, 39, 40, 42, 43, 44, 47, 48, 50, 51, 52, 56, 57, 59, 60, 63, 64, 65, 66, 67, 68], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_change.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 45], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_change_password_triggers_nostr_backup": {"executed_lines": [19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 45], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 15, 18], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 45], "summary": {"covered_lines": 38, "num_statements": 38, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_generation_policy.py": {"executed_lines": [1, 2, 3, 5, 7, 10, 11, 15, 16, 17, 20, 21, 22, 23, 24, 25, 28, 29, 37, 38, 39, 40, 41, 42, 43, 46, 47, 50, 51, 52, 53, 54, 55, 56, 57, 58, 61, 62, 65, 66, 67, 68], "summary": {"covered_lines": 42, "num_statements": 43, "percent_covered": 97.67441860465117, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [12], "excluded_lines": [], "functions": {"DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [12], "excluded_lines": []}, "DummyBIP85.derive_entropy": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_generator": {"executed_lines": [21, 22, 23, 24, 25], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "count_types": {"executed_lines": [29], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_zero_policy_preserves_length": {"executed_lines": [38, 39, 40, 41, 42, 43], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_custom_policy_applied": {"executed_lines": [47, 50, 51, 52, 53, 54, 55, 56, 57, 58], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_respects_policy": {"executed_lines": [62, 65, 66, 67, 68], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 10, 11, 15, 16, 20, 28, 37, 46, 61], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEnc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [12], "excluded_lines": []}, "DummyBIP85": {"executed_lines": [17], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 10, 11, 15, 16, 20, 21, 22, 23, 24, 25, 28, 29, 37, 38, 39, 40, 41, 42, 43, 46, 47, 50, 51, 52, 53, 54, 55, 56, 57, 58, 61, 62, 65, 66, 67, 68], "summary": {"covered_lines": 41, "num_statements": 41, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_helpers.py": {"executed_lines": [1, 2, 5, 6, 10, 11, 12, 15, 16, 17, 18, 19, 20, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 40, 41, 42, 43, 44, 45, 46, 47, 48, 51, 52, 53, 54, 55, 56], "summary": {"covered_lines": 41, "num_statements": 42, "percent_covered": 97.61904761904762, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [7], "excluded_lines": [], "functions": {"DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [7], "excluded_lines": []}, "DummyBIP85.derive_entropy": {"executed_lines": [12], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_generator": {"executed_lines": [16, 17, 18, 19, 20], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_derive_password_entropy_length": {"executed_lines": [24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_map_entropy_to_chars_only_uses_alphabet": {"executed_lines": [33, 34, 35, 36, 37], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_enforce_complexity_minimum_counts": {"executed_lines": [41, 42, 43, 44, 45, 46, 47, 48], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_shuffle_deterministically_repeatable": {"executed_lines": [52, 53, 54, 55, 56], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 10, 11, 15, 23, 32, 40, 51], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEnc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [7], "excluded_lines": []}, "DummyBIP85": {"executed_lines": [12], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 10, 11, 15, 16, 17, 18, 19, 20, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37, 40, 41, 42, 43, 44, 45, 46, 47, 48, 51, 52, 53, 54, 55, 56], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_length_constraints.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 16, 17, 21, 22, 23, 24, 25, 26, 29, 30, 31, 32], "summary": {"covered_lines": 20, "num_statements": 22, "percent_covered": 90.9090909090909, "percent_covered_display": "91", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [13, 18], "excluded_lines": [], "functions": {"DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [13], "excluded_lines": []}, "DummyBIP85.derive_entropy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [18], "excluded_lines": []}, "make_generator": {"executed_lines": [22, 23, 24, 25, 26], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password_too_short_raises": {"executed_lines": [30, 31, 32], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 16, 17, 21, 29], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEnc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [13], "excluded_lines": []}, "DummyBIP85": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [18], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 16, 17, 21, 22, 23, 24, 25, 26, 29, 30, 31, 32], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_notes_display.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 38, 41, 42, 44, 45, 46, 48, 49, 50, 51, 52], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_password_notes_shown": {"executed_lines": [17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 38, 41, 42, 44, 45, 46, 48, 49, 50, 51, 52], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 38, 41, 42, 44, 45, 46, 48, 49, 50, 51, 52], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_prompt.py": {"executed_lines": [1, 2, 4, 5, 7, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 31, 32, 33, 34, 35], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_prompt_new_password": {"executed_lines": [11, 12, 13, 14], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_prompt_new_password_retry": {"executed_lines": [18, 19, 20, 21, 22, 23], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_prompt_existing_password": {"executed_lines": [27, 28], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_confirm_action_yes_no": {"executed_lines": [32, 33, 34, 35], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 7, 10, 17, 26, 31], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 7, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 26, 27, 28, 31, 32, 33, 34, 35], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_properties.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 12, 13, 17, 18, 19, 22, 23, 24, 25, 26, 27, 30, 34, 35, 36, 37, 38, 39, 40, 42, 43, 45, 46, 47, 48, 49], "summary": {"covered_lines": 33, "num_statements": 34, "percent_covered": 97.05882352941177, "percent_covered_display": "97", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [14], "excluded_lines": [], "functions": {"DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [14], "excluded_lines": []}, "DummyBIP85.derive_entropy": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_generator": {"executed_lines": [23, 24, 25, 26, 27], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_password_properties": {"executed_lines": [36, 37, 38, 39, 40, 42, 43, 45, 46, 47, 48, 49], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 12, 13, 17, 18, 22, 30, 34, 35], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEnc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [14], "excluded_lines": []}, "DummyBIP85": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 12, 13, 17, 18, 22, 23, 24, 25, 26, 27, 30, 34, 35, 36, 37, 38, 39, 40, 42, 43, 45, 46, 47, 48, 49], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_shuffle_consistency.py": {"executed_lines": [1, 2, 4, 6, 9, 10, 14, 15, 16, 19, 20, 21, 22, 23, 24, 27, 28, 29, 30, 32], "summary": {"covered_lines": 20, "num_statements": 21, "percent_covered": 95.23809523809524, "percent_covered_display": "95", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [11], "excluded_lines": [], "functions": {"DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [11], "excluded_lines": []}, "DummyBIP85.derive_entropy": {"executed_lines": [16], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_generator": {"executed_lines": [20, 21, 22, 23, 24], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_password_generation_consistent_output": {"executed_lines": [28, 29, 30, 32], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 9, 10, 14, 15, 19, 27], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEnc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [11], "excluded_lines": []}, "DummyBIP85": {"executed_lines": [16], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 9, 10, 14, 15, 19, 20, 21, 22, 23, 24, 27, 28, 29, 30, 32], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_special_chars.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 12, 13, 17, 18, 19, 22, 23, 24, 25, 26, 27, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 58, 59], "summary": {"covered_lines": 41, "num_statements": 42, "percent_covered": 97.61904761904762, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [14], "excluded_lines": [], "functions": {"DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [14], "excluded_lines": []}, "DummyBIP85.derive_entropy": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_generator": {"executed_lines": [23, 24, 25, 26, 27], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_no_special_chars": {"executed_lines": [31, 32, 33, 34], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_allowed_special_chars_only": {"executed_lines": [38, 39, 40, 41, 42, 43], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_exclude_ambiguous_chars": {"executed_lines": [47, 48, 49, 50, 51], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_safe_special_chars_mode": {"executed_lines": [55, 56, 57, 58, 59], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 12, 13, 17, 18, 22, 30, 37, 46, 54], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEnc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [14], "excluded_lines": []}, "DummyBIP85": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 12, 13, 17, 18, 22, 23, 24, 25, 26, 27, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 46, 47, 48, 49, 50, 51, 54, 55, 56, 57, 58, 59], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_special_modes.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 16, 17, 18, 21, 22, 23, 24, 25, 26, 29, 30, 31, 32, 33, 36, 37, 38, 39, 40, 41, 44, 45, 46, 47, 48, 49, 50, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62], "summary": {"covered_lines": 45, "num_statements": 46, "percent_covered": 97.82608695652173, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [13], "excluded_lines": [], "functions": {"DummyEnc.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [13], "excluded_lines": []}, "DummyBIP85.derive_entropy": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "make_generator": {"executed_lines": [22, 23, 24, 25, 26], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_include_special_chars_false": {"executed_lines": [30, 31, 32, 33], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_safe_mode_uses_safe_chars": {"executed_lines": [37, 38, 39, 40, 41], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_allowed_chars_override_special_mode": {"executed_lines": [45, 46, 47, 48, 49, 50], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_enforce_complexity_min_special_zero": {"executed_lines": [54, 55, 56, 57, 58, 59, 60, 61, 62], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 16, 17, 21, 29, 36, 44, 53], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEnc": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [13], "excluded_lines": []}, "DummyBIP85": {"executed_lines": [18], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 11, 12, 16, 17, 21, 22, 23, 24, 25, 26, 29, 30, 31, 32, 33, 36, 37, 38, 39, 40, 41, 44, 45, 46, 47, 48, 49, 50, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62], "summary": {"covered_lines": 44, "num_statements": 44, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_password_unlock_after_change.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 14, 15, 16, 17, 19, 22, 23, 24, 25, 26, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 50, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 65, 67, 70, 71, 78, 79, 81, 84, 85, 86, 88, 90, 91, 92], "summary": {"covered_lines": 58, "num_statements": 58, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_password_change_and_unlock": {"executed_lines": [23, 24, 25, 26, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 50, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 65, 67, 70, 71, 78, 79, 81, 84, 85, 86, 88, 90, 91, 92], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 14, 15, 16, 17, 19, 22], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 14, 15, 16, 17, 19, 22, 23, 24, 25, 26, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 50, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 65, 67, 70, 71, 78, 79, 81, 84, 85, 86, 88, 90, 91, 92], "summary": {"covered_lines": 58, "num_statements": 58, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_pgp_entry.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 22, 25, 26, 28, 29, 32, 34, 35, 38, 39, 40, 41, 44, 47, 48, 49, 50, 51, 52, 54, 55, 56, 58, 59], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_pgp_key_determinism": {"executed_lines": [15, 16, 17, 18, 19, 20, 22, 25, 26, 28, 29, 32, 34, 35, 38, 39, 40, 41], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_pgp_rsa_key_determinism": {"executed_lines": [47, 48, 49, 50, 51, 52, 54, 55, 56, 58, 59], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 44], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 22, 25, 26, 28, 29, 32, 34, 35, 38, 39, 40, 41, 44, 47, 48, 49, 50, 51, 52, 54, 55, 56, 58, 59], "summary": {"covered_lines": 39, "num_statements": 39, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_portable_backup.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 52, 53, 54, 57, 58, 59, 60, 61, 62, 64, 65, 66, 68, 69, 70, 73, 76, 77, 78, 79, 80, 81, 83, 85, 86, 87, 88, 89, 91, 94, 97, 101, 102, 105, 106, 107, 108, 109, 111, 113, 114, 115, 116, 119, 120, 121, 122, 123, 125, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 142, 144, 145, 146, 147, 149, 150, 151, 152, 155, 156, 157, 159, 160, 161, 162, 164, 165, 166, 167, 168, 169, 171, 173, 174, 176, 177, 179, 180, 181], "summary": {"covered_lines": 131, "num_statements": 132, "percent_covered": 99.24242424242425, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [92], "excluded_lines": [], "functions": {"setup_vault": {"executed_lines": [27, 28, 29, 30, 32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_round_trip": {"executed_lines": [41, 42, 43, 44, 45, 47, 48, 49, 50, 52, 53, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_round_trip_unencrypted": {"executed_lines": [58, 59, 60, 61, 62, 64, 65, 66, 68, 69, 70], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_corruption_detection": {"executed_lines": [78, 79, 80, 81, 83, 85, 86, 87, 88, 89, 91, 94, 97, 101, 102], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_corruption_detection._fast_legacy_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [92], "excluded_lines": []}, "test_import_over_existing": {"executed_lines": [106, 107, 108, 109, 111, 113, 114, 115, 116], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_checksum_mismatch_detection": {"executed_lines": [120, 121, 122, 123, 125, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_export_import_seed_encrypted_with_different_key": {"executed_lines": [144, 145, 146, 147, 149, 150, 151, 152], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_export_creates_additional_backup_and_import": {"executed_lines": [156, 157, 159, 160, 161, 162, 164, 165, 166, 167, 168, 169, 171, 173, 174, 176, 177, 179, 180, 181], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 26, 40, 57, 73, 76, 77, 105, 119, 142, 155], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 52, 53, 54, 57, 58, 59, 60, 61, 62, 64, 65, 66, 68, 69, 70, 73, 76, 77, 78, 79, 80, 81, 83, 85, 86, 87, 88, 89, 91, 94, 97, 101, 102, 105, 106, 107, 108, 109, 111, 113, 114, 115, 116, 119, 120, 121, 122, 123, 125, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 142, 144, 145, 146, 147, 149, 150, 151, 152, 155, 156, 157, 159, 160, 161, 162, 164, 165, 166, 167, 168, 169, 171, 173, 174, 176, 177, 179, 180, 181], "summary": {"covered_lines": 131, "num_statements": 132, "percent_covered": 99.24242424242425, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [92], "excluded_lines": []}}}, "src/tests/test_post_sync_messages.py": {"executed_lines": [1, 2, 3, 5, 7, 10, 11, 18, 19, 20, 21, 22, 25, 26, 29, 30, 31, 34, 35, 42, 43, 44, 51, 52], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_handle_post_success": {"executed_lines": [11, 18, 19, 20, 21, 22], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_post_failure": {"executed_lines": [26, 29, 30, 31], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_post_prints_all_ids": {"executed_lines": [35, 42, 43, 44, 51, 52], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 10, 25, 34], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 10, 11, 18, 19, 20, 21, 22, 25, 26, 29, 30, 31, 34, 35, 42, 43, 44, 51, 52], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_profile_cleanup.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 12, 13, 14, 16, 17, 19, 20, 21, 22, 23, 24, 27, 28, 29, 30, 32, 34, 35, 40, 41, 44, 45, 46, 47, 48, 49, 50], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_pm": {"executed_lines": [13, 14, 16, 17, 19, 20, 21, 22, 23, 24], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_seed_cleanup_on_failure": {"executed_lines": [28, 29, 30, 32, 34, 35, 40, 41, 44, 45, 46, 47, 48, 49, 50], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 12, 27], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 12, 13, 14, 16, 17, 19, 20, 21, 22, 23, 24, 27, 28, 29, 30, 32, 34, 35, 40, 41, 44, 45, 46, 47, 48, 49, 50], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_profile_deletion_sync.py": {"executed_lines": [1, 2, 4, 5, 6, 8, 9, 10, 11, 14, 15, 16, 18, 20, 21, 23, 24, 25, 27, 45, 46, 48, 49, 51, 52, 53, 54, 55], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_profile_deletion_stops_sync": {"executed_lines": [15, 16, 18, 20, 23, 24, 25, 27, 45, 46, 48, 49, 51, 52, 53, 54, 55], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_profile_deletion_stops_sync.fake_post": {"executed_lines": [21], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 6, 8, 9, 10, 11, 14], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 6, 8, 9, 10, 11, 14, 15, 16, 18, 20, 21, 23, 24, 25, 27, 45, 46, 48, 49, 51, 52, 53, 54, 55], "summary": {"covered_lines": 28, "num_statements": 28, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_profile_export_import.py": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 11, 15, 16, 17, 18, 20, 21, 22, 23, 25, 26, 28, 29, 30, 32, 33], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_profile_export_import_round_trip": {"executed_lines": [9, 10, 11, 15, 16, 17, 18, 20, 21, 22, 23, 25, 28, 29, 30, 32, 33], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_profile_export_import_round_trip.sync": {"executed_lines": [26], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 11, 15, 16, 17, 18, 20, 21, 22, 23, 25, 26, 28, 29, 30, 32, 33], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_profile_init_integration.py": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, 25, 27, 29, 30, 31, 32, 33, 35, 39, 40, 42, 43, 45, 46, 47, 48], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"load_script": {"executed_lines": [10, 13, 14, 15, 16, 17], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_initialize_profile_and_manager": {"executed_lines": [21, 22, 23, 25, 27, 29, 30, 31, 32, 33, 35, 39, 40, 42, 43, 45, 46, 47, 48], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 9, 20], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, 25, 27, 29, 30, 31, 32, 33, 35, 39, 40, 42, 43, 45, 46, 47, 48], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_profile_management.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 43, 44, 46, 48, 49, 50, 52, 53, 55, 56, 57, 58, 60, 61, 62, 64, 65, 67, 68, 75, 76, 77, 83, 85, 86], "summary": {"covered_lines": 56, "num_statements": 56, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_add_and_delete_entry": {"executed_lines": [23, 24, 25, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 43, 44, 46, 48, 49, 50, 52, 53, 55, 56, 57, 58, 60, 61, 62, 64, 65, 67, 68, 75, 76, 77, 83, 85, 86], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 14, 15, 16, 17, 18, 19, 22], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 43, 44, 46, 48, 49, 50, 52, 53, 55, 56, 57, 58, 60, 61, 62, 64, 65, 67, 68, 75, 76, 77, 83, 85, 86], "summary": {"covered_lines": 56, "num_statements": 56, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_profiles.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 13, 16, 17, 18, 19, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 33, 34, 39, 40, 41, 42, 45, 49, 50, 51, 52, 55, 56, 57, 58, 59, 61, 62, 63, 64, 65, 67, 73, 78, 80, 81, 82, 83, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 99, 101, 102, 103, 104], "summary": {"covered_lines": 67, "num_statements": 67, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_add_and_switch_fingerprint": {"executed_lines": [17, 18, 19, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 33, 34, 39, 40, 41, 42, 45, 49, 50, 51, 52], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sync_index_missing_bad_data": {"executed_lines": [56, 57, 58, 59, 61, 62, 63, 64, 65, 67, 73, 78, 80, 81, 82, 83], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_attempt_initial_sync_incomplete_data": {"executed_lines": [87, 88, 89, 90, 92, 93, 94, 95, 96, 99, 101, 102, 103, 104], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 13, 16, 55, 86], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 13, 16, 17, 18, 19, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 33, 34, 39, 40, 41, 42, 45, 49, 50, 51, 52, 55, 56, 57, 58, 59, 61, 62, 63, 64, 65, 67, 73, 78, 80, 81, 82, 83, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 99, 101, 102, 103, 104], "summary": {"covered_lines": 67, "num_statements": 67, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_publish_json_result.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 16, 17, 18, 20, 25, 26, 27, 28, 29, 32, 33, 34, 35, 37, 40, 44, 45, 46, 48, 49, 52, 53, 54, 56, 57, 59, 60, 63, 64, 65, 68, 69, 70, 73, 74, 77, 79, 80, 82, 85, 86, 87, 88, 89, 90, 93, 94, 97, 99, 100, 102, 103, 104], "summary": {"covered_lines": 64, "num_statements": 66, "percent_covered": 96.96969696969697, "percent_covered_display": "97", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [38, 41], "excluded_lines": [], "functions": {"setup_client": {"executed_lines": [17, 18, 20, 25, 26, 27, 28, 29], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEvent.__init__": {"executed_lines": [34, 35], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEvent.id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [38], "excluded_lines": []}, "FakeEvent.content": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [41], "excluded_lines": []}, "FakeUnsignedEvent.__init__": {"executed_lines": [46], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeUnsignedEvent.sign_with_keys": {"executed_lines": [49], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeBuilder.__init__": {"executed_lines": [54], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeBuilder.tags": {"executed_lines": [57], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeBuilder.build": {"executed_lines": [60], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEventId.to_hex": {"executed_lines": [65], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeSendEventOutput.__init__": {"executed_lines": [70], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_snapshot_success": {"executed_lines": [74, 77, 79, 82, 85, 86, 87, 88, 89, 90], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_snapshot_success.fake_send": {"executed_lines": [80], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_snapshot_failure": {"executed_lines": [94, 97, 99, 102, 103, 104], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_snapshot_failure.boom": {"executed_lines": [100], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 16, 32, 33, 37, 40, 44, 45, 48, 52, 53, 56, 59, 63, 64, 68, 69, 73, 93], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakeEvent": {"executed_lines": [34, 35], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [38, 41], "excluded_lines": []}, "FakeUnsignedEvent": {"executed_lines": [46, 49], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeBuilder": {"executed_lines": [54, 57, 60], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeEventId": {"executed_lines": [65], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FakeSendEventOutput": {"executed_lines": [70], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 16, 17, 18, 20, 25, 26, 27, 28, 29, 32, 33, 37, 40, 44, 45, 48, 52, 53, 56, 59, 63, 64, 68, 69, 73, 74, 77, 79, 80, 82, 85, 86, 87, 88, 89, 90, 93, 94, 97, 99, 100, 102, 103, 104], "summary": {"covered_lines": 55, "num_statements": 55, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_pubsub.py": {"executed_lines": [1, 4, 5, 6, 8, 9, 11, 12, 14, 17, 18, 19, 21, 24, 25, 26, 28], "summary": {"covered_lines": 17, "num_statements": 18, "percent_covered": 94.44444444444444, "percent_covered_display": "94", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": [], "functions": {"test_subscribe_and_publish": {"executed_lines": [5, 6, 8, 11, 12, 14], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_subscribe_and_publish.handler": {"executed_lines": [9], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_unsubscribe": {"executed_lines": [18, 19, 21, 24, 25, 26, 28], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_unsubscribe.handler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": []}, "": {"executed_lines": [1, 4, 17], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 4, 5, 6, 8, 9, 11, 12, 14, 17, 18, 19, 21, 24, 25, 26, 28], "summary": {"covered_lines": 17, "num_statements": 18, "percent_covered": 94.44444444444444, "percent_covered_display": "94", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": []}}}, "src/tests/test_quick_unlock_default.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 32, 34], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_quick_unlock_default_off": {"executed_lines": [16, 17, 18], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_quick_unlock_logs_event": {"executed_lines": [22, 23, 24, 25, 26, 27, 28, 29, 31, 32, 34], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 15, 21], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 11, 12, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 32, 34], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_quick_unlock_profile_creation.py": {"executed_lines": [1, 2, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27, 28], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_toggle_quick_unlock_after_profile_creation": {"executed_lines": [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27, 28], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 6, 7, 10], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27, 28], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_restore_from_nostr_setup.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, 34, 36, 37, 38, 39, 41, 42, 43, 44, 46, 47, 48, 49, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 69, 70, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 93, 94, 95, 97, 99, 100, 101, 103, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 120, 121, 123, 124, 126, 127, 128, 129, 130, 131, 134, 135, 138, 141, 142, 144, 145, 146, 148, 149, 150, 152, 153, 154, 157, 160, 161, 163, 164, 165, 166, 168, 170, 173, 174, 176, 177, 178, 179, 180], "summary": {"covered_lines": 132, "num_statements": 133, "percent_covered": 99.24812030075188, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [171], "excluded_lines": [], "functions": {"_init_pm": {"executed_lines": [12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_new_seed_setup_restore_from_nostr": {"executed_lines": [34, 36, 37, 38, 39, 41, 42, 43, 44, 46, 47, 48, 49, 51, 66, 67, 69, 70, 72, 73, 74, 75, 76], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_new_seed_setup_restore_from_nostr.finalize": {"executed_lines": [52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_new_seed_setup_restore_from_local_backup": {"executed_lines": [80, 81, 82, 83, 85, 86, 87, 88, 89, 93, 94, 95, 97, 99, 103, 105, 120, 121, 123, 124, 126, 127, 128, 129, 130, 131], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_new_seed_setup_restore_from_local_backup.init_fp_mgr": {"executed_lines": [100, 101], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_handle_new_seed_setup_restore_from_local_backup.finalize": {"executed_lines": [106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_no_snapshot": {"executed_lines": [135], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_restore_from_nostr_warns": {"executed_lines": [141, 142, 144, 145, 146, 148, 149, 150, 152, 153, 154], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_restore_from_nostr_abort": {"executed_lines": [160, 161, 163, 164, 165, 166, 168, 170, 173, 174, 176, 177, 178, 179, 180], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_restore_from_nostr_abort.finalize": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [171], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 11, 31, 79, 134, 138, 157], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 6, 7, 8, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, 34, 36, 37, 38, 39, 41, 42, 43, 44, 46, 47, 48, 49, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 69, 70, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 93, 94, 95, 97, 99, 100, 101, 103, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 120, 121, 123, 124, 126, 127, 128, 129, 130, 131, 134, 135, 138, 141, 142, 144, 145, 146, 148, 149, 150, 152, 153, 154, 157, 160, 161, 163, 164, 165, 166, 168, 170, 173, 174, 176, 177, 178, 179, 180], "summary": {"covered_lines": 132, "num_statements": 133, "percent_covered": 99.24812030075188, "percent_covered_display": "99", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [171], "excluded_lines": []}}}, "src/tests/test_retrieve_pause_sensitive_entries.py": {"executed_lines": [1, 2, 4, 6, 8, 11, 20, 23, 25, 27, 28, 31, 32, 33, 34, 38, 39], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_pause_before_entry_actions": {"executed_lines": [23, 25, 27, 28, 31, 32, 33, 34, 38, 39], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 8, 11, 20], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 8, 11, 20, 23, 25, 27, 28, 31, 32, 33, 34, 38, 39], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_search_entries.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 27, 28, 30, 31, 34, 35, 36, 37, 39, 40, 42, 43, 46, 47, 48, 49, 51, 52, 54, 55, 60, 61, 62, 63, 65, 66, 67, 68, 71, 72, 74, 75, 78, 79, 80, 81, 83, 87, 89, 90, 93, 94, 95, 96, 98, 100, 101, 104, 105, 106, 107, 109, 110, 111, 114, 115, 116, 117, 119, 121, 122, 125, 126, 127, 128, 130, 131, 133, 134, 137, 138, 139, 140, 142, 143, 144, 146, 149, 151, 152], "summary": {"covered_lines": 98, "num_statements": 98, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_entry_manager": {"executed_lines": [16, 17, 18, 19], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_by_website": {"executed_lines": [23, 24, 25, 27, 28, 30, 31], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_by_username": {"executed_lines": [35, 36, 37, 39, 40, 42, 43], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_by_url": {"executed_lines": [47, 48, 49, 51, 52, 54, 55], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_by_notes_and_totp": {"executed_lines": [61, 62, 63, 65, 66, 67, 68, 71, 72, 74, 75], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_by_custom_field": {"executed_lines": [79, 80, 81, 83, 87, 89, 90], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_key_value_value": {"executed_lines": [94, 95, 96, 98, 100, 101], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_no_results": {"executed_lines": [105, 106, 107, 109, 110, 111], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_by_tag_password": {"executed_lines": [115, 116, 117, 119, 121, 122], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_by_tag_totp": {"executed_lines": [126, 127, 128, 130, 131, 133, 134], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_search_with_kind_filter": {"executed_lines": [138, 139, 140, 142, 143, 144, 146, 149, 151, 152], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 22, 34, 46, 60, 78, 93, 104, 114, 125, 137], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 27, 28, 30, 31, 34, 35, 36, 37, 39, 40, 42, 43, 46, 47, 48, 49, 51, 52, 54, 55, 60, 61, 62, 63, 65, 66, 67, 68, 71, 72, 74, 75, 78, 79, 80, 81, 83, 87, 89, 90, 93, 94, 95, 96, 98, 100, 101, 104, 105, 106, 107, 109, 110, 111, 114, 115, 116, 117, 119, 121, 122, 125, 126, 127, 128, 130, 131, 133, 134, 137, 138, 139, 140, 142, 143, 144, 146, 149, 151, 152], "summary": {"covered_lines": 98, "num_statements": 98, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_secret_mode.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 38, 39, 40, 41, 42, 44, 45, 46, 47, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 65, 69, 72, 76, 77, 82, 83, 84, 85, 86, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 104, 105, 106, 107, 108, 111, 112, 113, 114, 115, 116, 118, 122, 125, 129, 130, 135, 136, 137, 138, 139], "summary": {"covered_lines": 89, "num_statements": 89, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_pm": {"executed_lines": [18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_password_retrieve_secret_mode": {"executed_lines": [39, 40, 41, 42, 44, 45, 46, 47, 52, 53, 54, 55, 56], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_totp_display_secret_mode": {"executed_lines": [60, 61, 62, 63, 65, 69, 72, 76, 77, 82, 83, 84, 85, 86], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_password_retrieve_no_secret_mode": {"executed_lines": [90, 91, 92, 93, 94, 96, 97, 98, 99, 104, 105, 106, 107, 108], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_totp_display_no_secret_mode": {"executed_lines": [112, 113, 114, 115, 116, 118, 122, 125, 129, 130, 135, 136, 137, 138, 139], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 17, 38, 59, 89, 111], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 38, 39, 40, 41, 42, 44, 45, 46, 47, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 65, 69, 72, 76, 77, 82, 83, 84, 85, 86, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 104, 105, 106, 107, 108, 111, 112, 113, 114, 115, 116, 118, 122, 125, 129, 130, 135, 136, 137, 138, 139], "summary": {"covered_lines": 89, "num_statements": 89, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_secret_mode_profile_creation.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 26, 27, 30, 31, 32, 33, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 52, 54, 55, 56, 57, 58, 59], "summary": {"covered_lines": 47, "num_statements": 47, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_add_new_fingerprint_initializes_managers": {"executed_lines": [14, 15, 16, 17, 19, 26, 27, 30, 31, 32, 33], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_new_fingerprint_initializes_managers.fake_setup_existing_seed": {"executed_lines": [20, 21, 22, 23, 24], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_toggle_secret_mode_after_profile_creation": {"executed_lines": [37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 52, 54, 55, 56, 57, 58, 59], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 36], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 26, 27, 30, 31, 32, 33, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 52, 54, 55, 56, 57, 58, 59], "summary": {"covered_lines": 47, "num_statements": 47, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_seed_entry.py": {"executed_lines": [1, 2, 3, 5, 6, 8, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 31, 32, 34, 35, 37, 48, 59, 60, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74], "summary": {"covered_lines": 43, "num_statements": 43, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_seed_phrase_determinism": {"executed_lines": [19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 31, 32, 34, 35, 37, 48, 59, 60, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 8, 10, 11, 12, 13, 14, 15, 18], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 8, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 23, 24, 26, 27, 29, 30, 31, 32, 34, 35, 37, 48, 59, 60, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74], "summary": {"covered_lines": 43, "num_statements": 43, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_seed_generation.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 10, 12, 13, 16, 17, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 33, 35, 36, 38, 39, 41, 42, 43], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_password_manager": {"executed_lines": [12, 13, 16, 17, 19, 20, 21, 22, 23, 24, 25], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_bip85_and_new_seed": {"executed_lines": [29, 30, 31, 33, 35, 36, 38, 39, 41, 42, 43], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 10, 28], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 10, 12, 13, 16, 17, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 33, 35, 36, 38, 39, 41, 42, 43], "summary": {"covered_lines": 30, "num_statements": 30, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_seed_import.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_seed_encryption_round_trip": {"executed_lines": [16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 15], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 9, 11, 12, 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_seed_migration.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 11, 13, 16, 17, 18, 19, 20, 21, 22, 24, 25, 27, 29, 31, 32, 33, 34], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_parent_seed_migrates_from_fernet": {"executed_lines": [17, 18, 19, 20, 21, 22, 24, 25, 27, 29, 31, 32, 33, 34], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 11, 13, 16], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 11, 13, 16, 17, 18, 19, 20, 21, 22, 24, 25, 27, 29, 31, 32, 33, 34], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_seed_prompt.py": {"executed_lines": [1, 2, 3, 6, 7, 8, 9, 11, 19, 20, 22, 26, 28, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 50, 51, 52, 53, 55, 56, 61, 62, 63, 64, 66, 67, 68, 71, 72, 73, 74, 75, 77, 78, 81, 82, 84, 85, 86, 88, 89, 90, 92, 93, 96, 97, 99, 100, 101, 103, 104, 105, 107, 108], "summary": {"covered_lines": 68, "num_statements": 72, "percent_covered": 94.44444444444444, "percent_covered_display": "94", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [12, 17, 23, 24], "excluded_lines": [], "functions": {"test_masked_input_posix_backspace": {"executed_lines": [7, 8, 9, 11, 19, 20, 22, 26, 28, 30, 31, 32, 33, 34], "summary": {"covered_lines": 14, "num_statements": 18, "percent_covered": 77.77777777777777, "percent_covered_display": "78", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [12, 17, 23, 24], "excluded_lines": []}, "test_masked_input_windows_space": {"executed_lines": [38, 39, 40, 41, 43, 44, 45, 46, 47], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_masked_input_posix_ctrl_c": {"executed_lines": [51, 52, 53, 55, 56, 61, 62, 63, 64, 66, 67, 68], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_masked_input_windows_ctrl_c": {"executed_lines": [72, 73, 74, 75, 77, 78], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_prompt_seed_words_valid": {"executed_lines": [82, 84, 85, 86, 88, 89, 90, 92, 93], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_prompt_seed_words_invalid_word": {"executed_lines": [97, 99, 100, 101, 103, 104, 105, 107, 108], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 6, 37, 50, 71, 81, 96], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 6, 7, 8, 9, 11, 19, 20, 22, 26, 28, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 50, 51, 52, 53, 55, 56, 61, 62, 63, 64, 66, 67, 68, 71, 72, 73, 74, 75, 77, 78, 81, 82, 84, 85, 86, 88, 89, 90, 92, 93, 96, 97, 99, 100, 101, 103, 104, 105, 107, 108], "summary": {"covered_lines": 68, "num_statements": 72, "percent_covered": 94.44444444444444, "percent_covered_display": "94", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [12, 17, 23, 24], "excluded_lines": []}}}, "src/tests/test_seed_word_by_word_flow.py": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 13, 14, 15, 16, 18, 19, 20, 21, 23, 24, 27, 28, 29, 30, 31, 33, 34, 35, 36, 38, 39, 42, 43, 44, 45, 47, 48, 49, 50, 52, 53, 54, 55, 57, 59, 60, 61, 62, 64, 68, 70, 71, 72, 73, 76, 77, 78, 79, 81, 82, 83, 85, 86, 87, 88, 90, 91, 93, 94], "summary": {"covered_lines": 67, "num_statements": 67, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_prompt_seed_words_confirmation_loop": {"executed_lines": [13, 14, 15, 16, 18, 19, 20, 21, 23, 24], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_prompt_seed_words_invalid_word": {"executed_lines": [28, 29, 30, 31, 33, 34, 35, 36, 38, 39], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_new_fingerprint_words_flow_success": {"executed_lines": [43, 44, 45, 47, 48, 49, 50, 52, 53, 54, 55, 57, 59, 64, 68, 70, 71, 72, 73], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_new_fingerprint_words_flow_success.finalize": {"executed_lines": [60, 61, 62], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_new_fingerprint_words_flow_invalid_phrase": {"executed_lines": [77, 78, 79, 81, 82, 83, 85, 86, 87, 88, 90, 91, 93, 94], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 27, 42, 76], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 7, 8, 9, 12, 13, 14, 15, 16, 18, 19, 20, 21, 23, 24, 27, 28, 29, 30, 31, 33, 34, 35, 36, 38, 39, 42, 43, 44, 45, 47, 48, 49, 50, 52, 53, 54, 55, 57, 59, 60, 61, 62, 64, 68, 70, 71, 72, 73, 76, 77, 78, 79, 81, 82, 83, 85, 86, 87, 88, 90, 91, 93, 94], "summary": {"covered_lines": 67, "num_statements": 67, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_seedqr_encoding.py": {"executed_lines": [1, 2, 4, 6, 9, 10, 14, 15], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_seedqr_standard_example": {"executed_lines": [10, 14, 15], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 9], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 9, 10, 14, 15], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_service_classes.py": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 19, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 68, 69, 70, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 96, 97, 98, 100, 101, 102, 103, 104, 105, 106, 109, 110, 111, 112, 113, 115, 116, 118, 119, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 140, 143, 147, 148], "summary": {"covered_lines": 102, "num_statements": 102, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"FakePasswordGenerator.generate_password": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_setup_pm": {"executed_lines": [23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_service_add_password": {"executed_lines": [44, 45, 46, 47, 48, 68, 69, 70, 72, 73, 74, 75, 76], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_handler_list_entries": {"executed_lines": [80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_menu_handler_list_entries_shows_empty_message": {"executed_lines": [97, 98, 100, 101, 102, 103, 104, 105, 106], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_profile_service_switch": {"executed_lines": [110, 111, 115, 118, 121, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 140, 143, 147, 148], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_profile_service_switch.DummyFingerprintManager.__init__": {"executed_lines": [112, 113], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_profile_service_switch.DummyFingerprintManager.list_fingerprints": {"executed_lines": [116], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_profile_service_switch.DummyFingerprintManager.display_name": {"executed_lines": [119], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_profile_service_switch.DummyFingerprintManager.get_current_fingerprint_dir": {"executed_lines": [122], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 22, 43, 79, 96, 109], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FakePasswordGenerator": {"executed_lines": [19], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_profile_service_switch.DummyFingerprintManager": {"executed_lines": [112, 113, 116, 119, 122], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 68, 69, 70, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 96, 97, 98, 100, 101, 102, 103, 104, 105, 106, 109, 110, 111, 115, 118, 121, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 140, 143, 147, 148], "summary": {"covered_lines": 96, "num_statements": 96, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_settings_menu.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 17, 18, 19, 20, 21, 24, 25, 26, 28, 29, 31, 32, 33, 34, 35, 37, 45, 50, 53, 54, 55, 56, 59, 62, 67, 70, 71, 72, 75, 76, 79, 80, 81, 84, 85, 86, 87, 90, 91, 92, 93, 96, 97, 98, 99, 101, 102, 103, 104, 105, 108, 109, 110, 111, 112, 113, 115, 116, 117, 118, 120, 121, 123, 126, 127, 128, 129, 131, 132, 134, 135, 136, 137, 138, 140, 141, 143, 144, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 164, 165, 166, 168, 169, 171, 172], "summary": {"covered_lines": 113, "num_statements": 113, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_pm": {"executed_lines": [25, 26, 28, 29, 31, 32, 33, 34, 35, 37, 45, 50], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_relay_and_profile_actions": {"executed_lines": [54, 55, 56, 59, 62, 67, 70, 71, 72, 75, 76, 79, 80, 81, 84, 85, 86, 87, 90, 91, 92, 93], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_settings_menu_additional_backup": {"executed_lines": [97, 98, 99, 101, 102, 103, 104, 105], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_settings_menu_change_password": {"executed_lines": [109, 110, 111, 112, 113, 115, 116, 117, 118, 120, 121, 123], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_settings_menu_change_password_incorrect": {"executed_lines": [127, 128, 129, 131, 134, 135, 136, 137, 138, 140, 141, 143, 144], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_settings_menu_change_password_incorrect.fail_change": {"executed_lines": [132], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_settings_menu_without_nostr_client": {"executed_lines": [148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 164, 165, 166, 168, 169, 171, 172], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 17, 18, 19, 20, 21, 24, 53, 96, 108, 126, 147], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 17, 18, 19, 20, 21, 24, 25, 26, 28, 29, 31, 32, 33, 34, 35, 37, 45, 50, 53, 54, 55, 56, 59, 62, 67, 70, 71, 72, 75, 76, 79, 80, 81, 84, 85, 86, 87, 90, 91, 92, 93, 96, 97, 98, 99, 101, 102, 103, 104, 105, 108, 109, 110, 111, 112, 113, 115, 116, 117, 118, 120, 121, 123, 126, 127, 128, 129, 131, 132, 134, 135, 136, 137, 138, 140, 141, 143, 144, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 164, 165, 166, 168, 169, 171, 172], "summary": {"covered_lines": 113, "num_statements": 113, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_ssh_entry.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 35, 36, 37, 38], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_add_and_retrieve_ssh_key_pair": {"executed_lines": [16, 17, 18, 19, 20, 21, 23, 24, 25, 35, 36, 37, 38], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 35, 36, 37, 38], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_ssh_entry_valid.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 24, 25, 27, 31, 40], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_ssh_private_key_corresponds_to_public": {"executed_lines": [17, 18, 19, 20, 21, 22, 24, 25, 27, 31, 40], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 16], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 24, 25, 27, 31, 40], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_state_manager.py": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_state_manager_round_trip": {"executed_lines": [9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_stats_screen.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 20, 21, 22, 23, 28, 29, 30, 33, 34, 35, 36, 41, 42, 43, 46, 47, 49, 50, 52, 53, 59, 61, 64, 65, 66, 68, 70, 73, 74, 75, 76, 79, 80, 81, 82, 87, 88, 89, 90, 93, 94, 96, 97, 98, 100, 101, 103, 104, 106, 108], "summary": {"covered_lines": 59, "num_statements": 60, "percent_covered": 98.33333333333333, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [71], "excluded_lines": [], "functions": {"_make_pm": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_live_stats_shows_message": {"executed_lines": [21, 22, 23, 28, 29, 30], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_live_stats_shows_notification": {"executed_lines": [34, 35, 36, 41, 42, 43], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_live_stats_triggers_background_sync": {"executed_lines": [47, 49, 50, 52, 53, 59, 61], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_stats_display_only_once": {"executed_lines": [65, 66, 68, 70, 73, 74, 75, 76], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_stats_display_only_once.fake_input": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [71], "excluded_lines": []}, "test_stats_display_resets_after_exit": {"executed_lines": [80, 81, 82, 87, 88, 89, 90], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_stats_screen_breaks_on_enter": {"executed_lines": [94, 96, 100, 101, 103, 104, 106, 108], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_stats_screen_breaks_on_enter.display": {"executed_lines": [97, 98], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 20, 33, 46, 64, 79, 93], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 9, 12, 13, 20, 21, 22, 23, 28, 29, 30, 33, 34, 35, 36, 41, 42, 43, 46, 47, 49, 50, 52, 53, 59, 61, 64, 65, 66, 68, 70, 73, 74, 75, 76, 79, 80, 81, 82, 87, 88, 89, 90, 93, 94, 96, 97, 98, 100, 101, 103, 104, 106, 108], "summary": {"covered_lines": 59, "num_statements": 60, "percent_covered": 98.33333333333333, "percent_covered_display": "98", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [71], "excluded_lines": []}}}, "src/tests/test_sync_race_conditions.py": {"executed_lines": [1, 2, 3, 6, 8, 9, 10, 11, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 34, 35, 37, 38, 39, 40, 42, 44, 45, 46, 48, 51, 52, 53, 55, 56, 57, 59, 60, 61, 62, 64, 65, 67, 68, 69, 70, 72, 74, 75, 76, 77, 78, 86, 87, 88, 89, 90, 91, 93, 95, 96, 97, 98], "summary": {"covered_lines": 69, "num_statements": 76, "percent_covered": 90.78947368421052, "percent_covered_display": "91", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [49, 79, 80, 81, 82, 83, 84], "excluded_lines": [], "functions": {"_init_pm": {"executed_lines": [15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sync_race_conditions": {"executed_lines": [35, 37, 38, 39, 40, 42, 44, 45, 48, 51, 52, 55, 56, 57, 59, 60, 61, 62, 64, 65, 67, 68, 69, 70, 72, 74, 86, 87, 88, 89, 90, 91, 93, 95, 96, 97, 98], "summary": {"covered_lines": 37, "num_statements": 37, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sync_race_conditions.DummyKeys.private_key_hex": {"executed_lines": [46], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sync_race_conditions.DummyKeys.public_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [49], "excluded_lines": []}, "test_sync_race_conditions.DummyKeyManager.__init__": {"executed_lines": [53], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_sync_race_conditions.publish": {"executed_lines": [75, 76, 77, 78], "summary": {"covered_lines": 4, "num_statements": 10, "percent_covered": 40.0, "percent_covered_display": "40", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [79, 80, 81, 82, 83, 84], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 6, 8, 9, 10, 11, 14, 34], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_sync_race_conditions.DummyKeys": {"executed_lines": [46], "summary": {"covered_lines": 1, "num_statements": 2, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [49], "excluded_lines": []}, "test_sync_race_conditions.DummyKeyManager": {"executed_lines": [53], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 6, 8, 9, 10, 11, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 34, 35, 37, 38, 39, 40, 42, 44, 45, 48, 51, 52, 55, 56, 57, 59, 60, 61, 62, 64, 65, 67, 68, 69, 70, 72, 74, 75, 76, 77, 78, 86, 87, 88, 89, 90, 91, 93, 95, 96, 97, 98], "summary": {"covered_lines": 67, "num_statements": 73, "percent_covered": 91.78082191780823, "percent_covered_display": "92", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [79, 80, 81, 82, 83, 84], "excluded_lines": []}}}, "src/tests/test_tag_persistence.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 27, 30, 32, 33, 36, 37, 38, 39, 41, 42, 45, 50, 51, 52], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"setup_entry_manager": {"executed_lines": [16, 17, 18, 19], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_tags_persist_on_new_entry": {"executed_lines": [23, 24, 25, 27, 30, 32, 33], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_tags_persist_after_modify": {"executed_lines": [37, 38, 39, 41, 42, 45, 50, 51, 52], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 22, 36], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 27, 30, 32, 33, 36, 37, 38, 39, 41, 42, 45, 50, 51, 52], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_terminal_utils_failure_handling.py": {"executed_lines": [1, 3, 4, 6, 12, 13, 14, 17, 18, 20, 21, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 4}, "missing_lines": [], "excluded_lines": [13, 14, 20, 21], "functions": {"ErrorFingerprintManager.get_name": {"executed_lines": [14], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [14]}, "ErrorPM.get_current_notification": {"executed_lines": [21], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [21]}, "test_format_profile_reraises": {"executed_lines": [25, 26, 27, 28, 29], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_clear_header_with_notification_reraises": {"executed_lines": [33, 34, 35, 36, 37], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 6, 12, 13, 17, 18, 20, 24, 32], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [13, 20]}}, "classes": {"ErrorFingerprintManager": {"executed_lines": [14], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [14]}, "ErrorPM": {"executed_lines": [21], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [21]}, "": {"executed_lines": [1, 3, 4, 6, 12, 13, 17, 18, 20, 24, 25, 26, 27, 28, 29, 32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [13, 20]}}}, "src/tests/test_totp.py": {"executed_lines": [1, 2, 4, 5, 7, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 25, 26, 27, 28, 29, 30], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_current_code_matches_pyotp": {"executed_lines": [15, 16, 17], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_time_remaining": {"executed_lines": [22], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_print_progress_bar_terminates": {"executed_lines": [26, 27, 28, 29, 30], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 7, 9, 10, 13, 14, 20, 21, 25], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 5, 7, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 25, 26, 27, 28, 29, 30], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_totp_entry.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 25, 27, 28, 30, 31, 32, 34, 36, 37, 40, 41, 42, 45, 46, 47, 48, 49, 50, 52, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 73, 74, 75, 76, 77, 79, 80, 81, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 96, 97, 98, 100, 101], "summary": {"covered_lines": 75, "num_statements": 75, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_add_totp_and_get_code": {"executed_lines": [21, 22, 23, 24, 25, 27, 28, 30, 31, 32, 34, 36, 37, 40, 41, 42], "summary": {"covered_lines": 16, "num_statements": 16, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_totp_time_remaining": {"executed_lines": [46, 47, 48, 49, 50, 52, 54, 55, 56], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_totp_imported": {"executed_lines": [60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_totp_with_notes": {"executed_lines": [74, 75, 76, 77, 79, 80, 81], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_legacy_deterministic_entry": {"executed_lines": [85, 86, 87, 88, 90, 91, 92, 93, 94, 96, 97, 98, 100, 101], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 13, 14, 15, 16, 17, 20, 45, 59, 73, 84], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 10, 12, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 25, 27, 28, 30, 31, 32, 34, 36, 37, 40, 41, 42, 45, 46, 47, 48, 49, 50, 52, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 73, 74, 75, 76, 77, 79, 80, 81, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 96, 97, 98, 100, 101], "summary": {"covered_lines": 75, "num_statements": 75, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_totp_uri.py": {"executed_lines": [1, 2, 4, 6, 8, 13, 14, 15, 16, 17, 18, 19, 25, 26, 27, 33, 34, 35, 36, 42, 43, 44, 45, 46, 47], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_parse_otpauth_normal": {"executed_lines": [14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_parse_otpauth_missing_prefix": {"executed_lines": [26, 27], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_parse_otpauth_missing_secret": {"executed_lines": [34, 35, 36], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_make_otpauth_uri_roundtrip": {"executed_lines": [43, 44, 45, 46, 47], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 6, 8, 13, 25, 33, 42], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 6, 8, 13, 14, 15, 16, 17, 18, 19, 25, 26, 27, 33, 34, 35, 36, 42, 43, 44, 45, 46, 47], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_typer_cli.py": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 15, 18, 19, 21, 22, 23, 25, 29, 30, 31, 32, 33, 36, 37, 45, 46, 47, 48, 51, 52, 53, 55, 56, 66, 67, 68, 69, 72, 73, 75, 76, 77, 79, 80, 81, 82, 83, 84, 85, 88, 89, 91, 92, 94, 95, 96, 97, 98, 99, 100, 103, 104, 106, 107, 108, 110, 111, 113, 114, 117, 118, 119, 120, 121, 122, 125, 126, 128, 129, 131, 132, 133, 134, 135, 138, 139, 141, 142, 143, 145, 152, 153, 154, 155, 156, 159, 160, 162, 163, 164, 166, 173, 174, 175, 176, 177, 180, 181, 183, 184, 186, 189, 190, 191, 196, 197, 200, 201, 207, 208, 209, 210, 213, 214, 218, 219, 220, 221, 224, 225, 227, 228, 230, 235, 236, 237, 238, 241, 242, 244, 245, 247, 251, 252, 253, 254, 257, 258, 260, 261, 263, 266, 267, 268, 269, 272, 273, 279, 280, 281, 282, 285, 286, 288, 289, 291, 295, 296, 297, 298, 299, 302, 303, 306, 307, 308, 309, 312, 313, 315, 316, 317, 323, 324, 325, 326, 327, 328, 329, 330, 333, 334, 336, 337, 338, 339, 341, 346, 351, 374, 375, 376, 386, 389, 391, 393, 394, 395, 397, 398, 400, 401, 402, 405, 407, 409, 410, 411, 412, 414, 415, 416, 417, 420, 421, 423, 424, 425, 426, 428, 433, 434, 462, 463, 464, 465, 477, 478, 480, 483, 485, 490, 491, 492, 493, 496, 497, 498, 500, 505, 506, 507, 508, 511, 512, 514, 515, 517, 522, 523, 524, 525, 526, 529, 530, 532, 533, 535, 540, 541, 542, 543, 544, 547, 548, 550, 558, 560, 561, 562, 563, 564, 567, 568, 570, 574, 575, 576, 577, 580, 581, 583, 588, 589, 590, 591, 594, 595, 597, 602, 603, 604, 605, 608, 610, 612, 613, 614, 616, 617, 621, 622, 623, 626, 627, 629, 630, 632, 637, 638, 639, 640, 643, 646, 648, 649, 650, 653, 656, 658, 659, 660, 662, 664, 666, 667, 669, 671, 673, 674, 676, 682, 683, 684, 685], "summary": {"covered_lines": 345, "num_statements": 345, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_entry_list": {"executed_lines": [19, 21, 25, 29, 30, 31, 32, 33], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_list.list_entries": {"executed_lines": [22, 23], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_search": {"executed_lines": [37, 45, 46, 47, 48], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_get_password": {"executed_lines": [52, 55, 56, 66, 67, 68, 69], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_get_password.search": {"executed_lines": [53], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_export": {"executed_lines": [73, 75, 79, 80, 81, 82, 83, 84, 85], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_export.export_profile": {"executed_lines": [76, 77], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import": {"executed_lines": [89, 91, 94, 95, 96, 97, 98, 99, 100], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import.import_profile": {"executed_lines": [92], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_triggers_sync": {"executed_lines": [104, 106, 110, 113, 114, 117, 118, 119, 120, 121, 122], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_triggers_sync.import_profile": {"executed_lines": [107, 108], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_import_triggers_sync.sync_vault": {"executed_lines": [111], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_change_password": {"executed_lines": [126, 128, 131, 132, 133, 134, 135], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_change_password.change_pw": {"executed_lines": [129], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_lock": {"executed_lines": [139, 141, 145, 152, 153, 154, 155, 156], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_lock.lock": {"executed_lines": [142, 143], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_root_lock": {"executed_lines": [160, 162, 166, 173, 174, 175, 176, 177], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_root_lock.lock": {"executed_lines": [163, 164], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_reveal_parent_seed": {"executed_lines": [181, 183, 186, 189, 190, 191, 196, 197], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_vault_reveal_parent_seed.reveal": {"executed_lines": [184], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_nostr_get_pubkey": {"executed_lines": [201, 207, 208, 209, 210], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fingerprint_list": {"executed_lines": [214, 218, 219, 220, 221], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fingerprint_add": {"executed_lines": [225, 227, 230, 235, 236, 237, 238], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fingerprint_add.add": {"executed_lines": [228], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fingerprint_remove": {"executed_lines": [242, 244, 247, 251, 252, 253, 254], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fingerprint_remove.remove": {"executed_lines": [245], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fingerprint_switch": {"executed_lines": [258, 260, 263, 266, 267, 268, 269], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_fingerprint_switch.switch": {"executed_lines": [261], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_config_get": {"executed_lines": [273, 279, 280, 281, 282], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_config_set": {"executed_lines": [286, 288, 291, 295, 296, 297, 298, 299], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_config_set.set_timeout": {"executed_lines": [289], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_config_set_unknown_key": {"executed_lines": [303, 306, 307, 308, 309], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_nostr_sync": {"executed_lines": [313, 315, 323, 324, 325, 326, 327, 328, 329, 330], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_nostr_sync.sync_vault": {"executed_lines": [316, 317], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password": {"executed_lines": [334, 336, 341, 346, 351, 374, 375, 376, 386], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_generate_password.gen_pw": {"executed_lines": [337, 338, 339], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_api_start_passes_fingerprint": {"executed_lines": [391, 393, 397, 398, 400, 401, 402], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_api_start_passes_fingerprint.fake_start": {"executed_lines": [394, 395], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_list_passes_fingerprint": {"executed_lines": [407, 409, 410, 414, 415, 416, 417], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_list_passes_fingerprint.PM.__init__": {"executed_lines": [411, 412], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_add": {"executed_lines": [421, 423, 428, 433, 434, 462, 463, 464, 465], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_add.add_entry": {"executed_lines": [424, 425, 426], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_modify": {"executed_lines": [478, 480, 485, 490, 491, 492, 493], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_modify.modify_entry": {"executed_lines": [483], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_modify_invalid": {"executed_lines": [497, 500, 505, 506, 507, 508], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_modify_invalid.modify_entry": {"executed_lines": [498], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_archive": {"executed_lines": [512, 514, 517, 522, 523, 524, 525, 526], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_archive.archive_entry": {"executed_lines": [515], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_unarchive": {"executed_lines": [530, 532, 535, 540, 541, 542, 543, 544], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_unarchive.restore_entry": {"executed_lines": [533], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_export_totp": {"executed_lines": [548, 550, 558, 560, 561, 562, 563, 564], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_totp_codes": {"executed_lines": [568, 570, 574, 575, 576, 577], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_verify_checksum_command": {"executed_lines": [581, 583, 588, 589, 590, 591], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_update_checksum_command": {"executed_lines": [595, 597, 602, 603, 604, 605], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_tui_forward_fingerprint": {"executed_lines": [610, 612, 616, 617, 621, 622, 623], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_tui_forward_fingerprint.fake_main": {"executed_lines": [613, 614], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_gui_command": {"executed_lines": [627, 629, 632, 637, 638, 639, 640], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_gui_command.fake_main": {"executed_lines": [630], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_gui_command_no_backend": {"executed_lines": [646, 648, 649, 650], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_gui_command_install_backend": {"executed_lines": [656, 658, 662, 664, 666, 669, 671, 673, 676, 682, 683, 684, 685], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_gui_command_install_backend.backend_available": {"executed_lines": [659, 660], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_gui_command_install_backend.fake_check_call": {"executed_lines": [667], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_gui_command_install_backend.fake_main": {"executed_lines": [674], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 15, 18, 36, 51, 72, 88, 103, 125, 138, 159, 180, 200, 213, 224, 241, 257, 272, 285, 302, 312, 333, 389, 405, 420, 477, 496, 511, 529, 547, 567, 580, 594, 608, 626, 643, 653], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_entry_list_passes_fingerprint.PM": {"executed_lines": [411, 412], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 7, 9, 10, 11, 12, 13, 15, 18, 19, 21, 22, 23, 25, 29, 30, 31, 32, 33, 36, 37, 45, 46, 47, 48, 51, 52, 53, 55, 56, 66, 67, 68, 69, 72, 73, 75, 76, 77, 79, 80, 81, 82, 83, 84, 85, 88, 89, 91, 92, 94, 95, 96, 97, 98, 99, 100, 103, 104, 106, 107, 108, 110, 111, 113, 114, 117, 118, 119, 120, 121, 122, 125, 126, 128, 129, 131, 132, 133, 134, 135, 138, 139, 141, 142, 143, 145, 152, 153, 154, 155, 156, 159, 160, 162, 163, 164, 166, 173, 174, 175, 176, 177, 180, 181, 183, 184, 186, 189, 190, 191, 196, 197, 200, 201, 207, 208, 209, 210, 213, 214, 218, 219, 220, 221, 224, 225, 227, 228, 230, 235, 236, 237, 238, 241, 242, 244, 245, 247, 251, 252, 253, 254, 257, 258, 260, 261, 263, 266, 267, 268, 269, 272, 273, 279, 280, 281, 282, 285, 286, 288, 289, 291, 295, 296, 297, 298, 299, 302, 303, 306, 307, 308, 309, 312, 313, 315, 316, 317, 323, 324, 325, 326, 327, 328, 329, 330, 333, 334, 336, 337, 338, 339, 341, 346, 351, 374, 375, 376, 386, 389, 391, 393, 394, 395, 397, 398, 400, 401, 402, 405, 407, 409, 410, 414, 415, 416, 417, 420, 421, 423, 424, 425, 426, 428, 433, 434, 462, 463, 464, 465, 477, 478, 480, 483, 485, 490, 491, 492, 493, 496, 497, 498, 500, 505, 506, 507, 508, 511, 512, 514, 515, 517, 522, 523, 524, 525, 526, 529, 530, 532, 533, 535, 540, 541, 542, 543, 544, 547, 548, 550, 558, 560, 561, 562, 563, 564, 567, 568, 570, 574, 575, 576, 577, 580, 581, 583, 588, 589, 590, 591, 594, 595, 597, 602, 603, 604, 605, 608, 610, 612, 613, 614, 616, 617, 621, 622, 623, 626, 627, 629, 630, 632, 637, 638, 639, 640, 643, 646, 648, 649, 650, 653, 656, 658, 659, 660, 662, 664, 666, 667, 669, 671, 673, 674, 676, 682, 683, 684, 685], "summary": {"covered_lines": 343, "num_statements": 343, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_unlock_sync.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 26, 28, 29, 30, 31, 33, 36, 37, 38, 39, 41, 42, 45, 47, 48, 49, 51, 53, 54, 56, 58, 60, 63, 64, 65, 66, 67, 69, 70, 72, 73, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87], "summary": {"covered_lines": 61, "num_statements": 61, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_unlock_triggers_sync": {"executed_lines": [15, 16, 17, 18, 19, 20, 21, 23, 26, 28, 29, 30, 31, 33], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_unlock_triggers_sync.fake_sync": {"executed_lines": [24], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_quick_unlock_background_sync": {"executed_lines": [37, 38, 39, 41, 42, 45, 47, 48, 49, 51, 53, 56, 58, 60], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_quick_unlock_background_sync.fake_bg": {"executed_lines": [54], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_sync_running_loop": {"executed_lines": [64, 65, 66, 67, 69, 72, 75, 76, 78, 85, 86, 87], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_sync_running_loop.fake_attempt": {"executed_lines": [70], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_sync_running_loop.fake_sync": {"executed_lines": [73], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_sync_running_loop.runner": {"executed_lines": [79, 80, 81, 82, 83], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 14, 36, 63], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 26, 28, 29, 30, 31, 33, 36, 37, 38, 39, 41, 42, 45, 47, 48, 49, 51, 53, 54, 56, 58, 60, 63, 64, 65, 66, 67, 69, 70, 72, 73, 75, 76, 78, 79, 80, 81, 82, 83, 85, 86, 87], "summary": {"covered_lines": 61, "num_statements": 61, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_v2_prefix_fallback.py": {"executed_lines": [1, 2, 3, 5, 6, 8, 9, 10, 13, 14, 15, 17, 18, 19, 21, 22, 24, 25, 28, 29, 30, 32, 34, 35, 36, 38], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_v2_prefix_fernet_fallback": {"executed_lines": [14, 15, 17, 18, 19, 21, 22, 24, 25], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_aesgcm_payload_too_short": {"executed_lines": [29, 30, 32, 34, 35, 36, 38], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 8, 9, 10, 13, 28], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 8, 9, 10, 13, 14, 15, 17, 18, 19, 21, 22, 24, 25, 28, 29, 30, 32, 34, 35, 36, 38], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_vault_initialization.py": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 11, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 28, 30, 31], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_save_and_encrypt_seed_initializes_vault": {"executed_lines": [15, 16, 17, 18, 19, 20, 21, 23, 24, 28, 30, 31], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 11, 14], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 6, 8, 9, 11, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 28, 30, 31], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_vault_lock_event.py": {"executed_lines": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 23, 24, 25, 27, 28], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_lock_vault_publishes_event": {"executed_lines": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 23, 24, 25, 27, 28], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_lock_vault_publishes_event.handler": {"executed_lines": [21], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 23, 24, 25, 27, 28], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_vault_lock_flag.py": {"executed_lines": [1, 2, 4, 5, 8, 9, 10, 12, 13, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 30, 31, 32, 33, 34, 35, 36, 37, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"DummyEntryManager.__init__": {"executed_lines": [10], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "DummyEntryManager.clear_cache": {"executed_lines": [13], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_lock_vault_sets_flag_and_keeps_objects": {"executed_lines": [17, 18, 19, 20, 21, 22, 23, 24, 25, 26], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_entry_service_requires_unlocked": {"executed_lines": [30, 31, 32, 33, 34, 35, 36, 37], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_unlock_vault_clears_locked_flag": {"executed_lines": [41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8, 9, 12, 16, 29, 40], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEntryManager": {"executed_lines": [10, 13], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 5, 8, 9, 12, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 29, 30, 31, 32, 33, 34, 35, 36, 37, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52], "summary": {"covered_lines": 40, "num_statements": 40, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_verbose_timing.py": {"executed_lines": [1, 2, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_unlock_vault_logs_time": {"executed_lines": [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_publish_snapshot_logs_time": {"executed_lines": [23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 4, 7, 22], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 2, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/utils/__init__.py": {"executed_lines": [3, 5, 7, 9, 10, 19, 27, 28, 29, 30, 31, 37, 40, 41, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 10}, "missing_lines": [], "excluded_lines": [40, 41, 42, 43, 45, 46, 48, 49, 50, 51], "functions": {"": {"executed_lines": [3, 5, 7, 9, 10, 19, 27, 28, 29, 30, 31, 37, 40, 41, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 10}, "missing_lines": [], "excluded_lines": [40, 41, 42, 43, 45, 46, 48, 49, 50, 51]}}, "classes": {"": {"executed_lines": [3, 5, 7, 9, 10, 19, 27, 28, 29, 30, 31, 37, 40, 41, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 10}, "missing_lines": [], "excluded_lines": [40, 41, 42, 43, 45, 46, 48, 49, 50, 51]}}}, "src/utils/atomic_write.py": {"executed_lines": [1, 14, 16, 17, 18, 19, 22, 44, 45, 47, 48, 49, 50, 51, 52, 53, 62], "summary": {"covered_lines": 16, "num_statements": 22, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [54, 55, 56, 57, 58, 59], "excluded_lines": [], "functions": {"atomic_write": {"executed_lines": [44, 45, 47, 48, 49, 50, 51, 52, 53], "summary": {"covered_lines": 9, "num_statements": 15, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [54, 55, 56, 57, 58, 59], "excluded_lines": []}, "": {"executed_lines": [1, 14, 16, 17, 18, 19, 22, 62], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 14, 16, 17, 18, 19, 22, 44, 45, 47, 48, 49, 50, 51, 52, 53, 62], "summary": {"covered_lines": 16, "num_statements": 22, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [54, 55, 56, 57, 58, 59], "excluded_lines": []}}}, "src/utils/checksum.py": {"executed_lines": [3, 13, 14, 15, 16, 17, 18, 20, 22, 23, 26, 29, 31, 34, 36, 37, 40, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 65, 78, 89, 90, 91, 101, 102, 103, 105, 106, 109, 120, 121, 122, 123, 124, 125, 126, 140, 151, 152, 155, 156, 157, 158, 160, 161, 162, 165, 176, 177, 180, 181, 182, 185, 186, 201], "summary": {"covered_lines": 64, "num_statements": 95, "percent_covered": 67.36842105263158, "percent_covered_display": "67", "missing_lines": 31, "excluded_lines": 0}, "missing_lines": [66, 67, 70, 75, 92, 93, 94, 95, 96, 99, 127, 128, 131, 137, 153, 178, 187, 188, 192, 198, 203, 204, 205, 206, 207, 208, 211, 212, 213, 217, 223], "excluded_lines": [], "functions": {"canonical_json_dumps": {"executed_lines": [31], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "json_checksum": {"executed_lines": [36, 37], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "calculate_checksum": {"executed_lines": [50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 65], "summary": {"covered_lines": 12, "num_statements": 16, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [66, 67, 70, 75], "excluded_lines": []}, "verify_checksum": {"executed_lines": [89, 90, 91, 101, 102, 103, 105, 106], "summary": {"covered_lines": 8, "num_statements": 14, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [92, 93, 94, 95, 96, 99], "excluded_lines": []}, "update_checksum": {"executed_lines": [120, 121, 122, 123, 124, 125, 126], "summary": {"covered_lines": 7, "num_statements": 11, "percent_covered": 63.63636363636363, "percent_covered_display": "64", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [127, 128, 131, 137], "excluded_lines": []}, "verify_and_update_checksum": {"executed_lines": [151, 152, 155, 156, 157, 158, 160, 161, 162], "summary": {"covered_lines": 9, "num_statements": 10, "percent_covered": 90.0, "percent_covered_display": "90", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [153], "excluded_lines": []}, "initialize_checksum": {"executed_lines": [176, 177, 180, 181, 182, 185, 186], "summary": {"covered_lines": 7, "num_statements": 12, "percent_covered": 58.333333333333336, "percent_covered_display": "58", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [178, 187, 188, 192, 198], "excluded_lines": []}, "update_checksum_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [203, 204, 205, 206, 207, 208, 211, 212, 213, 217, 223], "excluded_lines": []}, "": {"executed_lines": [3, 13, 14, 15, 16, 17, 18, 20, 22, 23, 26, 29, 34, 40, 78, 109, 140, 165, 201], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 13, 14, 15, 16, 17, 18, 20, 22, 23, 26, 29, 31, 34, 36, 37, 40, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 65, 78, 89, 90, 91, 101, 102, 103, 105, 106, 109, 120, 121, 122, 123, 124, 125, 126, 140, 151, 152, 155, 156, 157, 158, 160, 161, 162, 165, 176, 177, 180, 181, 182, 185, 186, 201], "summary": {"covered_lines": 64, "num_statements": 95, "percent_covered": 67.36842105263158, "percent_covered_display": "67", "missing_lines": 31, "excluded_lines": 0}, "missing_lines": [66, 67, 70, 75, 92, 93, 94, 95, 96, 99, 127, 128, 131, 137, 153, 178, 187, 188, 192, 198, 203, 204, 205, 206, 207, 208, 211, 212, 213, 217, 223], "excluded_lines": []}}}, "src/utils/clipboard.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 11, 12, 15, 18, 20, 21, 22, 23, 24, 25, 35, 38, 40, 42, 43, 44, 46, 47, 48, 49, 52], "summary": {"covered_lines": 25, "num_statements": 26, "percent_covered": 96.15384615384616, "percent_covered_display": "96", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [29], "excluded_lines": [], "functions": {"_ensure_clipboard": {"executed_lines": [20, 21, 22, 23, 24, 25], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [29], "excluded_lines": []}, "copy_to_clipboard": {"executed_lines": [38, 40, 42, 46, 47, 48, 49], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "copy_to_clipboard.clear_clipboard": {"executed_lines": [43, 44], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 11, 12, 15, 18, 35, 52], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"ClipboardUnavailableError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 11, 12, 15, 18, 20, 21, 22, 23, 24, 25, 35, 38, 40, 42, 43, 44, 46, 47, 48, 49, 52], "summary": {"covered_lines": 25, "num_statements": 26, "percent_covered": 96.15384615384616, "percent_covered_display": "96", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [29], "excluded_lines": []}}}, "src/utils/color_scheme.py": {"executed_lines": [1, 3, 6, 7, 10, 12, 16, 29, 31, 32, 33, 34, 35], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_apply_orange": {"executed_lines": [12], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "color_text": {"executed_lines": [31, 32, 33, 34, 35], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 10, 16, 29], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 6, 7, 10, 12, 16, 29, 31, 32, 33, 34, 35], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/utils/file_lock.py": {"executed_lines": [1, 3, 4, 5, 6, 7, 10, 11, 21, 22, 23, 24, 25, 26, 38, 39, 42, 43, 53, 54, 55, 56, 57, 69, 70, 71], "summary": {"covered_lines": 25, "num_statements": 27, "percent_covered": 92.5925925925926, "percent_covered_display": "93", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [32, 63], "excluded_lines": [], "functions": {"exclusive_lock": {"executed_lines": [21, 22, 23, 24, 25, 26, 38, 39], "summary": {"covered_lines": 8, "num_statements": 9, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [32], "excluded_lines": []}, "shared_lock": {"executed_lines": [53, 54, 55, 56, 57, 69, 70, 71], "summary": {"covered_lines": 8, "num_statements": 9, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [63], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 7, 10, 11, 42, 43], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 6, 7, 10, 11, 21, 22, 23, 24, 25, 26, 38, 39, 42, 43, 53, 54, 55, 56, 57, 69, 70, 71], "summary": {"covered_lines": 25, "num_statements": 27, "percent_covered": 92.5925925925926, "percent_covered_display": "93", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [32, 63], "excluded_lines": []}}}, "src/utils/fingerprint.py": {"executed_lines": [3, 11, 12, 13, 16, 19, 30, 32, 33, 36, 37, 40, 41, 43], "summary": {"covered_lines": 13, "num_statements": 16, "percent_covered": 81.25, "percent_covered_display": "81", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [44, 45, 46], "excluded_lines": [], "functions": {"generate_fingerprint": {"executed_lines": [30, 32, 33, 36, 37, 40, 41, 43], "summary": {"covered_lines": 8, "num_statements": 11, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [44, 45, 46], "excluded_lines": []}, "": {"executed_lines": [3, 11, 12, 13, 16, 19], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 11, 12, 13, 16, 19, 30, 32, 33, 36, 37, 40, 41, 43], "summary": {"covered_lines": 13, "num_statements": 16, "percent_covered": 81.25, "percent_covered_display": "81", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [44, 45, 46], "excluded_lines": []}}}, "src/utils/fingerprint_manager.py": {"executed_lines": [3, 4, 5, 6, 7, 9, 11, 12, 15, 18, 19, 27, 34, 35, 36, 37, 43, 50, 51, 56, 60, 61, 62, 69, 71, 72, 73, 74, 75, 76, 77, 78, 81, 82, 85, 90, 94, 95, 100, 104, 111, 122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 141, 154, 155, 156, 157, 158, 159, 162, 164, 165, 166, 167, 168, 171, 172, 173, 174, 175, 176, 182, 183, 185, 192, 193, 195, 205, 206, 207, 208, 209, 214, 225, 227, 229, 231, 232, 234, 244, 245, 246], "summary": {"covered_lines": 94, "num_statements": 122, "percent_covered": 77.04918032786885, "percent_covered_display": "77", "missing_lines": 28, "excluded_lines": 0}, "missing_lines": [53, 54, 63, 64, 67, 86, 87, 88, 107, 108, 109, 138, 139, 169, 170, 177, 180, 211, 212, 216, 217, 218, 219, 221, 222, 223, 248, 249], "excluded_lines": [], "functions": {"FingerprintManager.__init__": {"executed_lines": [34, 35, 36, 37], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FingerprintManager.get_current_fingerprint_dir": {"executed_lines": [50, 51], "summary": {"covered_lines": 2, "num_statements": 4, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [53, 54], "excluded_lines": []}, "FingerprintManager._ensure_app_directory": {"executed_lines": [60, 61, 62], "summary": {"covered_lines": 3, "num_statements": 6, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [63, 64, 67], "excluded_lines": []}, "FingerprintManager._load_fingerprints": {"executed_lines": [71, 72, 73, 74, 75, 76, 77, 78, 81, 82, 85], "summary": {"covered_lines": 11, "num_statements": 14, "percent_covered": 78.57142857142857, "percent_covered_display": "79", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [86, 87, 88], "excluded_lines": []}, "FingerprintManager._save_fingerprints": {"executed_lines": [94, 95, 100, 104], "summary": {"covered_lines": 4, "num_statements": 7, "percent_covered": 57.142857142857146, "percent_covered_display": "57", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [107, 108, 109], "excluded_lines": []}, "FingerprintManager.add_fingerprint": {"executed_lines": [122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136], "summary": {"covered_lines": 14, "num_statements": 16, "percent_covered": 87.5, "percent_covered_display": "88", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [138, 139], "excluded_lines": []}, "FingerprintManager.remove_fingerprint": {"executed_lines": [154, 155, 156, 157, 158, 159, 162, 164, 165, 166, 167, 168, 171, 172, 173, 174, 175, 176, 182, 183], "summary": {"covered_lines": 20, "num_statements": 24, "percent_covered": 83.33333333333333, "percent_covered_display": "83", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [169, 170, 177, 180], "excluded_lines": []}, "FingerprintManager.list_fingerprints": {"executed_lines": [192, 193], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FingerprintManager.select_fingerprint": {"executed_lines": [205, 206, 207, 208, 209], "summary": {"covered_lines": 5, "num_statements": 7, "percent_covered": 71.42857142857143, "percent_covered_display": "71", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [211, 212], "excluded_lines": []}, "FingerprintManager.set_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [216, 217, 218, 219, 221, 222, 223], "excluded_lines": []}, "FingerprintManager.get_name": {"executed_lines": [227], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FingerprintManager.display_name": {"executed_lines": [231, 232], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "FingerprintManager.get_fingerprint_directory": {"executed_lines": [244, 245, 246], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [248, 249], "excluded_lines": []}, "": {"executed_lines": [3, 4, 5, 6, 7, 9, 11, 12, 15, 18, 19, 27, 43, 56, 69, 90, 111, 141, 185, 195, 214, 225, 229, 234], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FingerprintManager": {"executed_lines": [34, 35, 36, 37, 50, 51, 60, 61, 62, 71, 72, 73, 74, 75, 76, 77, 78, 81, 82, 85, 94, 95, 100, 104, 122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 154, 155, 156, 157, 158, 159, 162, 164, 165, 166, 167, 168, 171, 172, 173, 174, 175, 176, 182, 183, 192, 193, 205, 206, 207, 208, 209, 227, 231, 232, 244, 245, 246], "summary": {"covered_lines": 71, "num_statements": 99, "percent_covered": 71.71717171717172, "percent_covered_display": "72", "missing_lines": 28, "excluded_lines": 0}, "missing_lines": [53, 54, 63, 64, 67, 86, 87, 88, 107, 108, 109, 138, 139, 169, 170, 177, 180, 211, 212, 216, 217, 218, 219, 221, 222, 223, 248, 249], "excluded_lines": []}, "": {"executed_lines": [3, 4, 5, 6, 7, 9, 11, 12, 15, 18, 19, 27, 43, 56, 69, 90, 111, 141, 185, 195, 214, 225, 229, 234], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/utils/imghdr_stub.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 77, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 77, "excluded_lines": 39}, "missing_lines": [7, 9, 10, 12, 14, 25, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 51, 54, 56, 57, 58, 59, 62, 65, 67, 68, 71, 74, 76, 77, 80, 83, 85, 86, 89, 92, 94, 95, 98, 101, 103, 104, 107, 110, 112, 113, 116, 119, 121, 122, 125, 128, 130, 131, 134, 137, 139, 140, 143, 146, 148, 149, 152, 155, 157, 158, 161, 164, 166, 167, 170], "excluded_lines": [178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 219, 220], "functions": {"what": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44], "excluded_lines": []}, "test_jpeg": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [56, 57, 58, 59], "excluded_lines": []}, "test_png": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [67, 68], "excluded_lines": []}, "test_gif": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [76, 77], "excluded_lines": []}, "test_tiff": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [85, 86], "excluded_lines": []}, "test_rgb": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [94, 95], "excluded_lines": []}, "test_pbm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [103, 104], "excluded_lines": []}, "test_pgm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [112, 113], "excluded_lines": []}, "test_ppm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [121, 122], "excluded_lines": []}, "test_rast": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [130, 131], "excluded_lines": []}, "test_xbm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [139, 140], "excluded_lines": []}, "test_bmp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [148, 149], "excluded_lines": []}, "test_webp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [157, 158], "excluded_lines": []}, "test_exr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [166, 167], "excluded_lines": []}, "test": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 14}, "missing_lines": [], "excluded_lines": [179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192]}, "testall": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 21}, "missing_lines": [], "excluded_lines": [196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216]}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 4}, "missing_lines": [7, 9, 10, 12, 14, 25, 51, 54, 62, 65, 71, 74, 80, 83, 89, 92, 98, 101, 107, 110, 116, 119, 125, 128, 134, 137, 143, 146, 152, 155, 161, 164, 170], "excluded_lines": [178, 195, 219, 220]}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 77, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 77, "excluded_lines": 39}, "missing_lines": [7, 9, 10, 12, 14, 25, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 51, 54, 56, 57, 58, 59, 62, 65, 67, 68, 71, 74, 76, 77, 80, 83, 85, 86, 89, 92, 94, 95, 98, 101, 103, 104, 107, 110, 112, 113, 116, 119, 121, 122, 125, 128, 130, 131, 134, 137, 139, 140, 143, 146, 148, 149, 152, 155, 157, 158, 161, 164, 166, 167, 170], "excluded_lines": [178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 219, 220]}}}, "src/utils/input_utils.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 13, 25, 48], "summary": {"covered_lines": 10, "num_statements": 40, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 30, "excluded_lines": 4}, "missing_lines": [15, 16, 17, 18, 19, 20, 21, 22, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 50, 51, 52, 54, 55, 58], "excluded_lines": [9, 10, 27, 28], "functions": {"_timed_input_posix": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [15, 16, 17, 18, 19, 20, 21, 22], "excluded_lines": []}, "_timed_input_windows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 2}, "missing_lines": [29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45], "excluded_lines": [27, 28]}, "timed_input": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [50, 51, 52, 54, 55, 58], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 13, 25, 48], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [9, 10]}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 13, 25, 48], "summary": {"covered_lines": 10, "num_statements": 40, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 30, "excluded_lines": 4}, "missing_lines": [15, 16, 17, 18, 19, 20, 21, 22, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 50, 51, 52, 54, 55, 58], "excluded_lines": [9, 10, 27, 28]}}}, "src/utils/key_derivation.py": {"executed_lines": [3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 30, 31, 32, 35, 38, 39, 41, 44, 47, 49, 53, 54, 55, 57, 58, 59, 66, 71, 74, 96, 97, 98, 100, 101, 104, 105, 108, 111, 113, 115, 116, 123, 126, 127, 129, 136, 147, 151, 152, 153, 155, 156, 157, 166, 172, 214, 216, 217, 218, 219, 222, 224, 227, 229, 230, 233, 234, 236, 237, 238, 239, 240, 242, 243, 244, 245, 251], "summary": {"covered_lines": 77, "num_statements": 117, "percent_covered": 65.8119658119658, "percent_covered_display": "66", "missing_lines": 40, "excluded_lines": 5}, "missing_lines": [109, 131, 132, 133, 148, 149, 181, 183, 186, 188, 189, 191, 194, 201, 203, 204, 208, 209, 210, 211, 231, 246, 247, 248, 279, 280, 281, 282, 283, 284, 285, 289, 290, 291, 292, 293, 295, 296, 297, 298], "excluded_lines": [49, 50, 167, 168, 169], "functions": {"derive_key_from_password": {"executed_lines": [96, 97, 98, 100, 101, 104, 105, 108, 111, 113, 115, 116, 123, 126, 127, 129], "summary": {"covered_lines": 16, "num_statements": 20, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [109, 131, 132, 133], "excluded_lines": []}, "derive_key_from_password_argon2": {"executed_lines": [147, 151, 152, 153, 155, 156, 157, 166], "summary": {"covered_lines": 8, "num_statements": 10, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 2, "excluded_lines": 3}, "missing_lines": [148, 149], "excluded_lines": [167, 168, 169]}, "derive_key_from_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [181, 183, 186, 188, 189, 191, 194, 201, 203, 204, 208, 209, 210, 211], "excluded_lines": []}, "derive_index_key_seed_only": {"executed_lines": [216, 217, 218, 219], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "derive_index_key": {"executed_lines": [224], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "derive_totp_secret": {"executed_lines": [229, 230, 233, 234, 236, 237, 238, 239, 240, 242, 243, 244, 245], "summary": {"covered_lines": 13, "num_statements": 17, "percent_covered": 76.47058823529412, "percent_covered_display": "76", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [231, 246, 247, 248], "excluded_lines": []}, "calibrate_argon2_time_cost": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [279, 280, 281, 282, 283, 284, 285, 289, 290, 291, 292, 293, 295, 296, 297, 298], "excluded_lines": []}, "": {"executed_lines": [3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 30, 31, 32, 35, 38, 39, 41, 44, 47, 49, 53, 54, 55, 57, 58, 59, 66, 71, 74, 136, 172, 214, 222, 227, 251], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [49, 50]}}, "classes": {"EncryptionMode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "KdfConfig": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 30, 31, 32, 35, 38, 39, 41, 44, 47, 49, 53, 54, 55, 57, 58, 59, 66, 71, 74, 96, 97, 98, 100, 101, 104, 105, 108, 111, 113, 115, 116, 123, 126, 127, 129, 136, 147, 151, 152, 153, 155, 156, 157, 166, 172, 214, 216, 217, 218, 219, 222, 224, 227, 229, 230, 233, 234, 236, 237, 238, 239, 240, 242, 243, 244, 245, 251], "summary": {"covered_lines": 77, "num_statements": 117, "percent_covered": 65.8119658119658, "percent_covered_display": "66", "missing_lines": 40, "excluded_lines": 5}, "missing_lines": [109, 131, 132, 133, 148, 149, 181, 183, 186, 188, 189, 191, 194, 201, 203, 204, 208, 209, 210, 211, 231, 246, 247, 248, 279, 280, 281, 282, 283, 284, 285, 289, 290, 291, 292, 293, 295, 296, 297, 298], "excluded_lines": [49, 50, 167, 168, 169]}}}, "src/utils/key_hierarchy.py": {"executed_lines": [1, 3, 4, 5, 8, 21, 28], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"kd": {"executed_lines": [21, 28], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 8], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 8, 21, 28], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/utils/key_validation.py": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 10, 13, 15, 16, 17, 18, 19, 20, 23, 25, 26, 27, 35, 41, 43, 44, 45, 51, 53, 54, 55, 56, 57, 63, 65, 66], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 15}, "missing_lines": [], "excluded_lines": [18, 19, 20, 36, 37, 38, 46, 47, 48, 58, 59, 60, 67, 68, 69], "functions": {"validate_totp_secret": {"executed_lines": [15, 16, 17, 18, 19, 20], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [18, 19, 20]}, "validate_ssh_key_pair": {"executed_lines": [25, 26, 27, 35], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [36, 37, 38]}, "validate_pgp_private_key": {"executed_lines": [43, 44, 45], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [46, 47, 48]}, "validate_nostr_keys": {"executed_lines": [53, 54, 55, 56, 57], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [58, 59, 60]}, "validate_seed_phrase": {"executed_lines": [65, 66], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [67, 68, 69]}, "": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 10, 13, 23, 41, 51, 63], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 10, 13, 15, 16, 17, 18, 19, 20, 23, 25, 26, 27, 35, 41, 43, 44, 45, 51, 53, 54, 55, 56, 57, 63, 65, 66], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 15}, "missing_lines": [], "excluded_lines": [18, 19, 20, 36, 37, 38, 46, 47, 48, 58, 59, 60, 67, 68, 69]}}}, "src/utils/logging_utils.py": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 12, 15, 18, 19, 21, 24, 25, 26, 32, 35, 38, 41, 44, 45, 47, 48, 49, 51, 54, 57, 58, 59, 60, 62], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 13}, "missing_lines": [], "excluded_lines": [12, 13, 14, 15, 21, 22, 23, 24, 25, 26, 27, 28, 29], "functions": {"ConsolePauseFilter.filter": {"executed_lines": [15], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [15]}, "ChecksumWarningFilter.filter": {"executed_lines": [24, 25, 26], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [24, 25, 26, 27, 28, 29]}, "pause_console_logging": {"executed_lines": [35], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "resume_console_logging": {"executed_lines": [41], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "console_logging_paused": {"executed_lines": [47, 48, 49, 51], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pause_logging_for_ui": {"executed_lines": [57, 58, 62], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pause_logging_for_ui.wrapper": {"executed_lines": [59, 60], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 12, 18, 19, 21, 32, 38, 44, 45, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [12, 13, 14, 21, 22, 23]}}, "classes": {"ConsolePauseFilter": {"executed_lines": [15], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [15]}, "ChecksumWarningFilter": {"executed_lines": [24, 25, 26], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [24, 25, 26, 27, 28, 29]}, "": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 12, 18, 19, 21, 32, 35, 38, 41, 44, 45, 47, 48, 49, 51, 54, 57, 58, 59, 60, 62], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [12, 13, 14, 21, 22, 23]}}}, "src/utils/memory_protection.py": {"executed_lines": [1, 3, 4, 10, 11, 17, 18, 19, 20, 21, 22, 23, 25, 27, 29, 31, 32, 33, 34, 36, 38], "summary": {"covered_lines": 20, "num_statements": 20, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"InMemorySecret.__init__": {"executed_lines": [18, 19, 20, 21, 22, 23], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "InMemorySecret.get_bytes": {"executed_lines": [27], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "InMemorySecret.wipe": {"executed_lines": [31, 32, 33, 34], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "InMemorySecret.get_str": {"executed_lines": [38], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 10, 11, 17, 25, 29, 36], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"InMemorySecret": {"executed_lines": [18, 19, 20, 21, 22, 23, 27, 31, 32, 33, 34, 38], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 10, 11, 17, 25, 29, 36], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/utils/password_prompt.py": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 22, 24, 27, 30, 33, 36, 39, 42, 45, 47, 48, 53, 56, 59, 61, 62, 65, 66, 68, 71, 89, 90, 96, 97, 99, 100, 101, 102, 104, 113, 114, 120, 123, 124, 125, 127, 137, 138, 139, 158, 180, 181, 184, 185, 186, 187, 188, 190, 199, 200, 201, 219, 235, 236, 237, 238, 239, 240, 241, 242, 243, 259], "summary": {"covered_lines": 68, "num_statements": 126, "percent_covered": 53.96825396825397, "percent_covered_display": "54", "missing_lines": 58, "excluded_lines": 0}, "missing_lines": [46, 49, 50, 51, 52, 60, 91, 92, 93, 94, 105, 108, 109, 110, 111, 128, 131, 132, 133, 134, 141, 142, 143, 144, 145, 146, 149, 150, 151, 153, 154, 155, 182, 191, 194, 195, 196, 197, 203, 204, 205, 206, 207, 208, 212, 213, 214, 216, 245, 247, 248, 249, 250, 251, 252, 255, 256, 268], "excluded_lines": [], "functions": {"_env_password": {"executed_lines": [39], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_get_max_attempts": {"executed_lines": [45, 47, 48, 53], "summary": {"covered_lines": 4, "num_statements": 9, "percent_covered": 44.44444444444444, "percent_covered_display": "44", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [46, 49, 50, 51, 52], "excluded_lines": []}, "_apply_backoff": {"executed_lines": [59, 61, 62], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [60], "excluded_lines": []}, "prompt_new_password": {"executed_lines": [89, 90, 96, 97, 99, 100, 101, 102, 104, 113, 114, 120, 123, 124, 125, 127, 137, 138, 139], "summary": {"covered_lines": 19, "num_statements": 45, "percent_covered": 42.22222222222222, "percent_covered_display": "42", "missing_lines": 26, "excluded_lines": 0}, "missing_lines": [91, 92, 93, 94, 105, 108, 109, 110, 111, 128, 131, 132, 133, 134, 141, 142, 143, 144, 145, 146, 149, 150, 151, 153, 154, 155], "excluded_lines": []}, "prompt_existing_password": {"executed_lines": [180, 181, 184, 185, 186, 187, 188, 190, 199, 200, 201], "summary": {"covered_lines": 11, "num_statements": 27, "percent_covered": 40.74074074074074, "percent_covered_display": "41", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [182, 191, 194, 195, 196, 197, 203, 204, 205, 206, 207, 208, 212, 213, 214, 216], "excluded_lines": []}, "confirm_action": {"executed_lines": [235, 236, 237, 238, 239, 240, 241, 242, 243], "summary": {"covered_lines": 9, "num_statements": 18, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [245, 247, 248, 249, 250, 251, 252, 255, 256], "excluded_lines": []}, "prompt_for_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [268], "excluded_lines": []}, "": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 22, 24, 27, 30, 33, 36, 42, 56, 65, 66, 68, 71, 158, 219, 259], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"PasswordPromptError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 22, 24, 27, 30, 33, 36, 39, 42, 45, 47, 48, 53, 56, 59, 61, 62, 65, 66, 68, 71, 89, 90, 96, 97, 99, 100, 101, 102, 104, 113, 114, 120, 123, 124, 125, 127, 137, 138, 139, 158, 180, 181, 184, 185, 186, 187, 188, 190, 199, 200, 201, 219, 235, 236, 237, 238, 239, 240, 241, 242, 243, 259], "summary": {"covered_lines": 68, "num_statements": 126, "percent_covered": 53.96825396825397, "percent_covered_display": "54", "missing_lines": 58, "excluded_lines": 0}, "missing_lines": [46, 49, 50, 51, 52, 60, 91, 92, 93, 94, 105, 108, 109, 110, 111, 128, 131, 132, 133, 134, 141, 142, 143, 144, 145, 146, 149, 150, 151, 153, 154, 155, 182, 191, 194, 195, 196, 197, 203, 204, 205, 206, 207, 208, 212, 213, 214, 216, 245, 247, 248, 249, 250, 251, 252, 255, 256, 268], "excluded_lines": []}}}, "src/utils/seed_prompt.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 17, 18, 20, 23, 31, 33, 34, 39, 42, 45, 47, 48, 51, 53, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 71, 72, 73, 76, 78, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 102, 104, 107, 109, 110, 111, 112, 113, 114, 118, 121, 150, 152, 153, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 184, 185, 186, 187, 188, 189, 190, 191, 194, 195, 196, 211, 212, 213, 214], "summary": {"covered_lines": 107, "num_statements": 128, "percent_covered": 83.59375, "percent_covered_display": "84", "missing_lines": 21, "excluded_lines": 11}, "missing_lines": [32, 35, 36, 37, 38, 46, 67, 68, 69, 168, 197, 198, 199, 200, 201, 204, 205, 206, 207, 208, 209], "excluded_lines": [7, 8, 13, 14, 15, 53, 54, 78, 79, 115, 116], "functions": {"_get_max_attempts": {"executed_lines": [31, 33, 34, 39], "summary": {"covered_lines": 4, "num_statements": 9, "percent_covered": 44.44444444444444, "percent_covered_display": "44", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [32, 35, 36, 37, 38], "excluded_lines": []}, "_apply_backoff": {"executed_lines": [45, 47, 48], "summary": {"covered_lines": 3, "num_statements": 4, "percent_covered": 75.0, "percent_covered_display": "75", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [46], "excluded_lines": []}, "_masked_input_windows": {"executed_lines": [53, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 71, 72, 73], "summary": {"covered_lines": 14, "num_statements": 17, "percent_covered": 82.3529411764706, "percent_covered_display": "82", "missing_lines": 3, "excluded_lines": 2}, "missing_lines": [67, 68, 69], "excluded_lines": [53, 54]}, "_masked_input_posix": {"executed_lines": [78, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 102, 104], "summary": {"covered_lines": 22, "num_statements": 22, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [78, 79]}, "masked_input": {"executed_lines": [109, 110, 111, 112, 113, 114, 118], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [115, 116]}, "prompt_seed_words": {"executed_lines": [150, 152, 153, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 184, 185, 186, 187, 188, 189, 190, 191, 194, 195, 196, 211, 212, 213, 214], "summary": {"covered_lines": 40, "num_statements": 52, "percent_covered": 76.92307692307692, "percent_covered_display": "77", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [168, 197, 198, 199, 200, 201, 204, 205, 206, 207, 208, 209], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 17, 18, 20, 23, 42, 51, 76, 107, 121], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 5}, "missing_lines": [], "excluded_lines": [7, 8, 13, 14, 15]}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 17, 18, 20, 23, 31, 33, 34, 39, 42, 45, 47, 48, 51, 53, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 71, 72, 73, 76, 78, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 102, 104, 107, 109, 110, 111, 112, 113, 114, 118, 121, 150, 152, 153, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 184, 185, 186, 187, 188, 189, 190, 191, 194, 195, 196, 211, 212, 213, 214], "summary": {"covered_lines": 107, "num_statements": 128, "percent_covered": 83.59375, "percent_covered_display": "84", "missing_lines": 21, "excluded_lines": 11}, "missing_lines": [32, 35, 36, 37, 38, 46, 67, 68, 69, 168, 197, 198, 199, 200, 201, 204, 205, 206, 207, 208, 209], "excluded_lines": [7, 8, 13, 14, 15, 53, 54, 78, 79, 115, 116]}}}, "src/utils/terminal_utils.py": {"executed_lines": [1, 3, 4, 5, 7, 9, 12, 14, 16, 17, 18, 21, 22, 25, 26, 29, 31, 34, 57, 73, 82, 83, 84, 86, 87, 88, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 106, 107, 108, 109, 111, 113, 116, 118, 119], "summary": {"covered_lines": 42, "num_statements": 75, "percent_covered": 56.0, "percent_covered_display": "56", "missing_lines": 33, "excluded_lines": 6}, "missing_lines": [15, 19, 20, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 85, 89, 110, 120, 121, 122, 123], "excluded_lines": [21, 22, 25, 102, 103, 104], "functions": {"format_profile": {"executed_lines": [14, 16, 17, 18, 21, 22, 25, 26], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 3}, "missing_lines": [15, 19, 20], "excluded_lines": [21, 22, 25]}, "clear_screen": {"executed_lines": [31], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "clear_and_print_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54], "excluded_lines": []}, "clear_and_print_profile_chain": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [61, 62, 63, 64, 65, 66, 67, 68, 69, 70], "excluded_lines": []}, "clear_header_with_notification": {"executed_lines": [82, 83, 84, 86, 87, 88, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 106, 107, 108, 109, 111, 113], "summary": {"covered_lines": 23, "num_statements": 26, "percent_covered": 88.46153846153847, "percent_covered_display": "88", "missing_lines": 3, "excluded_lines": 3}, "missing_lines": [85, 89, 110], "excluded_lines": [102, 103, 104]}, "pause": {"executed_lines": [118, 119], "summary": {"covered_lines": 2, "num_statements": 6, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [120, 121, 122, 123], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 12, 29, 34, 57, 73, 116], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 7, 9, 12, 14, 16, 17, 18, 21, 22, 25, 26, 29, 31, 34, 57, 73, 82, 83, 84, 86, 87, 88, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 106, 107, 108, 109, 111, 113, 116, 118, 119], "summary": {"covered_lines": 42, "num_statements": 75, "percent_covered": 56.0, "percent_covered_display": "56", "missing_lines": 33, "excluded_lines": 6}, "missing_lines": [15, 19, 20, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 85, 89, 110, 120, 121, 122, 123], "excluded_lines": [21, 22, 25, 102, 103, 104]}}}}, "totals": {"covered_lines": 17039, "num_statements": 19898, "percent_covered": 85.63172178108353, "percent_covered_display": "86", "missing_lines": 2859, "excluded_lines": 290}} \ No newline at end of file diff --git a/artifacts/coverage/coverage.manager_workers.json b/artifacts/coverage/coverage.manager_workers.json new file mode 100644 index 00000000..2a141649 --- /dev/null +++ b/artifacts/coverage/coverage.manager_workers.json @@ -0,0 +1 @@ +{"meta": {"format": 3, "version": "7.10.1", "timestamp": "2026-02-23T15:21:05.322418", "branch_coverage": false, "show_contexts": false}, "files": {"src/constants.py": {"executed_lines": [3, 4, 7, 15, 16, 17, 22, 23, 28, 33, 45, 46, 47, 50, 53, 56, 62], "summary": {"covered_lines": 17, "num_statements": 22, "percent_covered": 77.27272727272727, "percent_covered_display": "77", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [35, 36, 37, 38, 39], "excluded_lines": [], "functions": {"initialize_app": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [35, 36, 37, 38, 39], "excluded_lines": []}, "": {"executed_lines": [3, 4, 7, 15, 16, 17, 22, 23, 28, 33, 45, 46, 47, 50, 53, 56, 62], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 4, 7, 15, 16, 17, 22, 23, 28, 33, 45, 46, 47, 50, 53, 56, 62], "summary": {"covered_lines": 17, "num_statements": 22, "percent_covered": 77.27272727272727, "percent_covered_display": "77", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [35, 36, 37, 38, 39], "excluded_lines": []}}}, "src/local_bip85/__init__.py": {"executed_lines": [3, 5, 7, 8, 15], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [9, 10, 11], "excluded_lines": [], "functions": {"": {"executed_lines": [3, 5, 7, 8, 15], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [9, 10, 11], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 5, 7, 8, 15], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [9, 10, 11], "excluded_lines": []}}}, "src/local_bip85/bip85.py": {"executed_lines": [3, 16, 17, 18, 19, 20, 21, 23, 25, 27, 28, 29, 32, 35, 36, 38, 41, 42, 61, 125, 149], "summary": {"covered_lines": 19, "num_statements": 75, "percent_covered": 25.333333333333332, "percent_covered_display": "25", "missing_lines": 56, "excluded_lines": 0}, "missing_lines": [50, 51, 52, 54, 55, 56, 57, 58, 59, 86, 87, 88, 89, 90, 91, 94, 96, 97, 98, 99, 101, 102, 103, 105, 107, 108, 111, 114, 118, 119, 120, 121, 122, 123, 126, 127, 128, 129, 130, 132, 138, 139, 142, 143, 144, 145, 146, 147, 151, 152, 153, 154, 155, 156, 157, 158], "excluded_lines": [], "functions": {"BIP85.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [50, 51, 52, 54, 55, 56, 57, 58, 59], "excluded_lines": []}, "BIP85.derive_entropy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [86, 87, 88, 89, 90, 91, 94, 96, 97, 98, 99, 101, 102, 103, 105, 107, 108, 111, 114, 118, 119, 120, 121, 122, 123], "excluded_lines": []}, "BIP85.derive_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [126, 127, 128, 129, 130, 132, 138, 139, 142, 143, 144, 145, 146, 147], "excluded_lines": []}, "BIP85.derive_symmetric_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [151, 152, 153, 154, 155, 156, 157, 158], "excluded_lines": []}, "": {"executed_lines": [3, 16, 17, 18, 19, 20, 21, 23, 25, 27, 28, 29, 32, 35, 36, 38, 41, 42, 61, 125, 149], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"Bip85Error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BIP85": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 56, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 56, "excluded_lines": 0}, "missing_lines": [50, 51, 52, 54, 55, 56, 57, 58, 59, 86, 87, 88, 89, 90, 91, 94, 96, 97, 98, 99, 101, 102, 103, 105, 107, 108, 111, 114, 118, 119, 120, 121, 122, 123, 126, 127, 128, 129, 130, 132, 138, 139, 142, 143, 144, 145, 146, 147, 151, 152, 153, 154, 155, 156, 157, 158], "excluded_lines": []}, "": {"executed_lines": [3, 16, 17, 18, 19, 20, 21, 23, 25, 27, 28, 29, 32, 35, 36, 38, 41, 42, 61, 125, 149], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/main.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1067, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1067, "excluded_lines": 5}, "missing_lines": [2, 3, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 33, 40, 41, 42, 47, 49, 51, 58, 60, 61, 62, 63, 64, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 84, 87, 88, 90, 91, 92, 93, 95, 96, 98, 101, 102, 104, 105, 106, 107, 108, 110, 112, 113, 116, 117, 124, 125, 126, 127, 128, 129, 131, 134, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 149, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 165, 166, 172, 173, 174, 175, 181, 183, 184, 185, 186, 188, 189, 190, 191, 193, 194, 195, 200, 201, 202, 204, 205, 206, 207, 210, 216, 217, 218, 219, 220, 223, 225, 226, 227, 228, 229, 231, 232, 233, 234, 236, 237, 238, 239, 241, 242, 245, 247, 248, 249, 250, 251, 252, 254, 257, 260, 261, 268, 270, 271, 272, 273, 276, 282, 283, 284, 285, 286, 288, 289, 290, 291, 292, 293, 294, 295, 298, 302, 303, 304, 305, 306, 308, 309, 310, 311, 312, 313, 316, 324, 325, 326, 327, 328, 330, 331, 332, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 363, 365, 366, 372, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 398, 399, 400, 401, 402, 403, 404, 405, 408, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 426, 427, 428, 429, 430, 432, 435, 437, 438, 439, 440, 446, 447, 449, 450, 453, 454, 455, 456, 457, 458, 459, 465, 466, 467, 468, 470, 473, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 490, 492, 493, 494, 495, 496, 497, 498, 501, 503, 504, 505, 506, 507, 508, 509, 510, 511, 514, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 542, 545, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 570, 571, 572, 573, 574, 575, 576, 577, 579, 582, 584, 585, 586, 587, 588, 590, 591, 592, 593, 594, 595, 596, 598, 601, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 635, 637, 638, 640, 641, 642, 643, 644, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 684, 686, 687, 688, 689, 690, 691, 692, 693, 695, 696, 697, 698, 699, 701, 704, 705, 706, 707, 708, 709, 710, 711, 713, 714, 715, 716, 717, 718, 719, 720, 721, 723, 724, 725, 726, 727, 728, 729, 730, 733, 735, 736, 737, 738, 739, 740, 741, 743, 744, 745, 746, 747, 749, 752, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 803, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 840, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 878, 880, 881, 886, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 914, 917, 919, 920, 921, 922, 923, 924, 925, 926, 927, 929, 930, 935, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 968, 971, 973, 974, 979, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1070, 1073, 1081, 1092, 1093, 1094, 1095, 1096, 1097, 1102, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1117, 1118, 1119, 1123, 1124, 1126, 1129, 1130, 1131, 1132, 1133, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1165, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1234, 1237, 1247, 1248, 1249, 1250, 1251, 1253, 1254, 1255, 1256, 1260, 1265, 1270, 1276, 1278, 1279, 1280, 1286, 1287, 1289, 1290, 1292, 1293, 1295, 1296, 1298, 1300, 1301, 1302, 1303, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1335, 1336, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1350, 1351, 1352, 1353, 1355, 1356, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1416, 1418, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1430, 1431, 1433, 1434, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470, 1473, 1474], "excluded_lines": [333, 334, 367, 368, 369], "functions": {"_warn_missing_optional_dependencies": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [60, 61, 62, 63, 64], "excluded_lines": []}, "load_global_config": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [73, 74, 75, 76, 77, 78, 79, 80, 81], "excluded_lines": []}, "configure_logging": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [87, 88, 90, 91, 92, 93, 95, 96, 98, 101, 102, 104, 105, 106, 107, 108, 110, 112, 113], "excluded_lines": []}, "confirm_action": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [124, 125, 126, 127, 128, 129, 131], "excluded_lines": []}, "drain_notifications": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146], "excluded_lines": []}, "get_notification_text": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162], "excluded_lines": []}, "handle_switch_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [172, 173, 174, 175, 181, 183, 184, 185, 186, 188, 189, 190, 191, 193, 194, 195, 200, 201, 202, 204, 205, 206, 207], "excluded_lines": []}, "handle_add_new_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [216, 217, 218, 219, 220], "excluded_lines": []}, "handle_remove_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 0}, "missing_lines": [225, 226, 227, 228, 229, 231, 232, 233, 234, 236, 237, 238, 239, 241, 242, 245, 247, 254, 257, 260, 261, 268, 270, 271, 272, 273], "excluded_lines": []}, "handle_remove_fingerprint._cleanup_and_exit": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [248, 249, 250, 251, 252], "excluded_lines": []}, "handle_list_fingerprints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [282, 283, 284, 285, 286, 288, 289, 290, 291, 292, 293, 294, 295], "excluded_lines": []}, "handle_display_npub": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [302, 303, 304, 305, 306, 308, 309, 310, 311, 312, 313], "excluded_lines": []}, "_display_live_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 32, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 32, "excluded_lines": 2}, "missing_lines": [324, 325, 326, 327, 328, 330, 331, 332, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360], "excluded_lines": [333, 334]}, "handle_display_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 3}, "missing_lines": [365, 366], "excluded_lines": [367, 368, 369]}, "print_matches": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 28, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 28, "excluded_lines": 0}, "missing_lines": [377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 398, 399, 400, 401, 402, 403, 404, 405], "excluded_lines": []}, "handle_post_to_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 426, 427, 428, 429, 430, 432], "excluded_lines": []}, "handle_retrieve_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [437, 438, 439, 440, 446, 447, 449, 450, 453, 454, 455, 456, 457, 458, 459, 465, 466, 467, 468, 470], "excluded_lines": []}, "handle_view_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487], "excluded_lines": []}, "_safe_close_client_pool": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [492, 493, 494, 495, 496, 497, 498], "excluded_lines": []}, "_reload_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [503, 504, 505, 506, 507, 508, 509, 510, 511], "excluded_lines": []}, "handle_add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 0}, "missing_lines": [516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 542], "excluded_lines": []}, "handle_remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 27, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 27, "excluded_lines": 0}, "missing_lines": [547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 570, 571, 572, 573, 574, 575, 576, 577, 579], "excluded_lines": []}, "handle_reset_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [584, 585, 586, 587, 588, 590, 591, 592, 593, 594, 595, 596, 598], "excluded_lines": []}, "handle_set_inactivity_timeout": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 30, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 30, "excluded_lines": 0}, "missing_lines": [603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632], "excluded_lines": []}, "handle_set_kdf_iterations": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 38, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 38, "excluded_lines": 0}, "missing_lines": [637, 638, 640, 641, 642, 643, 644, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681], "excluded_lines": []}, "handle_set_additional_backup_location": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 39, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 39, "excluded_lines": 0}, "missing_lines": [686, 687, 688, 689, 690, 691, 692, 693, 695, 696, 697, 698, 699, 701, 704, 705, 706, 707, 708, 709, 710, 711, 713, 714, 715, 716, 717, 718, 719, 720, 721, 723, 724, 725, 726, 727, 728, 729, 730], "excluded_lines": []}, "handle_set_profile_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [735, 736, 737, 738, 739, 740, 741, 743, 744, 745, 746, 747, 749], "excluded_lines": []}, "handle_toggle_secret_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 46, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 46, "excluded_lines": 0}, "missing_lines": [754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800], "excluded_lines": []}, "handle_toggle_quick_unlock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 32, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 32, "excluded_lines": 0}, "missing_lines": [805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837], "excluded_lines": []}, "handle_toggle_offline_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 0}, "missing_lines": [842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875], "excluded_lines": []}, "handle_profiles_menu": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [880, 881, 886, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 914], "excluded_lines": []}, "handle_nostr_menu": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 39, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 39, "excluded_lines": 0}, "missing_lines": [919, 920, 921, 922, 923, 924, 925, 926, 927, 929, 930, 935, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 968], "excluded_lines": []}, "handle_settings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 88, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 88, "excluded_lines": 0}, "missing_lines": [973, 974, 979, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1070], "excluded_lines": []}, "display_menu": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 107, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 107, "excluded_lines": 0}, "missing_lines": [1081, 1092, 1093, 1094, 1095, 1096, 1097, 1102, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1117, 1118, 1119, 1123, 1124, 1126, 1129, 1130, 1131, 1132, 1133, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1165, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1234], "excluded_lines": []}, "main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 159, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 159, "excluded_lines": 0}, "missing_lines": [1247, 1248, 1249, 1250, 1251, 1253, 1254, 1255, 1256, 1260, 1265, 1270, 1276, 1278, 1279, 1280, 1286, 1287, 1289, 1290, 1292, 1293, 1295, 1296, 1298, 1300, 1301, 1302, 1303, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1335, 1336, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1350, 1351, 1352, 1353, 1355, 1356, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1416, 1418, 1430, 1431, 1433, 1434, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470], "excluded_lines": []}, "main.signal_handler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 68, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 68, "excluded_lines": 0}, "missing_lines": [2, 3, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 33, 40, 41, 42, 47, 49, 51, 58, 71, 84, 116, 117, 134, 149, 165, 166, 210, 223, 276, 298, 316, 363, 372, 408, 435, 473, 490, 501, 514, 545, 582, 601, 635, 684, 733, 752, 803, 840, 878, 917, 971, 1073, 1237, 1473, 1474], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1067, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1067, "excluded_lines": 5}, "missing_lines": [2, 3, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 33, 40, 41, 42, 47, 49, 51, 58, 60, 61, 62, 63, 64, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 84, 87, 88, 90, 91, 92, 93, 95, 96, 98, 101, 102, 104, 105, 106, 107, 108, 110, 112, 113, 116, 117, 124, 125, 126, 127, 128, 129, 131, 134, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 149, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 165, 166, 172, 173, 174, 175, 181, 183, 184, 185, 186, 188, 189, 190, 191, 193, 194, 195, 200, 201, 202, 204, 205, 206, 207, 210, 216, 217, 218, 219, 220, 223, 225, 226, 227, 228, 229, 231, 232, 233, 234, 236, 237, 238, 239, 241, 242, 245, 247, 248, 249, 250, 251, 252, 254, 257, 260, 261, 268, 270, 271, 272, 273, 276, 282, 283, 284, 285, 286, 288, 289, 290, 291, 292, 293, 294, 295, 298, 302, 303, 304, 305, 306, 308, 309, 310, 311, 312, 313, 316, 324, 325, 326, 327, 328, 330, 331, 332, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 363, 365, 366, 372, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 398, 399, 400, 401, 402, 403, 404, 405, 408, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 426, 427, 428, 429, 430, 432, 435, 437, 438, 439, 440, 446, 447, 449, 450, 453, 454, 455, 456, 457, 458, 459, 465, 466, 467, 468, 470, 473, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 490, 492, 493, 494, 495, 496, 497, 498, 501, 503, 504, 505, 506, 507, 508, 509, 510, 511, 514, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 542, 545, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 570, 571, 572, 573, 574, 575, 576, 577, 579, 582, 584, 585, 586, 587, 588, 590, 591, 592, 593, 594, 595, 596, 598, 601, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 635, 637, 638, 640, 641, 642, 643, 644, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 684, 686, 687, 688, 689, 690, 691, 692, 693, 695, 696, 697, 698, 699, 701, 704, 705, 706, 707, 708, 709, 710, 711, 713, 714, 715, 716, 717, 718, 719, 720, 721, 723, 724, 725, 726, 727, 728, 729, 730, 733, 735, 736, 737, 738, 739, 740, 741, 743, 744, 745, 746, 747, 749, 752, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 803, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 840, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 878, 880, 881, 886, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 914, 917, 919, 920, 921, 922, 923, 924, 925, 926, 927, 929, 930, 935, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 968, 971, 973, 974, 979, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1070, 1073, 1081, 1092, 1093, 1094, 1095, 1096, 1097, 1102, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1117, 1118, 1119, 1123, 1124, 1126, 1129, 1130, 1131, 1132, 1133, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1165, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1234, 1237, 1247, 1248, 1249, 1250, 1251, 1253, 1254, 1255, 1256, 1260, 1265, 1270, 1276, 1278, 1279, 1280, 1286, 1287, 1289, 1290, 1292, 1293, 1295, 1296, 1298, 1300, 1301, 1302, 1303, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1335, 1336, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1350, 1351, 1352, 1353, 1355, 1356, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1416, 1418, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1430, 1431, 1433, 1434, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470, 1473, 1474], "excluded_lines": [333, 334, 367, 368, 369]}}}, "src/nostr/__init__.py": {"executed_lines": [3, 5, 6, 8, 16, 18, 29, 30, 32, 34], "summary": {"covered_lines": 9, "num_statements": 11, "percent_covered": 81.81818181818181, "percent_covered_display": "82", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [31, 33], "excluded_lines": [], "functions": {"__getattr__": {"executed_lines": [30, 32, 34], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [31, 33], "excluded_lines": []}, "": {"executed_lines": [3, 5, 6, 8, 16, 18, 29], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 5, 6, 8, 16, 18, 29, 30, 32, 34], "summary": {"covered_lines": 9, "num_statements": 11, "percent_covered": 81.81818181818181, "percent_covered_display": "82", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [31, 33], "excluded_lines": []}}}, "src/nostr/backup_models.py": {"executed_lines": [1, 2, 5, 6, 7, 10, 11, 12, 14, 15, 16, 17, 20, 21, 22, 24, 25, 26, 27, 28], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [1, 2, 5, 6, 7, 10, 11, 12, 14, 15, 16, 17, 20, 21, 22, 24, 25, 26, 27, 28], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"ChunkMeta": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Manifest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 7, 10, 11, 12, 14, 15, 16, 17, 20, 21, 22, 24, 25, 26, 27, 28], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/client.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 22, 24, 25, 27, 34, 35, 36, 38, 42, 43, 45, 46, 49, 50, 52, 113], "summary": {"covered_lines": 24, "num_statements": 58, "percent_covered": 41.37931034482759, "percent_covered_display": "41", "missing_lines": 34, "excluded_lines": 2}, "missing_lines": [63, 64, 65, 66, 67, 69, 70, 73, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 88, 90, 91, 92, 93, 94, 97, 99, 100, 101, 102, 103, 104, 107, 108, 110], "excluded_lines": [38, 39], "functions": {"NostrClient.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 34, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 34, "excluded_lines": 0}, "missing_lines": [63, 64, 65, 66, 67, 69, 70, 73, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 88, 90, 91, 92, 93, 94, 97, 99, 100, 101, 102, 103, 104, 107, 108, 110], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 22, 24, 25, 27, 34, 35, 36, 38, 42, 43, 45, 46, 49, 50, 52, 113], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [38, 39]}}, "classes": {"NostrClient": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 34, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 34, "excluded_lines": 0}, "missing_lines": [63, 64, 65, 66, 67, 69, 70, 73, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 88, 90, 91, 92, 93, 94, 97, 99, 100, 101, 102, 103, 104, 107, 108, 110], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 22, 24, 25, 27, 34, 35, 36, 38, 42, 43, 45, 46, 49, 50, 52, 113], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [38, 39]}}}, "src/nostr/coincurve_keys.py": {"executed_lines": [1, 3, 4, 7, 8, 10, 28, 29, 34, 35, 42, 45], "summary": {"covered_lines": 11, "num_statements": 33, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [11, 12, 13, 14, 15, 17, 18, 20, 21, 22, 23, 24, 26, 31, 32, 36, 37, 38, 39, 40, 43, 46], "excluded_lines": [], "functions": {"Keys.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [11, 12, 13, 14, 15, 17, 18, 20, 21, 22, 23, 24, 26], "excluded_lines": []}, "Keys.hex_to_bech32": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [31, 32], "excluded_lines": []}, "Keys.bech32_to_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [36, 37, 38, 39, 40], "excluded_lines": []}, "Keys.private_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [43], "excluded_lines": []}, "Keys.public_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [46], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 7, 8, 10, 28, 29, 34, 35, 42, 45], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"Keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [11, 12, 13, 14, 15, 17, 18, 20, 21, 22, 23, 24, 26, 31, 32, 36, 37, 38, 39, 40, 43, 46], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 7, 8, 10, 28, 29, 34, 35, 42, 45], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/connection.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 15, 22, 23, 25, 32, 38, 45, 69, 93, 103, 109, 148, 155, 164, 201, 225], "summary": {"covered_lines": 26, "num_statements": 155, "percent_covered": 16.774193548387096, "percent_covered_display": "17", "missing_lines": 129, "excluded_lines": 0}, "missing_lines": [27, 28, 29, 30, 34, 35, 36, 40, 41, 42, 43, 46, 47, 49, 50, 51, 52, 53, 54, 55, 57, 59, 60, 62, 63, 65, 66, 67, 71, 72, 73, 80, 81, 84, 85, 86, 87, 88, 89, 90, 91, 94, 95, 96, 97, 98, 101, 105, 106, 107, 116, 117, 118, 119, 120, 121, 123, 124, 125, 129, 130, 131, 132, 133, 135, 140, 141, 143, 144, 145, 146, 150, 151, 152, 153, 157, 158, 159, 160, 161, 162, 168, 169, 171, 172, 173, 174, 176, 181, 182, 183, 184, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 202, 203, 204, 205, 206, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 227, 228, 229, 230, 231, 232], "excluded_lines": [], "functions": {"ConnectionHandler.connect": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [27, 28, 29, 30], "excluded_lines": []}, "ConnectionHandler.initialize_client_pool": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [34, 35, 36], "excluded_lines": []}, "ConnectionHandler._connect_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [40, 41, 42, 43], "excluded_lines": []}, "ConnectionHandler._initialize_client_pool": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [46, 47, 49, 50, 51, 52, 53, 54, 55, 57, 59, 60, 62, 63, 65, 66, 67], "excluded_lines": []}, "ConnectionHandler._ping_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [71, 72, 73, 80, 81, 84, 85, 86, 87, 88, 89, 90, 91], "excluded_lines": []}, "ConnectionHandler._check_relay_health": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [94, 95, 96, 97, 98, 101], "excluded_lines": []}, "ConnectionHandler.check_relay_health": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [105, 106, 107], "excluded_lines": []}, "ConnectionHandler.publish_json_to_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [116, 117, 118, 119, 120, 121, 123, 124, 125, 129, 130, 131, 132, 133, 135, 140, 141, 143, 144, 145, 146], "excluded_lines": []}, "ConnectionHandler.publish_event": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [150, 151, 152, 153], "excluded_lines": []}, "ConnectionHandler.update_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [157, 158, 159, 160, 161, 162], "excluded_lines": []}, "ConnectionHandler.retrieve_json_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [168, 169, 171, 172, 173, 174, 176, 181, 182, 183, 184, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199], "excluded_lines": []}, "ConnectionHandler._retrieve_json_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [202, 203, 204, 205, 206, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223], "excluded_lines": []}, "ConnectionHandler.close_client_pool": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [227, 228, 229, 230, 231, 232], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 15, 22, 23, 25, 32, 38, 45, 69, 93, 103, 109, 148, 155, 164, 201, 225], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"ConnectionHandler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 129, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 129, "excluded_lines": 0}, "missing_lines": [27, 28, 29, 30, 34, 35, 36, 40, 41, 42, 43, 46, 47, 49, 50, 51, 52, 53, 54, 55, 57, 59, 60, 62, 63, 65, 66, 67, 71, 72, 73, 80, 81, 84, 85, 86, 87, 88, 89, 90, 91, 94, 95, 96, 97, 98, 101, 105, 106, 107, 116, 117, 118, 119, 120, 121, 123, 124, 125, 129, 130, 131, 132, 133, 135, 140, 141, 143, 144, 145, 146, 150, 151, 152, 153, 157, 158, 159, 160, 161, 162, 168, 169, 171, 172, 173, 174, 176, 181, 182, 183, 184, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 202, 203, 204, 205, 206, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 227, 228, 229, 230, 231, 232], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 15, 22, 23, 25, 32, 38, 45, 69, 93, 103, 109, 148, 155, 164, 201, 225], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/key_manager.py": {"executed_lines": [3, 4, 5, 7, 8, 9, 12, 13, 15, 18, 19, 21, 64, 80, 97, 111, 122, 131, 140, 157], "summary": {"covered_lines": 19, "num_statements": 84, "percent_covered": 22.61904761904762, "percent_covered_display": "23", "missing_lines": 65, "excluded_lines": 0}, "missing_lines": [36, 37, 38, 41, 42, 46, 47, 48, 49, 54, 57, 58, 60, 61, 62, 71, 72, 73, 74, 75, 76, 77, 78, 82, 83, 85, 89, 90, 91, 92, 93, 94, 95, 99, 100, 103, 106, 107, 108, 109, 113, 114, 117, 118, 119, 120, 129, 138, 147, 148, 149, 150, 151, 152, 153, 154, 155, 159, 160, 161, 162, 163, 164, 165, 166], "excluded_lines": [], "functions": {"KeyManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [36, 37, 38, 41, 42, 46, 47, 48, 49, 54, 57, 58, 60, 61, 62], "excluded_lines": []}, "KeyManager.initialize_bip85": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [71, 72, 73, 74, 75, 76, 77, 78], "excluded_lines": []}, "KeyManager.generate_nostr_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [82, 83, 85, 89, 90, 91, 92, 93, 94, 95], "excluded_lines": []}, "KeyManager.generate_v1_nostr_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [99, 100, 103, 106, 107, 108, 109], "excluded_lines": []}, "KeyManager.generate_legacy_nostr_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [113, 114, 117, 118, 119, 120], "excluded_lines": []}, "KeyManager.get_public_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [129], "excluded_lines": []}, "KeyManager.get_private_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [138], "excluded_lines": []}, "KeyManager.get_npub": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [147, 148, 149, 150, 151, 152, 153, 154, 155], "excluded_lines": []}, "KeyManager.get_nsec": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [159, 160, 161, 162, 163, 164, 165, 166], "excluded_lines": []}, "": {"executed_lines": [3, 4, 5, 7, 8, 9, 12, 13, 15, 18, 19, 21, 64, 80, 97, 111, 122, 131, 140, 157], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"KeyManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 65, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 65, "excluded_lines": 0}, "missing_lines": [36, 37, 38, 41, 42, 46, 47, 48, 49, 54, 57, 58, 60, 61, 62, 71, 72, 73, 74, 75, 76, 77, 78, 82, 83, 85, 89, 90, 91, 92, 93, 94, 95, 99, 100, 103, 106, 107, 108, 109, 113, 114, 117, 118, 119, 120, 129, 138, 147, 148, 149, 150, 151, 152, 153, 154, 155, 159, 160, 161, 162, 163, 164, 165, 166], "excluded_lines": []}, "": {"executed_lines": [3, 4, 5, 7, 8, 9, 12, 13, 15, 18, 19, 21, 64, 80, 97, 111, 122, 131, 140, 157], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/snapshot.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 25, 26, 29, 49, 62, 63, 65, 137, 221, 279, 312, 348, 394, 433, 437, 441], "summary": {"covered_lines": 29, "num_statements": 264, "percent_covered": 10.984848484848484, "percent_covered_display": "11", "missing_lines": 235, "excluded_lines": 11}, "missing_lines": [33, 34, 35, 36, 37, 45, 46, 57, 58, 59, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 90, 91, 92, 93, 96, 97, 99, 104, 105, 107, 108, 110, 120, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 140, 141, 142, 143, 144, 155, 156, 158, 159, 160, 162, 167, 168, 169, 170, 172, 173, 174, 175, 176, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 245, 246, 252, 253, 262, 263, 265, 266, 267, 268, 269, 277, 281, 282, 283, 284, 285, 286, 287, 290, 291, 292, 293, 294, 295, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 314, 315, 316, 317, 318, 319, 320, 321, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 349, 350, 351, 352, 353, 354, 355, 358, 359, 360, 361, 364, 365, 366, 367, 368, 369, 370, 381, 389, 390, 391, 392, 395, 396, 397, 398, 399, 405, 406, 407, 410, 411, 412, 413, 414, 415, 416, 420, 421, 422, 423, 424, 427, 430, 431, 434, 435, 438, 439, 442, 443], "excluded_lines": [236, 237, 238, 243, 254, 255, 256, 261, 270, 271, 272], "functions": {"prepare_snapshot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [33, 34, 35, 36, 37, 45, 46], "excluded_lines": []}, "new_manifest_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [57, 58, 59], "excluded_lines": []}, "SnapshotHandler.publish_snapshot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 0}, "missing_lines": [68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 90, 91, 92, 93, 96, 97, 99, 104, 105, 107, 108, 110, 120, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135], "excluded_lines": []}, "SnapshotHandler._fetch_chunks_with_retry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 57, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 57, "excluded_lines": 0}, "missing_lines": [140, 141, 142, 143, 144, 155, 156, 158, 159, 160, 162, 167, 168, 169, 170, 172, 173, 174, 175, 176, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219], "excluded_lines": []}, "SnapshotHandler._fetch_manifest_with_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 11}, "missing_lines": [225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 245, 246, 252, 253, 262, 263, 265, 266, 267, 268, 269, 277], "excluded_lines": [236, 237, 238, 243, 254, 255, 256, 261, 270, 271, 272]}, "SnapshotHandler.fetch_latest_snapshot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 0}, "missing_lines": [281, 282, 283, 284, 285, 286, 287, 290, 291, 292, 293, 294, 295, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310], "excluded_lines": []}, "SnapshotHandler.ensure_manifest_is_current": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 27, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 27, "excluded_lines": 0}, "missing_lines": [314, 315, 316, 317, 318, 319, 320, 321, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346], "excluded_lines": []}, "SnapshotHandler.publish_delta": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [349, 350, 351, 352, 353, 354, 355, 358, 359, 360, 361, 364, 365, 366, 367, 368, 369, 370, 381, 389, 390, 391, 392], "excluded_lines": []}, "SnapshotHandler.fetch_deltas_since": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [395, 396, 397, 398, 399, 405, 406, 407, 410, 411, 412, 413, 414, 415, 416, 420, 421, 422, 423, 424, 427, 430, 431], "excluded_lines": []}, "SnapshotHandler.get_current_manifest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [434, 435], "excluded_lines": []}, "SnapshotHandler.get_current_manifest_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [438, 439], "excluded_lines": []}, "SnapshotHandler.get_delta_events": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [442, 443], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 25, 26, 29, 49, 62, 63, 65, 137, 221, 279, 312, 348, 394, 433, 437, 441], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"SnapshotHandler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 225, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 225, "excluded_lines": 11}, "missing_lines": [68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 90, 91, 92, 93, 96, 97, 99, 104, 105, 107, 108, 110, 120, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 140, 141, 142, 143, 144, 155, 156, 158, 159, 160, 162, 167, 168, 169, 170, 172, 173, 174, 175, 176, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 245, 246, 252, 253, 262, 263, 265, 266, 267, 268, 269, 277, 281, 282, 283, 284, 285, 286, 287, 290, 291, 292, 293, 294, 295, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 314, 315, 316, 317, 318, 319, 320, 321, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 349, 350, 351, 352, 353, 354, 355, 358, 359, 360, 361, 364, 365, 366, 367, 368, 369, 370, 381, 389, 390, 391, 392, 395, 396, 397, 398, 399, 405, 406, 407, 410, 411, 412, 413, 414, 415, 416, 420, 421, 422, 423, 424, 427, 430, 431, 434, 435, 438, 439, 442, 443], "excluded_lines": [236, 237, 238, 243, 254, 255, 256, 261, 270, 271, 272]}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 25, 26, 29, 49, 62, 63, 65, 137, 221, 279, 312, 348, 394, 433, 437, 441], "summary": {"covered_lines": 29, "num_statements": 39, "percent_covered": 74.35897435897436, "percent_covered_display": "74", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [33, 34, 35, 36, 37, 45, 46, 57, 58, 59], "excluded_lines": []}}}, "src/seedpass/__init__.py": {"executed_lines": [1], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [1], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/api.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 20, 22, 23, 24, 25, 27, 28, 29, 31, 32, 33, 35, 36, 38, 41, 47, 56, 70, 104, 110, 123, 124, 143, 144, 159, 160, 279, 280, 310, 311, 321, 322, 332, 333, 345, 346, 379, 380, 400, 401, 409, 410, 420, 421, 431, 432, 446, 447, 460, 461, 486, 487, 496, 497, 513, 514, 520, 521, 529, 530, 551, 552, 571, 572, 586, 587, 597, 598, 608, 609, 625, 626, 668, 669, 694, 695, 706, 707, 732, 733, 743, 744], "summary": {"covered_lines": 95, "num_statements": 378, "percent_covered": 25.132275132275133, "percent_covered_display": "25", "missing_lines": 283, "excluded_lines": 0}, "missing_lines": [42, 43, 44, 48, 49, 50, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 89, 94, 95, 101, 105, 106, 107, 116, 117, 118, 119, 120, 127, 128, 129, 130, 150, 151, 152, 153, 154, 155, 156, 171, 172, 174, 176, 177, 187, 189, 197, 199, 200, 202, 214, 216, 217, 225, 227, 228, 238, 240, 241, 249, 251, 252, 259, 261, 262, 267, 274, 276, 291, 292, 293, 294, 305, 306, 307, 315, 316, 317, 318, 326, 327, 328, 329, 336, 337, 338, 340, 341, 342, 353, 354, 355, 356, 367, 369, 370, 372, 373, 375, 376, 384, 385, 386, 388, 390, 391, 392, 393, 394, 395, 396, 397, 404, 405, 406, 414, 415, 416, 417, 425, 426, 427, 428, 436, 437, 438, 440, 441, 442, 443, 453, 454, 455, 456, 457, 467, 468, 469, 470, 473, 474, 475, 476, 478, 480, 483, 491, 492, 493, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 515, 516, 517, 523, 524, 525, 526, 534, 535, 536, 538, 539, 540, 541, 543, 544, 545, 546, 547, 548, 556, 557, 558, 559, 561, 562, 563, 564, 565, 566, 567, 568, 576, 577, 578, 580, 581, 582, 583, 591, 592, 593, 594, 602, 603, 604, 605, 615, 616, 617, 618, 619, 620, 621, 622, 630, 631, 633, 635, 636, 637, 639, 640, 641, 642, 643, 644, 645, 646, 648, 650, 651, 653, 654, 656, 657, 658, 663, 664, 665, 676, 677, 678, 680, 682, 684, 686, 687, 688, 689, 690, 691, 699, 700, 701, 703, 711, 712, 713, 715, 725, 727, 728, 729, 737, 738, 739, 740, 747, 748, 750], "excluded_lines": [], "functions": {"_get_pm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [42, 43, 44], "excluded_lines": []}, "_check_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [48, 49, 50, 51, 52, 53], "excluded_lines": []}, "_reload_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [58, 59, 60, 61, 62, 63, 64, 65, 66, 67], "excluded_lines": []}, "start_server": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 89, 94, 95, 101], "excluded_lines": []}, "_require_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [105, 106, 107], "excluded_lines": []}, "_validate_encryption_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [116, 117, 118, 119, 120], "excluded_lines": []}, "search_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [127, 128, 129, 130], "excluded_lines": []}, "get_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [150, 151, 152, 153, 154, 155, 156], "excluded_lines": []}, "create_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 29, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 29, "excluded_lines": 0}, "missing_lines": [171, 172, 174, 176, 177, 187, 189, 197, 199, 200, 202, 214, 216, 217, 225, 227, 228, 238, 240, 241, 249, 251, 252, 259, 261, 262, 267, 274, 276], "excluded_lines": []}, "update_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [291, 292, 293, 294, 305, 306, 307], "excluded_lines": []}, "archive_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [315, 316, 317, 318], "excluded_lines": []}, "unarchive_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [326, 327, 328, 329], "excluded_lines": []}, "get_config": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [336, 337, 338, 340, 341, 342], "excluded_lines": []}, "update_config": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [353, 354, 355, 356, 367, 369, 370, 372, 373, 375, 376], "excluded_lines": []}, "set_secret_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [384, 385, 386, 388, 390, 391, 392, 393, 394, 395, 396, 397], "excluded_lines": []}, "list_fingerprints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [404, 405, 406], "excluded_lines": []}, "add_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [414, 415, 416, 417], "excluded_lines": []}, "remove_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [425, 426, 427, 428], "excluded_lines": []}, "select_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [436, 437, 438, 440, 441, 442, 443], "excluded_lines": []}, "export_totp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [453, 454, 455, 456, 457], "excluded_lines": []}, "get_totp_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [467, 468, 469, 470, 473, 474, 475, 476, 478, 480, 483], "excluded_lines": []}, "get_profile_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [491, 492, 493], "excluded_lines": []}, "get_notifications": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510], "excluded_lines": []}, "get_nostr_pubkey": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [515, 516, 517], "excluded_lines": []}, "list_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [523, 524, 525, 526], "excluded_lines": []}, "add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [534, 535, 536, 538, 539, 540, 541, 543, 544, 545, 546, 547, 548], "excluded_lines": []}, "remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [556, 557, 558, 559, 561, 562, 563, 564, 565, 566, 567, 568], "excluded_lines": []}, "reset_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [576, 577, 578, 580, 581, 582, 583], "excluded_lines": []}, "verify_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [591, 592, 593, 594], "excluded_lines": []}, "update_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [602, 603, 604, 605], "excluded_lines": []}, "export_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [615, 616, 617, 618, 619, 620, 621, 622], "excluded_lines": []}, "import_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [630, 631, 633, 635, 636, 637, 639, 640, 641, 642, 643, 644, 645, 646, 648, 650, 651, 653, 654, 656, 657, 658, 663, 664, 665], "excluded_lines": []}, "backup_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [676, 677, 678, 680, 682, 684, 686, 687, 688, 689, 690, 691], "excluded_lines": []}, "change_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [699, 700, 701, 703], "excluded_lines": []}, "generate_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [711, 712, 713, 715, 725, 727, 728, 729], "excluded_lines": []}, "lock_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [737, 738, 739, 740], "excluded_lines": []}, "shutdown_server": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [747, 748, 750], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 20, 22, 23, 24, 25, 27, 28, 29, 31, 32, 33, 35, 36, 38, 41, 47, 56, 70, 104, 110, 123, 124, 143, 144, 159, 160, 279, 280, 310, 311, 321, 322, 332, 333, 345, 346, 379, 380, 400, 401, 409, 410, 420, 421, 431, 432, 446, 447, 460, 461, 486, 487, 496, 497, 513, 514, 520, 521, 529, 530, 551, 552, 571, 572, 586, 587, 597, 598, 608, 609, 625, 626, 668, 669, 694, 695, 706, 707, 732, 733, 743, 744], "summary": {"covered_lines": 95, "num_statements": 95, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 20, 22, 23, 24, 25, 27, 28, 29, 31, 32, 33, 35, 36, 38, 41, 47, 56, 70, 104, 110, 123, 124, 143, 144, 159, 160, 279, 280, 310, 311, 321, 322, 332, 333, 345, 346, 379, 380, 400, 401, 409, 410, 420, 421, 431, 432, 446, 447, 460, 461, 486, 487, 496, 497, 513, 514, 520, 521, 529, 530, 551, 552, 571, 572, 586, 587, 597, 598, 608, 609, 625, 626, 668, 669, 694, 695, 706, 707, 732, 733, 743, 744], "summary": {"covered_lines": 95, "num_statements": 378, "percent_covered": 25.132275132275133, "percent_covered_display": "25", "missing_lines": 283, "excluded_lines": 0}, "missing_lines": [42, 43, 44, 48, 49, 50, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 89, 94, 95, 101, 105, 106, 107, 116, 117, 118, 119, 120, 127, 128, 129, 130, 150, 151, 152, 153, 154, 155, 156, 171, 172, 174, 176, 177, 187, 189, 197, 199, 200, 202, 214, 216, 217, 225, 227, 228, 238, 240, 241, 249, 251, 252, 259, 261, 262, 267, 274, 276, 291, 292, 293, 294, 305, 306, 307, 315, 316, 317, 318, 326, 327, 328, 329, 336, 337, 338, 340, 341, 342, 353, 354, 355, 356, 367, 369, 370, 372, 373, 375, 376, 384, 385, 386, 388, 390, 391, 392, 393, 394, 395, 396, 397, 404, 405, 406, 414, 415, 416, 417, 425, 426, 427, 428, 436, 437, 438, 440, 441, 442, 443, 453, 454, 455, 456, 457, 467, 468, 469, 470, 473, 474, 475, 476, 478, 480, 483, 491, 492, 493, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 515, 516, 517, 523, 524, 525, 526, 534, 535, 536, 538, 539, 540, 541, 543, 544, 545, 546, 547, 548, 556, 557, 558, 559, 561, 562, 563, 564, 565, 566, 567, 568, 576, 577, 578, 580, 581, 582, 583, 591, 592, 593, 594, 602, 603, 604, 605, 615, 616, 617, 618, 619, 620, 621, 622, 630, 631, 633, 635, 636, 637, 639, 640, 641, 642, 643, 644, 645, 646, 648, 650, 651, 653, 654, 656, 657, 658, 663, 664, 665, 676, 677, 678, 680, 682, 684, 686, 687, 688, 689, 690, 691, 699, 700, 701, 703, 711, 712, 713, 715, 725, 727, 728, 729, 737, 738, 739, 740, 747, 748, 750], "excluded_lines": []}}}, "src/seedpass/cli/__init__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 78, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 78, "excluded_lines": 2}, "missing_lines": [1, 3, 4, 5, 6, 7, 9, 11, 12, 14, 20, 27, 33, 40, 42, 43, 44, 45, 46, 47, 48, 51, 53, 54, 55, 56, 57, 60, 62, 63, 64, 65, 68, 69, 79, 84, 85, 86, 89, 90, 92, 93, 94, 97, 98, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 125, 129, 131, 132, 137, 139, 142, 143, 145, 150, 151, 162, 163, 164, 169, 171, 172, 176, 178, 180], "excluded_lines": [183, 184], "functions": {"run": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [53, 54, 55, 56, 57], "excluded_lines": []}, "_gui_backend_available": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [62, 63, 64, 65], "excluded_lines": []}, "main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [79, 84, 85, 86], "excluded_lines": []}, "root_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [92, 93, 94], "excluded_lines": []}, "gui": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 0}, "missing_lines": [111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 125, 129, 131, 132, 137, 139, 142, 143, 145, 150, 151, 162, 163, 164, 169, 171, 172, 176, 178, 180], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 29, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 29, "excluded_lines": 2}, "missing_lines": [1, 3, 4, 5, 6, 7, 9, 11, 12, 14, 20, 27, 33, 40, 42, 43, 44, 45, 46, 47, 48, 51, 60, 68, 69, 89, 90, 97, 98], "excluded_lines": [183, 184]}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 78, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 78, "excluded_lines": 2}, "missing_lines": [1, 3, 4, 5, 6, 7, 9, 11, 12, 14, 20, 27, 33, 40, 42, 43, 44, 45, 46, 47, 48, 51, 53, 54, 55, 56, 57, 60, 62, 63, 64, 65, 68, 69, 79, 84, 85, 86, 89, 90, 92, 93, 94, 97, 98, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 125, 129, 131, 132, 137, 139, 142, 143, 145, 150, 151, 162, 163, 164, 169, 171, 172, 176, 178, 180], "excluded_lines": [183, 184]}}}, "src/seedpass/cli/api.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 2}, "missing_lines": [1, 3, 4, 6, 8, 11, 12, 14, 15, 18, 21, 22, 28, 30, 31], "excluded_lines": [36, 37], "functions": {"api_start": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [14, 15, 18], "excluded_lines": []}, "api_stop": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 2}, "missing_lines": [28, 30, 31], "excluded_lines": [36, 37]}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [1, 3, 4, 6, 8, 11, 12, 21, 22], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 2}, "missing_lines": [1, 3, 4, 6, 8, 11, 12, 14, 15, 18, 21, 22, 28, 30, 31], "excluded_lines": [36, 37]}}}, "src/seedpass/cli/common.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 30, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 30, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 6, 7, 23, 25, 26, 27, 29, 30, 31, 32, 33, 34, 37, 42, 43, 46, 47, 48, 51, 52, 53, 56, 57, 58, 61, 62, 63], "excluded_lines": [], "functions": {"_get_pm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [25, 26, 27, 29, 30, 31, 32, 33, 34], "excluded_lines": []}, "_get_services": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [42, 43], "excluded_lines": []}, "_get_entry_service": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [47, 48], "excluded_lines": []}, "_get_config_service": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [52, 53], "excluded_lines": []}, "_get_util_service": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [57, 58], "excluded_lines": []}, "_get_nostr_service": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [62, 63], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 6, 7, 23, 37, 46, 51, 56, 61], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 30, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 30, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 6, 7, 23, 25, 26, 27, 29, 30, 31, 32, 33, 34, 37, 42, 43, 46, 47, 48, 51, 52, 53, 56, 57, 58, 61, 62, 63], "excluded_lines": []}}}, "src/seedpass/cli/config.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 62, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 62, "excluded_lines": 15}, "missing_lines": [1, 3, 5, 7, 10, 11, 13, 14, 15, 16, 18, 21, 22, 24, 26, 27, 32, 33, 34, 35, 40, 43, 44, 50, 51, 52, 53, 58, 59, 66, 67, 68, 69, 71, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 90, 91, 94, 95, 97, 98, 99, 104, 105, 112, 113, 114, 115, 117, 118, 123, 124], "excluded_lines": [36, 37, 38, 54, 55, 56, 86, 87, 88, 100, 101, 102, 119, 120, 121], "functions": {"config_get": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [13, 14, 15, 16, 18], "excluded_lines": []}, "config_set": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 3}, "missing_lines": [24, 26, 27, 32, 33, 34, 35, 40], "excluded_lines": [36, 37, 38]}, "config_toggle_secret_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 24, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 24, "excluded_lines": 6}, "missing_lines": [50, 51, 52, 53, 58, 59, 66, 67, 68, 69, 71, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 90, 91], "excluded_lines": [54, 55, 56, 86, 87, 88]}, "config_toggle_offline": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 6}, "missing_lines": [97, 98, 99, 104, 105, 112, 113, 114, 115, 117, 118, 123, 124], "excluded_lines": [100, 101, 102, 119, 120, 121]}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 7, 10, 11, 21, 22, 43, 44, 94, 95], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 62, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 62, "excluded_lines": 15}, "missing_lines": [1, 3, 5, 7, 10, 11, 13, 14, 15, 16, 18, 21, 22, 24, 26, 27, 32, 33, 34, 35, 40, 43, 44, 50, 51, 52, 53, 58, 59, 66, 67, 68, 69, 71, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 90, 91, 94, 95, 97, 98, 99, 104, 105, 112, 113, 114, 115, 117, 118, 123, 124], "excluded_lines": [36, 37, 38, 54, 55, 56, 86, 87, 88, 100, 101, 102, 119, 120, 121]}}}, "src/seedpass/cli/entry.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 156, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 156, "excluded_lines": 0}, "missing_lines": [1, 3, 4, 5, 6, 8, 9, 11, 12, 13, 15, 18, 19, 33, 34, 39, 40, 41, 42, 43, 44, 45, 46, 47, 50, 51, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 115, 118, 119, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 166, 167, 170, 171, 183, 184, 192, 195, 196, 203, 204, 209, 212, 213, 222, 223, 230, 233, 234, 241, 242, 247, 250, 251, 259, 260, 266, 269, 270, 278, 279, 280, 283, 284, 291, 292, 297, 300, 301, 316, 317, 318, 329, 330, 331, 332, 335, 336, 338, 339, 340, 343, 344, 346, 347, 348, 351, 352, 354, 355, 358, 359, 363, 364, 365, 366], "excluded_lines": [], "functions": {"entry_list": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [33, 34, 39, 40, 41, 42, 43, 44, 45, 46, 47], "excluded_lines": []}, "entry_search": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75], "excluded_lines": []}, "entry_get": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 29, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 29, "excluded_lines": 0}, "missing_lines": [81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 115], "excluded_lines": []}, "entry_add": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 166, 167], "excluded_lines": []}, "entry_add_totp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [183, 184, 192], "excluded_lines": []}, "entry_add_ssh": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [203, 204, 209], "excluded_lines": []}, "entry_add_pgp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [222, 223, 230], "excluded_lines": []}, "entry_add_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [241, 242, 247], "excluded_lines": []}, "entry_add_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [259, 260, 266], "excluded_lines": []}, "entry_add_key_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [278, 279, 280], "excluded_lines": []}, "entry_add_managed_account": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [291, 292, 297], "excluded_lines": []}, "entry_modify": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [316, 317, 318, 329, 330, 331, 332], "excluded_lines": []}, "entry_archive": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [338, 339, 340], "excluded_lines": []}, "entry_unarchive": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [346, 347, 348], "excluded_lines": []}, "entry_totp_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [354, 355], "excluded_lines": []}, "entry_export_totp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [363, 364, 365, 366], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 43, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 43, "excluded_lines": 0}, "missing_lines": [1, 3, 4, 5, 6, 8, 9, 11, 12, 13, 15, 18, 19, 50, 51, 78, 79, 118, 119, 170, 171, 195, 196, 212, 213, 233, 234, 250, 251, 269, 270, 283, 284, 300, 301, 335, 336, 343, 344, 351, 352, 358, 359], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 156, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 156, "excluded_lines": 0}, "missing_lines": [1, 3, 4, 5, 6, 8, 9, 11, 12, 13, 15, 18, 19, 33, 34, 39, 40, 41, 42, 43, 44, 45, 46, 47, 50, 51, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 115, 118, 119, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 166, 167, 170, 171, 183, 184, 192, 195, 196, 203, 204, 209, 212, 213, 222, 223, 230, 233, 234, 241, 242, 247, 250, 251, 259, 260, 266, 269, 270, 278, 279, 280, 283, 284, 291, 292, 297, 300, 301, 316, 317, 318, 329, 330, 331, 332, 335, 336, 338, 339, 340, 343, 344, 346, 347, 348, 351, 352, 354, 355, 358, 359, 363, 364, 365, 366], "excluded_lines": []}}}, "src/seedpass/cli/fingerprint.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 7, 10, 11, 13, 14, 15, 18, 19, 21, 22, 25, 26, 28, 29, 32, 33, 35, 36, 37], "excluded_lines": [], "functions": {"fingerprint_list": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [13, 14, 15], "excluded_lines": []}, "fingerprint_add": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [21, 22], "excluded_lines": []}, "fingerprint_remove": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [28, 29], "excluded_lines": []}, "fingerprint_switch": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [35, 36, 37], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 7, 10, 11, 18, 19, 25, 26, 32, 33], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 7, 10, 11, 13, 14, 15, 18, 19, 21, 22, 25, 26, 28, 29, 32, 33, 35, 36, 37], "excluded_lines": []}}}, "src/seedpass/cli/nostr.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 39, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 39, "excluded_lines": 6}, "missing_lines": [1, 3, 5, 7, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 28, 29, 31, 32, 33, 36, 37, 39, 40, 41, 42, 45, 46, 48, 49, 50, 54, 57, 58, 60, 61, 62, 66], "excluded_lines": [51, 52, 53, 63, 64, 65], "functions": {"nostr_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [15, 16, 17, 18, 19, 20, 21, 22, 23, 25], "excluded_lines": []}, "nostr_get_pubkey": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [31, 32, 33], "excluded_lines": []}, "nostr_list_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [39, 40, 41, 42], "excluded_lines": []}, "nostr_add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 3}, "missing_lines": [48, 49, 50, 54], "excluded_lines": [51, 52, 53]}, "nostr_remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 3}, "missing_lines": [60, 61, 62, 66], "excluded_lines": [63, 64, 65]}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 7, 12, 13, 28, 29, 36, 37, 45, 46, 57, 58], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 39, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 39, "excluded_lines": 6}, "missing_lines": [1, 3, 5, 7, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 28, 29, 31, 32, 33, 36, 37, 39, 40, 41, 42, 45, 46, 48, 49, 50, 54, 57, 58, 60, 61, 62, 66], "excluded_lines": [51, 52, 53, 63, 64, 65]}}}, "src/seedpass/cli/util.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 35, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 35, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 7, 9, 12, 13, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 57, 58, 61, 62, 64, 65, 68, 69, 71, 72], "excluded_lines": [], "functions": {"generate_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 57, 58], "excluded_lines": []}, "verify_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [64, 65], "excluded_lines": []}, "update_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [71, 72], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 7, 9, 12, 13, 61, 62, 68, 69], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 35, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 35, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 7, 9, 12, 13, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 57, 58, 61, 62, 64, 65, 68, 69, 71, 72], "excluded_lines": []}}}, "src/seedpass/cli/vault.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 49, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 49, "excluded_lines": 6}, "missing_lines": [1, 3, 4, 5, 7, 9, 16, 19, 20, 24, 25, 26, 27, 30, 31, 35, 36, 37, 38, 41, 42, 44, 45, 46, 47, 48, 54, 57, 58, 60, 61, 62, 63, 67, 70, 71, 73, 74, 75, 78, 79, 81, 82, 83, 86, 87, 94, 95, 96], "excluded_lines": [51, 52, 53, 64, 65, 66], "functions": {"vault_export": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [24, 25, 26, 27], "excluded_lines": []}, "vault_import": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [35, 36, 37, 38], "excluded_lines": []}, "vault_change_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 3}, "missing_lines": [44, 45, 46, 47, 48, 54], "excluded_lines": [51, 52, 53]}, "vault_unlock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 3}, "missing_lines": [60, 61, 62, 63, 67], "excluded_lines": [64, 65, 66]}, "vault_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [73, 74, 75], "excluded_lines": []}, "vault_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [81, 82, 83], "excluded_lines": []}, "vault_reveal_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [94, 95, 96], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [1, 3, 4, 5, 7, 9, 16, 19, 20, 30, 31, 41, 42, 57, 58, 70, 71, 78, 79, 86, 87], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 49, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 49, "excluded_lines": 6}, "missing_lines": [1, 3, 4, 5, 7, 9, 16, 19, 20, 24, 25, 26, 27, 30, 31, 35, 36, 37, 38, 41, 42, 44, 45, 46, 47, 48, 54, 57, 58, 60, 61, 62, 63, 67, 70, 71, 73, 74, 75, 78, 79, 81, 82, 83, 86, 87, 94, 95, 96], "excluded_lines": [51, 52, 53, 64, 65, 66]}}}, "src/seedpass/core/__init__.py": {"executed_lines": [3, 5, 7, 17, 18, 20, 22, 24, 26, 28, 30], "summary": {"covered_lines": 10, "num_statements": 16, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [19, 21, 23, 25, 27, 29], "excluded_lines": [], "functions": {"__getattr__": {"executed_lines": [18, 20, 22, 24, 26, 28, 30], "summary": {"covered_lines": 7, "num_statements": 13, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [19, 21, 23, 25, 27, 29], "excluded_lines": []}, "": {"executed_lines": [3, 5, 7, 17], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 5, 7, 17, 18, 20, 22, 24, 26, 28, 30], "summary": {"covered_lines": 10, "num_statements": 16, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [19, 21, 23, 25, 27, 29], "excluded_lines": []}}}, "src/seedpass/core/api.py": {"executed_lines": [1, 3, 10, 11, 12, 13, 14, 16, 18, 19, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 41, 42, 44, 45, 48, 49, 51, 54, 55, 57, 60, 61, 63, 64, 67, 68, 70, 71, 74, 75, 77, 80, 81, 83, 84, 85, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 108, 109, 112, 113, 116, 117, 119, 123, 130, 137, 147, 158, 164, 171, 177, 185, 192, 193, 195, 199, 205, 214, 220, 227, 228, 230, 234, 245, 251, 258, 259, 261, 265, 278, 294, 298, 306, 313, 358, 382, 399, 420, 437, 456, 466, 483, 510, 515, 520, 527, 532, 533, 535, 539, 543, 597, 601, 605, 613, 617, 624, 625, 627, 631, 676, 680, 685, 686, 688, 692, 696, 700, 707], "summary": {"covered_lines": 116, "num_statements": 325, "percent_covered": 35.69230769230769, "percent_covered_display": "36", "missing_lines": 209, "excluded_lines": 0}, "missing_lines": [120, 121, 126, 127, 128, 133, 134, 135, 140, 141, 142, 145, 150, 151, 154, 155, 156, 161, 162, 167, 168, 169, 174, 175, 180, 181, 188, 189, 196, 197, 202, 203, 208, 209, 210, 217, 218, 223, 224, 231, 232, 237, 238, 239, 240, 241, 242, 243, 248, 249, 254, 255, 262, 263, 271, 272, 291, 292, 295, 296, 299, 300, 301, 302, 303, 304, 307, 308, 311, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 355, 356, 368, 369, 370, 379, 380, 389, 390, 396, 397, 408, 409, 417, 418, 427, 428, 434, 435, 445, 446, 453, 454, 459, 460, 463, 464, 473, 474, 480, 481, 496, 497, 508, 511, 512, 513, 516, 517, 518, 521, 522, 525, 528, 529, 536, 537, 540, 541, 544, 545, 581, 582, 583, 584, 585, 586, 587, 592, 593, 595, 598, 599, 602, 603, 606, 607, 608, 609, 610, 611, 614, 615, 618, 619, 620, 621, 628, 629, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 665, 666, 670, 671, 673, 674, 677, 678, 681, 682, 689, 690, 693, 694, 697, 698, 701, 702, 703, 708, 709, 710], "excluded_lines": [], "functions": {"VaultService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [120, 121], "excluded_lines": []}, "VaultService.export_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [126, 127, 128], "excluded_lines": []}, "VaultService.import_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [133, 134, 135], "excluded_lines": []}, "VaultService.export_profile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [140, 141, 142, 145], "excluded_lines": []}, "VaultService.import_profile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [150, 151, 154, 155, 156], "excluded_lines": []}, "VaultService.change_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [161, 162], "excluded_lines": []}, "VaultService.unlock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [167, 168, 169], "excluded_lines": []}, "VaultService.lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [174, 175], "excluded_lines": []}, "VaultService.backup_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [180, 181], "excluded_lines": []}, "VaultService.stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [188, 189], "excluded_lines": []}, "ProfileService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [196, 197], "excluded_lines": []}, "ProfileService.list_profiles": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [202, 203], "excluded_lines": []}, "ProfileService.add_profile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [208, 209, 210], "excluded_lines": []}, "ProfileService.remove_profile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [217, 218], "excluded_lines": []}, "ProfileService.switch_profile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [223, 224], "excluded_lines": []}, "SyncService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [231, 232], "excluded_lines": []}, "SyncService.sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [237, 238, 239, 240, 241, 242, 243], "excluded_lines": []}, "SyncService.start_background_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [248, 249], "excluded_lines": []}, "SyncService.start_background_vault_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [254, 255], "excluded_lines": []}, "EntryService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [262, 263], "excluded_lines": []}, "EntryService.list_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [271, 272], "excluded_lines": []}, "EntryService.search_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [291, 292], "excluded_lines": []}, "EntryService.retrieve_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [295, 296], "excluded_lines": []}, "EntryService.generate_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [299, 300, 301, 302, 303, 304], "excluded_lines": []}, "EntryService.get_totp_code": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [307, 308, 311], "excluded_lines": []}, "EntryService.add_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 355, 356], "excluded_lines": []}, "EntryService.add_totp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [368, 369, 370, 379, 380], "excluded_lines": []}, "EntryService.add_ssh_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [389, 390, 396, 397], "excluded_lines": []}, "EntryService.add_pgp_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [408, 409, 417, 418], "excluded_lines": []}, "EntryService.add_nostr_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [427, 428, 434, 435], "excluded_lines": []}, "EntryService.add_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [445, 446, 453, 454], "excluded_lines": []}, "EntryService.add_key_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [459, 460, 463, 464], "excluded_lines": []}, "EntryService.add_managed_account": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [473, 474, 480, 481], "excluded_lines": []}, "EntryService.modify_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [496, 497, 508], "excluded_lines": []}, "EntryService.archive_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [511, 512, 513], "excluded_lines": []}, "EntryService.restore_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [516, 517, 518], "excluded_lines": []}, "EntryService.export_totp_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [521, 522, 525], "excluded_lines": []}, "EntryService.display_totp_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [528, 529], "excluded_lines": []}, "ConfigService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [536, 537], "excluded_lines": []}, "ConfigService.get": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [540, 541], "excluded_lines": []}, "ConfigService.set": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [544, 545, 581, 582, 583, 584, 585, 586, 587, 592, 593, 595], "excluded_lines": []}, "ConfigService.get_secret_mode_enabled": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [598, 599], "excluded_lines": []}, "ConfigService.get_clipboard_clear_delay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [602, 603], "excluded_lines": []}, "ConfigService.set_secret_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [606, 607, 608, 609, 610, 611], "excluded_lines": []}, "ConfigService.get_offline_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [614, 615], "excluded_lines": []}, "ConfigService.set_offline_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [618, 619, 620, 621], "excluded_lines": []}, "UtilityService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [628, 629], "excluded_lines": []}, "UtilityService.generate_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 0}, "missing_lines": [644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 665, 666, 670, 671, 673, 674], "excluded_lines": []}, "UtilityService.verify_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [677, 678], "excluded_lines": []}, "UtilityService.update_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [681, 682], "excluded_lines": []}, "NostrService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [689, 690], "excluded_lines": []}, "NostrService.get_pubkey": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [693, 694], "excluded_lines": []}, "NostrService.list_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [697, 698], "excluded_lines": []}, "NostrService.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [701, 702, 703], "excluded_lines": []}, "NostrService.remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [708, 709, 710], "excluded_lines": []}, "": {"executed_lines": [1, 3, 10, 11, 12, 13, 14, 16, 18, 19, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 41, 42, 44, 45, 48, 49, 51, 54, 55, 57, 60, 61, 63, 64, 67, 68, 70, 71, 74, 75, 77, 80, 81, 83, 84, 85, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 108, 109, 112, 113, 116, 117, 119, 123, 130, 137, 147, 158, 164, 171, 177, 185, 192, 193, 195, 199, 205, 214, 220, 227, 228, 230, 234, 245, 251, 258, 259, 261, 265, 278, 294, 298, 306, 313, 358, 382, 399, 420, 437, 456, 466, 483, 510, 515, 520, 527, 532, 533, 535, 539, 543, 597, 601, 605, 613, 617, 624, 625, 627, 631, 676, 680, 685, 686, 688, 692, 696, 700, 707], "summary": {"covered_lines": 116, "num_statements": 116, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"VaultExportRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultExportResponse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultImportRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ChangePasswordRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "UnlockRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "UnlockResponse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BackupParentSeedRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileSwitchRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileRemoveRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SyncResponse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordPolicyOptions": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AddPasswordEntryRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "GeneratePasswordRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "GeneratePasswordResponse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 28, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 28, "excluded_lines": 0}, "missing_lines": [120, 121, 126, 127, 128, 133, 134, 135, 140, 141, 142, 145, 150, 151, 154, 155, 156, 161, 162, 167, 168, 169, 174, 175, 180, 181, 188, 189], "excluded_lines": []}, "ProfileService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [196, 197, 202, 203, 208, 209, 210, 217, 218, 223, 224], "excluded_lines": []}, "SyncService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [231, 232, 237, 238, 239, 240, 241, 242, 243, 248, 249, 254, 255], "excluded_lines": []}, "EntryService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 81, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 81, "excluded_lines": 0}, "missing_lines": [262, 263, 271, 272, 291, 292, 295, 296, 299, 300, 301, 302, 303, 304, 307, 308, 311, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 355, 356, 368, 369, 370, 379, 380, 389, 390, 396, 397, 408, 409, 417, 418, 427, 428, 434, 435, 445, 446, 453, 454, 459, 460, 463, 464, 473, 474, 480, 481, 496, 497, 508, 511, 512, 513, 516, 517, 518, 521, 522, 525, 528, 529], "excluded_lines": []}, "ConfigService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 32, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 32, "excluded_lines": 0}, "missing_lines": [536, 537, 540, 541, 544, 545, 581, 582, 583, 584, 585, 586, 587, 592, 593, 595, 598, 599, 602, 603, 606, 607, 608, 609, 610, 611, 614, 615, 618, 619, 620, 621], "excluded_lines": []}, "UtilityService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 32, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 32, "excluded_lines": 0}, "missing_lines": [628, 629, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 665, 666, 670, 671, 673, 674, 677, 678, 681, 682], "excluded_lines": []}, "NostrService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [689, 690, 693, 694, 697, 698, 701, 702, 703, 708, 709, 710], "excluded_lines": []}, "": {"executed_lines": [1, 3, 10, 11, 12, 13, 14, 16, 18, 19, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 41, 42, 44, 45, 48, 49, 51, 54, 55, 57, 60, 61, 63, 64, 67, 68, 70, 71, 74, 75, 77, 80, 81, 83, 84, 85, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 108, 109, 112, 113, 116, 117, 119, 123, 130, 137, 147, 158, 164, 171, 177, 185, 192, 193, 195, 199, 205, 214, 220, 227, 228, 230, 234, 245, 251, 258, 259, 261, 265, 278, 294, 298, 306, 313, 358, 382, 399, 420, 437, 456, 466, 483, 510, 515, 520, 527, 532, 533, 535, 539, 543, 597, 601, 605, 613, 617, 624, 625, 627, 631, 676, 680, 685, 686, 688, 692, 696, 700, 707], "summary": {"covered_lines": 116, "num_statements": 116, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/backup.py": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 23, 24, 27, 30, 31, 39, 41, 61, 95, 114, 148, 170, 193], "summary": {"covered_lines": 19, "num_statements": 116, "percent_covered": 16.379310344827587, "percent_covered_display": "16", "missing_lines": 97, "excluded_lines": 2}, "missing_lines": [51, 52, 53, 54, 55, 56, 57, 62, 63, 64, 65, 66, 72, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 89, 90, 91, 92, 93, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 115, 116, 122, 123, 124, 125, 127, 128, 129, 130, 131, 132, 137, 138, 141, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 164, 171, 172, 178, 179, 180, 181, 183, 184, 185, 188, 189, 190, 191, 194, 195, 197, 198, 199, 200, 202, 203, 206, 207, 208, 209, 210, 215, 216, 219], "excluded_lines": [108, 109], "functions": {"BackupManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [51, 52, 53, 54, 55, 56, 57], "excluded_lines": []}, "BackupManager.create_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [62, 63, 64, 65, 66, 72, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 89, 90, 91, 92, 93], "excluded_lines": []}, "BackupManager._create_additional_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 2}, "missing_lines": [97, 98, 99, 101, 102, 103, 104, 105, 106, 107], "excluded_lines": [108, 109]}, "BackupManager.restore_latest_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [115, 116, 122, 123, 124, 125, 127, 128, 129, 130, 131, 132, 137, 138, 141], "excluded_lines": []}, "BackupManager.restore_from_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 164], "excluded_lines": []}, "BackupManager.list_backups": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [171, 172, 178, 179, 180, 181, 183, 184, 185, 188, 189, 190, 191], "excluded_lines": []}, "BackupManager.restore_backup_by_timestamp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [194, 195, 197, 198, 199, 200, 202, 203, 206, 207, 208, 209, 210, 215, 216, 219], "excluded_lines": []}, "": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 23, 24, 27, 30, 31, 39, 41, 61, 95, 114, 148, 170, 193], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"BackupManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 97, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 97, "excluded_lines": 2}, "missing_lines": [51, 52, 53, 54, 55, 56, 57, 62, 63, 64, 65, 66, 72, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 89, 90, 91, 92, 93, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 115, 116, 122, 123, 124, 125, 127, 128, 129, 130, 131, 132, 137, 138, 141, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 164, 171, 172, 178, 179, 180, 181, 183, 184, 185, 188, 189, 190, 191, 194, 195, 197, 198, 199, 200, 202, 203, 206, 207, 208, 209, 210, 215, 216, 219], "excluded_lines": [108, 109]}, "": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 23, 24, 27, 30, 31, 39, 41, 61, 95, 114, 148, 170, 193], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/config_manager.py": {"executed_lines": [1, 3, 5, 6, 7, 9, 11, 13, 14, 16, 18, 21, 24, 25, 27, 29, 34, 120, 129, 137, 144, 152, 159, 165, 173, 178, 186, 191, 199, 204, 212, 217, 223, 229, 235, 241, 246, 251, 259, 264, 272, 278, 294, 299, 304, 309, 314, 320, 326, 332, 338, 344, 349, 357, 362, 370, 375, 380], "summary": {"covered_lines": 55, "num_statements": 241, "percent_covered": 22.821576763485478, "percent_covered_display": "23", "missing_lines": 186, "excluded_lines": 2}, "missing_lines": [30, 31, 32, 43, 44, 45, 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 114, 115, 116, 117, 118, 122, 123, 124, 125, 126, 127, 131, 132, 133, 134, 135, 139, 140, 141, 142, 146, 147, 148, 149, 150, 154, 155, 156, 157, 161, 162, 163, 167, 168, 169, 170, 171, 175, 176, 180, 181, 182, 183, 184, 188, 189, 193, 194, 195, 196, 197, 201, 202, 206, 207, 208, 209, 210, 214, 215, 219, 220, 221, 225, 226, 227, 231, 232, 233, 237, 238, 239, 243, 244, 248, 249, 253, 254, 255, 256, 257, 261, 262, 266, 267, 268, 269, 270, 274, 275, 280, 282, 283, 295, 296, 297, 300, 301, 302, 305, 306, 307, 310, 311, 312, 316, 317, 318, 322, 323, 324, 328, 329, 330, 334, 335, 336, 340, 341, 342, 346, 347, 351, 352, 353, 354, 355, 359, 360, 364, 365, 366, 367, 368, 372, 373, 376, 377, 378, 381, 382], "excluded_lines": [18, 19], "functions": {"ConfigManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [30, 31, 32], "excluded_lines": []}, "ConfigManager.load_config": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 47, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 47, "excluded_lines": 0}, "missing_lines": [43, 44, 45, 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 114, 115, 116, 117, 118], "excluded_lines": []}, "ConfigManager.save_config": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [122, 123, 124, 125, 126, 127], "excluded_lines": []}, "ConfigManager.set_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [131, 132, 133, 134, 135], "excluded_lines": []}, "ConfigManager.set_pin": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [139, 140, 141, 142], "excluded_lines": []}, "ConfigManager.verify_pin": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [146, 147, 148, 149, 150], "excluded_lines": []}, "ConfigManager.change_pin": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [154, 155, 156, 157], "excluded_lines": []}, "ConfigManager.set_password_hash": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [161, 162, 163], "excluded_lines": []}, "ConfigManager.set_inactivity_timeout": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [167, 168, 169, 170, 171], "excluded_lines": []}, "ConfigManager.get_inactivity_timeout": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [175, 176], "excluded_lines": []}, "ConfigManager.set_kdf_iterations": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [180, 181, 182, 183, 184], "excluded_lines": []}, "ConfigManager.get_kdf_iterations": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [188, 189], "excluded_lines": []}, "ConfigManager.set_kdf_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [193, 194, 195, 196, 197], "excluded_lines": []}, "ConfigManager.get_kdf_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [201, 202], "excluded_lines": []}, "ConfigManager.set_argon2_time_cost": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [206, 207, 208, 209, 210], "excluded_lines": []}, "ConfigManager.get_argon2_time_cost": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [214, 215], "excluded_lines": []}, "ConfigManager.set_additional_backup_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [219, 220, 221], "excluded_lines": []}, "ConfigManager.get_additional_backup_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [225, 226, 227], "excluded_lines": []}, "ConfigManager.set_secret_mode_enabled": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [231, 232, 233], "excluded_lines": []}, "ConfigManager.set_offline_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [237, 238, 239], "excluded_lines": []}, "ConfigManager.get_secret_mode_enabled": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [243, 244], "excluded_lines": []}, "ConfigManager.get_offline_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [248, 249], "excluded_lines": []}, "ConfigManager.set_clipboard_clear_delay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [253, 254, 255, 256, 257], "excluded_lines": []}, "ConfigManager.get_clipboard_clear_delay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [261, 262], "excluded_lines": []}, "ConfigManager.set_backup_interval": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [266, 267, 268, 269, 270], "excluded_lines": []}, "ConfigManager.get_backup_interval": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [274, 275], "excluded_lines": []}, "ConfigManager.get_password_policy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [280, 282, 283], "excluded_lines": []}, "ConfigManager.set_min_uppercase": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [295, 296, 297], "excluded_lines": []}, "ConfigManager.set_min_lowercase": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [300, 301, 302], "excluded_lines": []}, "ConfigManager.set_min_digits": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [305, 306, 307], "excluded_lines": []}, "ConfigManager.set_min_special": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [310, 311, 312], "excluded_lines": []}, "ConfigManager.set_include_special_chars": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [316, 317, 318], "excluded_lines": []}, "ConfigManager.set_allowed_special_chars": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [322, 323, 324], "excluded_lines": []}, "ConfigManager.set_special_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [328, 329, 330], "excluded_lines": []}, "ConfigManager.set_exclude_ambiguous": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [334, 335, 336], "excluded_lines": []}, "ConfigManager.set_quick_unlock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [340, 341, 342], "excluded_lines": []}, "ConfigManager.get_quick_unlock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [346, 347], "excluded_lines": []}, "ConfigManager.set_nostr_max_retries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [351, 352, 353, 354, 355], "excluded_lines": []}, "ConfigManager.get_nostr_max_retries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [359, 360], "excluded_lines": []}, "ConfigManager.set_nostr_retry_delay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [364, 365, 366, 367, 368], "excluded_lines": []}, "ConfigManager.get_nostr_retry_delay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [372, 373], "excluded_lines": []}, "ConfigManager.set_verbose_timing": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [376, 377, 378], "excluded_lines": []}, "ConfigManager.get_verbose_timing": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [381, 382], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 9, 11, 13, 14, 16, 18, 21, 24, 25, 27, 29, 34, 120, 129, 137, 144, 152, 159, 165, 173, 178, 186, 191, 199, 204, 212, 217, 223, 229, 235, 241, 246, 251, 259, 264, 272, 278, 294, 299, 304, 309, 314, 320, 326, 332, 338, 344, 349, 357, 362, 370, 375, 380], "summary": {"covered_lines": 55, "num_statements": 55, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [18, 19]}}, "classes": {"ConfigManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 186, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 186, "excluded_lines": 0}, "missing_lines": [30, 31, 32, 43, 44, 45, 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 114, 115, 116, 117, 118, 122, 123, 124, 125, 126, 127, 131, 132, 133, 134, 135, 139, 140, 141, 142, 146, 147, 148, 149, 150, 154, 155, 156, 157, 161, 162, 163, 167, 168, 169, 170, 171, 175, 176, 180, 181, 182, 183, 184, 188, 189, 193, 194, 195, 196, 197, 201, 202, 206, 207, 208, 209, 210, 214, 215, 219, 220, 221, 225, 226, 227, 231, 232, 233, 237, 238, 239, 243, 244, 248, 249, 253, 254, 255, 256, 257, 261, 262, 266, 267, 268, 269, 270, 274, 275, 280, 282, 283, 295, 296, 297, 300, 301, 302, 305, 306, 307, 310, 311, 312, 316, 317, 318, 322, 323, 324, 328, 329, 330, 334, 335, 336, 340, 341, 342, 346, 347, 351, 352, 353, 354, 355, 359, 360, 364, 365, 366, 367, 368, 372, 373, 376, 377, 378, 381, 382], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 9, 11, 13, 14, 16, 18, 21, 24, 25, 27, 29, 34, 120, 129, 137, 144, 152, 159, 165, 173, 178, 186, 191, 199, 204, 212, 217, 223, 229, 235, 241, 246, 251, 259, 264, 272, 278, 294, 299, 304, 309, 314, 320, 326, 332, 338, 344, 349, 357, 362, 370, 375, 380], "summary": {"covered_lines": 55, "num_statements": 55, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [18, 19]}}}, "src/seedpass/core/encryption.py": {"executed_lines": [3, 4, 6, 7, 9, 10, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 35, 38, 45, 46, 48, 56, 57, 62, 99, 117, 206, 247, 271, 279, 297, 303, 330, 347, 355, 363, 379, 441, 450, 560, 603, 619], "summary": {"covered_lines": 46, "num_statements": 343, "percent_covered": 13.411078717201166, "percent_covered_display": "13", "missing_lines": 297, "excluded_lines": 23}, "missing_lines": [40, 41, 42, 49, 52, 53, 71, 72, 74, 75, 76, 79, 80, 82, 83, 85, 86, 87, 91, 94, 95, 97, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 131, 133, 135, 136, 137, 138, 139, 140, 141, 144, 145, 146, 147, 152, 153, 154, 155, 156, 157, 158, 161, 162, 163, 166, 167, 168, 171, 172, 173, 176, 181, 182, 183, 184, 185, 188, 192, 193, 198, 199, 200, 211, 212, 213, 214, 215, 218, 219, 220, 221, 222, 223, 225, 228, 234, 237, 240, 241, 266, 267, 268, 269, 275, 276, 277, 281, 282, 283, 285, 286, 289, 291, 292, 293, 295, 298, 299, 300, 301, 311, 312, 313, 315, 316, 317, 318, 319, 320, 325, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 348, 349, 350, 351, 352, 353, 356, 357, 358, 359, 360, 361, 370, 371, 372, 373, 375, 376, 377, 386, 387, 388, 389, 390, 391, 392, 395, 397, 398, 399, 401, 402, 405, 407, 408, 411, 412, 414, 417, 418, 419, 420, 421, 423, 424, 425, 426, 427, 428, 429, 436, 437, 438, 439, 442, 443, 444, 445, 446, 447, 448, 470, 471, 473, 474, 475, 477, 478, 479, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 496, 497, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 512, 515, 516, 517, 518, 521, 527, 528, 529, 530, 531, 535, 541, 542, 543, 562, 563, 564, 565, 566, 568, 569, 570, 571, 572, 575, 576, 579, 580, 581, 582, 583, 584, 589, 590, 591, 592, 593, 594, 595, 596, 597, 601, 609, 610, 611, 612, 613, 614, 615, 616, 617, 620, 621, 622, 623, 625, 626, 627, 628, 630, 631, 632, 633, 634, 635, 636], "excluded_lines": [11, 12, 13, 15, 201, 202, 229, 230, 238, 239, 321, 322, 430, 431, 432, 433, 544, 545, 546, 550, 556, 557, 558], "functions": {"_derive_legacy_key_from_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [40, 41, 42], "excluded_lines": []}, "LegacyFormatRequiresMigrationError.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [49, 52, 53], "excluded_lines": []}, "EncryptionManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [71, 72, 74, 75, 76, 79, 80, 82, 83, 85, 86, 87, 91, 94, 95, 97], "excluded_lines": []}, "EncryptionManager.encrypt_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115], "excluded_lines": []}, "EncryptionManager.decrypt_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 2}, "missing_lines": [131, 133, 135, 136, 137, 138, 139, 140, 141, 144, 145, 146, 147, 152, 153, 154, 155, 156, 157, 158, 161, 162, 163, 166, 167, 168, 171, 172, 173, 176, 181, 182, 183, 184, 185, 188, 192, 193, 198, 199, 200], "excluded_lines": [201, 202]}, "EncryptionManager.decrypt_legacy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 4}, "missing_lines": [211, 212, 213, 214, 215, 218, 219, 220, 221, 222, 223, 225, 228, 234, 237, 240, 241], "excluded_lines": [229, 230, 238, 239]}, "EncryptionManager.resolve_relative_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [266, 267, 268, 269], "excluded_lines": []}, "EncryptionManager.encrypt_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [275, 276, 277], "excluded_lines": []}, "EncryptionManager.decrypt_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [281, 282, 283, 285, 286, 289, 291, 292, 293, 295], "excluded_lines": []}, "EncryptionManager._serialize": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [298, 299, 300, 301], "excluded_lines": []}, "EncryptionManager._deserialize": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 2}, "missing_lines": [311, 312, 313, 315, 316, 317, 318, 319, 320, 325], "excluded_lines": [321, 322]}, "EncryptionManager.encrypt_and_save_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345], "excluded_lines": []}, "EncryptionManager.decrypt_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [348, 349, 350, 351, 352, 353], "excluded_lines": []}, "EncryptionManager.get_file_kdf": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [356, 357, 358, 359, 360, 361], "excluded_lines": []}, "EncryptionManager.save_json_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [370, 371, 372, 373, 375, 376, 377], "excluded_lines": []}, "EncryptionManager.load_json_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 35, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 35, "excluded_lines": 4}, "missing_lines": [386, 387, 388, 389, 390, 391, 392, 395, 397, 398, 399, 401, 402, 405, 407, 408, 411, 412, 414, 417, 418, 419, 420, 421, 423, 424, 425, 426, 427, 428, 429, 436, 437, 438, 439], "excluded_lines": [430, 431, 432, 433]}, "EncryptionManager.get_encrypted_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [442, 443, 444, 445, 446, 447, 448], "excluded_lines": []}, "EncryptionManager.decrypt_and_save_index_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 32, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 32, "excluded_lines": 7}, "missing_lines": [470, 471, 473, 474, 475, 477, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 512, 515, 516, 517, 518, 521, 527, 528, 529, 530, 531, 535, 541, 542, 543], "excluded_lines": [544, 545, 546, 550, 556, 557, 558]}, "EncryptionManager.decrypt_and_save_index_from_nostr._process": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [478, 479, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 496, 497], "excluded_lines": []}, "EncryptionManager.update_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 28, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 28, "excluded_lines": 0}, "missing_lines": [562, 563, 564, 565, 566, 568, 569, 570, 571, 572, 575, 576, 579, 580, 581, 582, 583, 584, 589, 590, 591, 592, 593, 594, 595, 596, 597, 601], "excluded_lines": []}, "EncryptionManager.validate_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [609, 610, 611, 612, 613, 614, 615, 616, 617], "excluded_lines": []}, "EncryptionManager.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [620, 621, 622, 623, 625, 626, 627, 628, 630, 631, 632, 633, 634, 635, 636], "excluded_lines": []}, "": {"executed_lines": [3, 4, 6, 7, 9, 10, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 35, 38, 45, 46, 48, 56, 57, 62, 99, 117, 206, 247, 271, 279, 297, 303, 330, 347, 355, 363, 379, 441, 450, 560, 603, 619], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 4}, "missing_lines": [], "excluded_lines": [11, 12, 13, 15]}}, "classes": {"LegacyFormatRequiresMigrationError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [49, 52, 53], "excluded_lines": []}, "EncryptionManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 291, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 291, "excluded_lines": 19}, "missing_lines": [71, 72, 74, 75, 76, 79, 80, 82, 83, 85, 86, 87, 91, 94, 95, 97, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 131, 133, 135, 136, 137, 138, 139, 140, 141, 144, 145, 146, 147, 152, 153, 154, 155, 156, 157, 158, 161, 162, 163, 166, 167, 168, 171, 172, 173, 176, 181, 182, 183, 184, 185, 188, 192, 193, 198, 199, 200, 211, 212, 213, 214, 215, 218, 219, 220, 221, 222, 223, 225, 228, 234, 237, 240, 241, 266, 267, 268, 269, 275, 276, 277, 281, 282, 283, 285, 286, 289, 291, 292, 293, 295, 298, 299, 300, 301, 311, 312, 313, 315, 316, 317, 318, 319, 320, 325, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 348, 349, 350, 351, 352, 353, 356, 357, 358, 359, 360, 361, 370, 371, 372, 373, 375, 376, 377, 386, 387, 388, 389, 390, 391, 392, 395, 397, 398, 399, 401, 402, 405, 407, 408, 411, 412, 414, 417, 418, 419, 420, 421, 423, 424, 425, 426, 427, 428, 429, 436, 437, 438, 439, 442, 443, 444, 445, 446, 447, 448, 470, 471, 473, 474, 475, 477, 478, 479, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 496, 497, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 512, 515, 516, 517, 518, 521, 527, 528, 529, 530, 531, 535, 541, 542, 543, 562, 563, 564, 565, 566, 568, 569, 570, 571, 572, 575, 576, 579, 580, 581, 582, 583, 584, 589, 590, 591, 592, 593, 594, 595, 596, 597, 601, 609, 610, 611, 612, 613, 614, 615, 616, 617, 620, 621, 622, 623, 625, 626, 627, 628, 630, 631, 632, 633, 634, 635, 636], "excluded_lines": [201, 202, 229, 230, 238, 239, 321, 322, 430, 431, 432, 433, 544, 545, 546, 550, 556, 557, 558]}, "": {"executed_lines": [3, 4, 6, 7, 9, 10, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 35, 38, 45, 46, 48, 56, 57, 62, 99, 117, 206, 247, 271, 279, 297, 303, 330, 347, 355, 363, 379, 441, 450, 560, 603, 619], "summary": {"covered_lines": 46, "num_statements": 49, "percent_covered": 93.87755102040816, "percent_covered_display": "94", "missing_lines": 3, "excluded_lines": 4}, "missing_lines": [40, 41, 42], "excluded_lines": [11, 12, 13, 15]}}}, "src/seedpass/core/entry_management.py": {"executed_lines": [3, 18, 19, 21, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 48, 49, 50, 53, 56, 57, 76, 80, 123, 132, 152, 242, 256, 327, 369, 383, 429, 450, 494, 529, 554, 597, 619, 674, 697, 717, 738, 751, 784, 799, 837, 1101, 1105, 1109, 1252, 1307, 1344, 1365, 1407, 1440], "summary": {"covered_lines": 57, "num_statements": 667, "percent_covered": 8.545727136431784, "percent_covered_display": "9", "missing_lines": 610, "excluded_lines": 3}, "missing_lines": [64, 65, 66, 69, 70, 72, 74, 78, 81, 82, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 95, 96, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 119, 120, 121, 124, 125, 126, 127, 128, 129, 130, 138, 139, 140, 141, 142, 144, 145, 146, 147, 148, 149, 150, 183, 184, 185, 187, 188, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 222, 224, 228, 229, 230, 232, 233, 235, 237, 238, 239, 240, 244, 245, 246, 254, 271, 272, 273, 275, 276, 277, 278, 279, 280, 281, 282, 283, 297, 298, 299, 300, 301, 315, 317, 318, 319, 321, 322, 323, 324, 325, 343, 344, 346, 348, 349, 350, 352, 353, 354, 364, 365, 366, 367, 372, 373, 374, 375, 376, 378, 380, 381, 396, 397, 399, 400, 401, 403, 404, 406, 407, 408, 410, 411, 412, 424, 425, 426, 427, 432, 433, 434, 435, 436, 438, 439, 440, 442, 443, 445, 446, 447, 448, 461, 462, 464, 465, 466, 468, 469, 470, 471, 472, 473, 474, 475, 477, 478, 479, 489, 490, 491, 492, 507, 509, 510, 511, 524, 525, 526, 527, 532, 533, 534, 535, 538, 540, 541, 542, 544, 545, 547, 548, 549, 550, 551, 552, 566, 567, 569, 570, 571, 573, 574, 575, 576, 577, 579, 580, 581, 592, 593, 594, 595, 600, 601, 602, 603, 606, 608, 609, 610, 612, 613, 615, 616, 617, 634, 635, 637, 638, 639, 641, 642, 644, 646, 647, 648, 649, 651, 652, 654, 655, 656, 669, 670, 671, 672, 677, 678, 679, 680, 684, 686, 687, 688, 690, 691, 693, 694, 695, 703, 704, 705, 706, 709, 710, 711, 712, 713, 714, 715, 724, 725, 726, 727, 730, 731, 732, 733, 734, 735, 736, 740, 741, 742, 743, 746, 748, 749, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 771, 772, 773, 782, 790, 791, 792, 793, 794, 797, 806, 807, 808, 810, 811, 812, 817, 818, 821, 822, 824, 825, 826, 828, 829, 832, 835, 876, 877, 878, 880, 881, 884, 890, 892, 894, 916, 990, 991, 994, 995, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1019, 1020, 1021, 1022, 1026, 1027, 1028, 1029, 1030, 1031, 1033, 1034, 1036, 1037, 1038, 1039, 1040, 1044, 1045, 1046, 1048, 1049, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1078, 1080, 1081, 1085, 1086, 1087, 1089, 1090, 1094, 1095, 1096, 1099, 1103, 1107, 1130, 1131, 1132, 1134, 1135, 1136, 1137, 1138, 1140, 1141, 1142, 1143, 1144, 1147, 1148, 1150, 1151, 1153, 1155, 1156, 1158, 1159, 1160, 1164, 1165, 1168, 1169, 1171, 1172, 1173, 1174, 1175, 1176, 1186, 1196, 1197, 1198, 1199, 1202, 1203, 1204, 1205, 1206, 1209, 1215, 1216, 1222, 1227, 1228, 1235, 1236, 1242, 1244, 1246, 1247, 1248, 1249, 1250, 1261, 1262, 1264, 1265, 1267, 1268, 1272, 1273, 1277, 1278, 1280, 1281, 1284, 1285, 1286, 1288, 1289, 1290, 1291, 1293, 1294, 1305, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1328, 1331, 1338, 1339, 1340, 1348, 1349, 1350, 1351, 1354, 1356, 1358, 1359, 1361, 1362, 1363, 1371, 1372, 1373, 1374, 1375, 1380, 1382, 1385, 1387, 1388, 1394, 1395, 1397, 1398, 1401, 1415, 1416, 1421, 1422, 1423, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1435, 1436, 1437, 1438, 1447, 1448, 1449, 1451, 1452, 1454, 1455, 1456, 1457, 1458, 1459, 1462, 1463, 1464, 1466, 1467, 1469, 1470, 1471, 1472, 1473, 1474], "excluded_lines": [22, 23, 25], "functions": {"EntryManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [64, 65, 66, 69, 70, 72, 74], "excluded_lines": []}, "EntryManager.clear_cache": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [78], "excluded_lines": []}, "EntryManager._load_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 0}, "missing_lines": [81, 82, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 95, 96, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 119, 120, 121], "excluded_lines": []}, "EntryManager._save_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [124, 125, 126, 127, 128, 129, 130], "excluded_lines": []}, "EntryManager.get_next_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [138, 139, 140, 141, 142, 144, 145, 146, 147, 148, 149, 150], "excluded_lines": []}, "EntryManager.add_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 36, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 36, "excluded_lines": 0}, "missing_lines": [183, 184, 185, 187, 188, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 222, 224, 228, 229, 230, 232, 233, 235, 237, 238, 239, 240], "excluded_lines": []}, "EntryManager.get_next_totp_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [244, 245, 246, 254], "excluded_lines": []}, "EntryManager.add_totp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 0}, "missing_lines": [271, 272, 273, 275, 276, 277, 278, 279, 280, 281, 282, 283, 297, 298, 299, 300, 301, 315, 317, 318, 319, 321, 322, 323, 324, 325], "excluded_lines": []}, "EntryManager.add_ssh_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [343, 344, 346, 348, 349, 350, 352, 353, 354, 364, 365, 366, 367], "excluded_lines": []}, "EntryManager.get_ssh_key_pair": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [372, 373, 374, 375, 376, 378, 380, 381], "excluded_lines": []}, "EntryManager.add_pgp_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [396, 397, 399, 400, 401, 403, 404, 406, 407, 408, 410, 411, 412, 424, 425, 426, 427], "excluded_lines": []}, "EntryManager.get_pgp_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [432, 433, 434, 435, 436, 438, 439, 440, 442, 443, 445, 446, 447, 448], "excluded_lines": []}, "EntryManager.add_nostr_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [461, 462, 464, 465, 466, 468, 469, 470, 471, 472, 473, 474, 475, 477, 478, 479, 489, 490, 491, 492], "excluded_lines": []}, "EntryManager.add_key_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [507, 509, 510, 511, 524, 525, 526, 527], "excluded_lines": []}, "EntryManager.get_nostr_key_pair": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [532, 533, 534, 535, 538, 540, 541, 542, 544, 545, 547, 548, 549, 550, 551, 552], "excluded_lines": []}, "EntryManager.add_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [566, 567, 569, 570, 571, 573, 574, 575, 576, 577, 579, 580, 581, 592, 593, 594, 595], "excluded_lines": []}, "EntryManager.get_seed_phrase": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [600, 601, 602, 603, 606, 608, 609, 610, 612, 613, 615, 616, 617], "excluded_lines": []}, "EntryManager.add_managed_account": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [634, 635, 637, 638, 639, 641, 642, 644, 646, 647, 648, 649, 651, 652, 654, 655, 656, 669, 670, 671, 672], "excluded_lines": []}, "EntryManager.get_managed_account_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [677, 678, 679, 680, 684, 686, 687, 688, 690, 691, 693, 694, 695], "excluded_lines": []}, "EntryManager.get_totp_secret": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [703, 704, 705, 706, 709, 710, 711, 712, 713, 714, 715], "excluded_lines": []}, "EntryManager.get_totp_code": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [724, 725, 726, 727, 730, 731, 732, 733, 734, 735, 736], "excluded_lines": []}, "EntryManager.get_totp_time_remaining": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [740, 741, 742, 743, 746, 748, 749], "excluded_lines": []}, "EntryManager.export_totp_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 771, 772, 773, 782], "excluded_lines": []}, "EntryManager.get_encrypted_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [790, 791, 792, 793, 794, 797], "excluded_lines": []}, "EntryManager.retrieve_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [806, 807, 808, 810, 811, 812, 817, 818, 821, 822, 824, 825, 826, 828, 829, 832, 835], "excluded_lines": []}, "EntryManager.modify_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 90, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 90, "excluded_lines": 0}, "missing_lines": [876, 877, 878, 880, 881, 884, 890, 892, 894, 916, 990, 991, 994, 995, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1019, 1020, 1021, 1022, 1026, 1027, 1028, 1029, 1030, 1031, 1033, 1034, 1036, 1037, 1038, 1039, 1040, 1044, 1045, 1046, 1048, 1049, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1078, 1080, 1081, 1085, 1086, 1087, 1089, 1090, 1094, 1095, 1096, 1099], "excluded_lines": []}, "EntryManager.archive_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1103], "excluded_lines": []}, "EntryManager.restore_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1107], "excluded_lines": []}, "EntryManager.list_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 50, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 50, "excluded_lines": 0}, "missing_lines": [1130, 1131, 1132, 1134, 1135, 1136, 1137, 1138, 1140, 1153, 1155, 1156, 1158, 1159, 1160, 1164, 1165, 1168, 1169, 1171, 1172, 1173, 1174, 1175, 1176, 1186, 1196, 1197, 1198, 1199, 1202, 1203, 1204, 1205, 1206, 1209, 1215, 1216, 1222, 1227, 1228, 1235, 1236, 1242, 1244, 1246, 1247, 1248, 1249, 1250], "excluded_lines": []}, "EntryManager.list_entries.sort_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [1141, 1142, 1143, 1144, 1147, 1148, 1150, 1151], "excluded_lines": []}, "EntryManager.search_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [1261, 1262, 1264, 1265, 1267, 1268, 1272, 1273, 1277, 1278, 1280, 1281, 1284, 1285, 1286, 1288, 1289, 1290, 1291, 1293, 1294, 1305], "excluded_lines": []}, "EntryManager.delete_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1328, 1331, 1338, 1339, 1340], "excluded_lines": []}, "EntryManager.update_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [1348, 1349, 1350, 1351, 1354, 1356, 1358, 1359, 1361, 1362, 1363], "excluded_lines": []}, "EntryManager.restore_from_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [1371, 1372, 1373, 1374, 1375, 1380, 1382, 1385, 1387, 1388, 1394, 1395, 1397, 1398, 1401], "excluded_lines": []}, "EntryManager.list_all_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [1415, 1416, 1421, 1422, 1423, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1435, 1436, 1437, 1438], "excluded_lines": []}, "EntryManager.get_entry_summaries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [1447, 1448, 1449, 1451, 1452, 1454, 1455, 1456, 1457, 1458, 1459, 1462, 1463, 1464, 1466, 1467, 1469, 1470, 1471, 1472, 1473, 1474], "excluded_lines": []}, "": {"executed_lines": [3, 18, 19, 21, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 48, 49, 50, 53, 56, 57, 76, 80, 123, 132, 152, 242, 256, 327, 369, 383, 429, 450, 494, 529, 554, 597, 619, 674, 697, 717, 738, 751, 784, 799, 837, 1101, 1105, 1109, 1252, 1307, 1344, 1365, 1407, 1440], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [22, 23, 25]}}, "classes": {"EntryManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 610, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 610, "excluded_lines": 0}, "missing_lines": [64, 65, 66, 69, 70, 72, 74, 78, 81, 82, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 95, 96, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 119, 120, 121, 124, 125, 126, 127, 128, 129, 130, 138, 139, 140, 141, 142, 144, 145, 146, 147, 148, 149, 150, 183, 184, 185, 187, 188, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 222, 224, 228, 229, 230, 232, 233, 235, 237, 238, 239, 240, 244, 245, 246, 254, 271, 272, 273, 275, 276, 277, 278, 279, 280, 281, 282, 283, 297, 298, 299, 300, 301, 315, 317, 318, 319, 321, 322, 323, 324, 325, 343, 344, 346, 348, 349, 350, 352, 353, 354, 364, 365, 366, 367, 372, 373, 374, 375, 376, 378, 380, 381, 396, 397, 399, 400, 401, 403, 404, 406, 407, 408, 410, 411, 412, 424, 425, 426, 427, 432, 433, 434, 435, 436, 438, 439, 440, 442, 443, 445, 446, 447, 448, 461, 462, 464, 465, 466, 468, 469, 470, 471, 472, 473, 474, 475, 477, 478, 479, 489, 490, 491, 492, 507, 509, 510, 511, 524, 525, 526, 527, 532, 533, 534, 535, 538, 540, 541, 542, 544, 545, 547, 548, 549, 550, 551, 552, 566, 567, 569, 570, 571, 573, 574, 575, 576, 577, 579, 580, 581, 592, 593, 594, 595, 600, 601, 602, 603, 606, 608, 609, 610, 612, 613, 615, 616, 617, 634, 635, 637, 638, 639, 641, 642, 644, 646, 647, 648, 649, 651, 652, 654, 655, 656, 669, 670, 671, 672, 677, 678, 679, 680, 684, 686, 687, 688, 690, 691, 693, 694, 695, 703, 704, 705, 706, 709, 710, 711, 712, 713, 714, 715, 724, 725, 726, 727, 730, 731, 732, 733, 734, 735, 736, 740, 741, 742, 743, 746, 748, 749, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 771, 772, 773, 782, 790, 791, 792, 793, 794, 797, 806, 807, 808, 810, 811, 812, 817, 818, 821, 822, 824, 825, 826, 828, 829, 832, 835, 876, 877, 878, 880, 881, 884, 890, 892, 894, 916, 990, 991, 994, 995, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1019, 1020, 1021, 1022, 1026, 1027, 1028, 1029, 1030, 1031, 1033, 1034, 1036, 1037, 1038, 1039, 1040, 1044, 1045, 1046, 1048, 1049, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1078, 1080, 1081, 1085, 1086, 1087, 1089, 1090, 1094, 1095, 1096, 1099, 1103, 1107, 1130, 1131, 1132, 1134, 1135, 1136, 1137, 1138, 1140, 1141, 1142, 1143, 1144, 1147, 1148, 1150, 1151, 1153, 1155, 1156, 1158, 1159, 1160, 1164, 1165, 1168, 1169, 1171, 1172, 1173, 1174, 1175, 1176, 1186, 1196, 1197, 1198, 1199, 1202, 1203, 1204, 1205, 1206, 1209, 1215, 1216, 1222, 1227, 1228, 1235, 1236, 1242, 1244, 1246, 1247, 1248, 1249, 1250, 1261, 1262, 1264, 1265, 1267, 1268, 1272, 1273, 1277, 1278, 1280, 1281, 1284, 1285, 1286, 1288, 1289, 1290, 1291, 1293, 1294, 1305, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1328, 1331, 1338, 1339, 1340, 1348, 1349, 1350, 1351, 1354, 1356, 1358, 1359, 1361, 1362, 1363, 1371, 1372, 1373, 1374, 1375, 1380, 1382, 1385, 1387, 1388, 1394, 1395, 1397, 1398, 1401, 1415, 1416, 1421, 1422, 1423, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1435, 1436, 1437, 1438, 1447, 1448, 1449, 1451, 1452, 1454, 1455, 1456, 1457, 1458, 1459, 1462, 1463, 1464, 1466, 1467, 1469, 1470, 1471, 1472, 1473, 1474], "excluded_lines": []}, "": {"executed_lines": [3, 18, 19, 21, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 48, 49, 50, 53, 56, 57, 76, 80, 123, 132, 152, 242, 256, 327, 369, 383, 429, 450, 494, 529, 554, 597, 619, 674, 697, 717, 738, 751, 784, 799, 837, 1101, 1105, 1109, 1252, 1307, 1344, 1365, 1407, 1440], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [22, 23, 25]}}}, "src/seedpass/core/entry_service.py": {"executed_lines": [1, 3, 4, 5, 7, 9, 14, 15, 17, 21, 22, 24, 27], "summary": {"covered_lines": 11, "num_statements": 114, "percent_covered": 9.649122807017545, "percent_covered_display": "10", "missing_lines": 103, "excluded_lines": 8}, "missing_lines": [25, 28, 29, 30, 31, 39, 40, 41, 44, 45, 46, 47, 52, 53, 54, 55, 61, 62, 64, 65, 66, 68, 69, 71, 77, 78, 81, 88, 90, 91, 92, 100, 102, 103, 104, 105, 106, 107, 108, 114, 115, 116, 117, 119, 120, 122, 123, 124, 127, 128, 129, 131, 139, 140, 142, 143, 144, 150, 151, 152, 153, 154, 155, 156, 157, 158, 162, 164, 167, 168, 169, 171, 174, 175, 177, 178, 179, 181, 184, 185, 186, 188, 191, 192, 193, 194, 196, 199, 200, 201, 202, 204, 205, 206, 207, 208, 210, 213, 214, 215, 216, 218, 237], "excluded_lines": [17, 18, 95, 96, 239, 240, 241, 242], "functions": {"EntryService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [25], "excluded_lines": []}, "EntryService.handle_add_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 77, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 77, "excluded_lines": 4}, "missing_lines": [28, 29, 30, 31, 39, 64, 102, 103, 104, 105, 106, 107, 108, 114, 115, 116, 117, 119, 120, 122, 123, 124, 127, 128, 129, 131, 139, 140, 142, 143, 144, 150, 151, 152, 153, 154, 155, 156, 157, 158, 162, 164, 167, 168, 169, 171, 174, 175, 177, 178, 179, 181, 184, 185, 186, 188, 191, 192, 193, 194, 196, 199, 200, 201, 202, 204, 205, 206, 207, 208, 210, 213, 214, 215, 216, 218, 237], "excluded_lines": [239, 240, 241, 242]}, "EntryService.handle_add_password.prompt_length": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [40, 41, 44, 45, 46, 47, 52, 53, 54, 55, 61, 62], "excluded_lines": []}, "EntryService.handle_add_password.finalize_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 2}, "missing_lines": [65, 66, 68, 69, 71, 77, 78, 81, 88, 90, 91, 92, 100], "excluded_lines": [95, 96]}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 14, 15, 17, 21, 22, 24, 27], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [17, 18]}}, "classes": {"EntryService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 103, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 103, "excluded_lines": 6}, "missing_lines": [25, 28, 29, 30, 31, 39, 40, 41, 44, 45, 46, 47, 52, 53, 54, 55, 61, 62, 64, 65, 66, 68, 69, 71, 77, 78, 81, 88, 90, 91, 92, 100, 102, 103, 104, 105, 106, 107, 108, 114, 115, 116, 117, 119, 120, 122, 123, 124, 127, 128, 129, 131, 139, 140, 142, 143, 144, 150, 151, 152, 153, 154, 155, 156, 157, 158, 162, 164, 167, 168, 169, 171, 174, 175, 177, 178, 179, 181, 184, 185, 186, 188, 191, 192, 193, 194, 196, 199, 200, 201, 202, 204, 205, 206, 207, 208, 210, 213, 214, 215, 216, 218, 237], "excluded_lines": [95, 96, 239, 240, 241, 242]}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 14, 15, 17, 21, 22, 24, 27], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [17, 18]}}}, "src/seedpass/core/entry_types.py": {"executed_lines": [2, 4, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 21], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [2, 4, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 21], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"EntryType": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [2, 4, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 21], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/errors.py": {"executed_lines": [1, 11, 12, 15, 16, 18, 22, 23, 30], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [19], "excluded_lines": [], "functions": {"SeedPassError.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [19], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 15, 16, 18, 22, 23, 30], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"SeedPassError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [19], "excluded_lines": []}, "DecryptionError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 15, 16, 18, 22, 23, 30], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/manager.py": {"executed_lines": [3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 52, 53, 60, 66, 67, 68, 69, 75, 76, 77, 78, 79, 81, 94, 95, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 112, 113, 114, 115, 118, 121, 122, 124, 141, 158, 164, 189, 190, 191, 193, 194, 197, 200, 201, 206, 209, 210, 212, 218, 227, 228, 237, 238, 239, 240, 241, 242, 244, 327, 328, 339, 340, 345, 355, 369, 386, 387, 391, 392, 398, 399, 407, 408, 422, 423, 432, 441, 450, 465, 477, 478, 483, 484, 489, 490, 497, 505, 551, 565, 577, 621, 667, 700, 794, 839, 840, 841, 844, 845, 875, 876, 900, 901, 987, 988, 1032, 1071, 1077, 1169, 1170, 1251, 1271, 1292, 1293, 1365, 1395, 1537, 1651, 1654, 1685, 1693, 1722, 1724, 1727, 1728, 1729, 1730, 1731, 1737, 1738, 1739, 1740, 1743, 1744, 1745, 1746, 1748, 1750, 1813, 1816, 1824, 1835, 1861, 1890, 1891, 1894, 1895, 2036, 2037, 2094, 2095, 2164, 2165, 2232, 2233, 2292, 2293, 2374, 2375, 2437, 2464, 2481, 2488, 2511, 2604, 2682, 2745, 3165, 3166, 3200, 3201, 3638, 3639, 3696, 3848, 3849, 3852, 3889, 3890, 3908, 3909, 3986, 3987, 3990, 3991, 4030, 4031, 4059, 4079, 4100, 4145, 4150, 4161, 4176, 4177, 4219, 4220, 4302, 4303, 4373, 4374, 4470, 4515, 4532, 4573, 4648, 4720], "summary": {"covered_lines": 237, "num_statements": 2703, "percent_covered": 8.76803551609323, "percent_covered_display": "9", "missing_lines": 2466, "excluded_lines": 32}, "missing_lines": [125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 142, 143, 148, 149, 152, 153, 154, 155, 160, 161, 174, 175, 176, 177, 180, 182, 183, 185, 186, 202, 203, 204, 215, 216, 220, 221, 222, 223, 224, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 277, 278, 279, 280, 281, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 304, 305, 306, 309, 310, 311, 314, 316, 318, 321, 323, 333, 334, 335, 343, 348, 349, 350, 351, 352, 353, 357, 363, 364, 365, 366, 367, 371, 372, 373, 374, 375, 376, 377, 378, 389, 394, 395, 396, 400, 401, 402, 403, 405, 410, 411, 412, 413, 414, 417, 418, 419, 420, 425, 426, 427, 428, 429, 430, 434, 435, 436, 437, 438, 439, 443, 444, 445, 446, 447, 448, 452, 453, 454, 455, 456, 458, 462, 463, 467, 468, 469, 470, 471, 472, 473, 474, 475, 479, 480, 481, 485, 486, 487, 491, 492, 493, 494, 495, 499, 500, 501, 502, 503, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 536, 541, 542, 543, 546, 547, 548, 549, 555, 556, 557, 558, 559, 560, 563, 569, 570, 572, 575, 581, 582, 583, 586, 587, 588, 590, 591, 592, 597, 598, 600, 602, 603, 604, 605, 607, 608, 610, 613, 614, 616, 617, 618, 619, 626, 627, 634, 635, 636, 637, 638, 639, 641, 642, 644, 645, 648, 649, 657, 658, 660, 662, 663, 664, 665, 670, 671, 672, 675, 676, 682, 686, 688, 689, 690, 697, 698, 709, 710, 711, 712, 713, 714, 716, 721, 726, 727, 729, 730, 731, 733, 734, 735, 736, 737, 738, 739, 741, 744, 745, 746, 747, 752, 753, 754, 755, 757, 758, 759, 760, 761, 762, 764, 765, 766, 767, 768, 770, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 799, 800, 802, 803, 805, 806, 811, 816, 817, 818, 819, 820, 822, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 842, 847, 848, 850, 851, 852, 853, 855, 859, 860, 861, 863, 864, 865, 866, 867, 869, 870, 871, 872, 873, 878, 879, 880, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 894, 895, 896, 897, 898, 906, 907, 908, 911, 912, 915, 916, 917, 923, 927, 928, 929, 934, 936, 937, 938, 939, 941, 942, 943, 946, 947, 948, 951, 956, 960, 961, 962, 963, 964, 965, 966, 967, 970, 975, 976, 977, 978, 980, 981, 982, 983, 984, 985, 993, 995, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1025, 1026, 1029, 1030, 1052, 1053, 1054, 1055, 1056, 1058, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1075, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1093, 1094, 1095, 1096, 1102, 1106, 1109, 1110, 1113, 1115, 1116, 1117, 1118, 1119, 1120, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1133, 1137, 1138, 1139, 1141, 1146, 1147, 1149, 1150, 1152, 1153, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1165, 1166, 1167, 1177, 1178, 1179, 1180, 1182, 1184, 1185, 1186, 1187, 1188, 1189, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1203, 1204, 1205, 1206, 1212, 1214, 1217, 1218, 1221, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1233, 1234, 1235, 1238, 1239, 1240, 1241, 1243, 1244, 1246, 1248, 1249, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1303, 1304, 1305, 1309, 1313, 1314, 1315, 1318, 1320, 1321, 1323, 1324, 1325, 1326, 1331, 1335, 1336, 1338, 1342, 1347, 1348, 1350, 1351, 1353, 1354, 1358, 1359, 1360, 1361, 1362, 1363, 1369, 1370, 1371, 1372, 1373, 1374, 1376, 1379, 1380, 1381, 1384, 1386, 1387, 1389, 1390, 1391, 1392, 1393, 1400, 1402, 1403, 1406, 1409, 1413, 1414, 1419, 1420, 1421, 1427, 1428, 1431, 1432, 1433, 1435, 1440, 1441, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1469, 1470, 1471, 1472, 1473, 1474, 1485, 1488, 1490, 1491, 1492, 1499, 1500, 1501, 1502, 1503, 1504, 1507, 1508, 1509, 1516, 1523, 1530, 1532, 1533, 1534, 1535, 1539, 1540, 1541, 1542, 1543, 1544, 1545, 1546, 1547, 1548, 1553, 1557, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1594, 1595, 1596, 1597, 1604, 1610, 1611, 1616, 1623, 1629, 1630, 1631, 1632, 1633, 1638, 1639, 1642, 1647, 1648, 1649, 1652, 1656, 1657, 1658, 1659, 1660, 1663, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1674, 1675, 1676, 1677, 1680, 1681, 1683, 1687, 1688, 1689, 1690, 1691, 1695, 1700, 1702, 1703, 1704, 1707, 1708, 1709, 1714, 1715, 1716, 1717, 1719, 1720, 1725, 1732, 1733, 1734, 1735, 1757, 1758, 1760, 1761, 1762, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1807, 1808, 1809, 1811, 1814, 1822, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1837, 1838, 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1848, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1859, 1863, 1864, 1866, 1867, 1868, 1869, 1871, 1872, 1873, 1875, 1876, 1877, 1878, 1879, 1880, 1882, 1885, 1887, 1888, 1892, 1897, 1898, 1899, 1900, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1922, 1923, 1924, 1927, 1932, 1933, 1934, 1939, 1949, 1950, 1951, 1953, 1954, 1955, 1956, 1957, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1983, 1984, 1985, 1986, 1987, 1988, 1991, 1996, 1997, 2007, 2008, 2009, 2015, 2016, 2017, 2018, 2019, 2023, 2024, 2025, 2026, 2027, 2028, 2030, 2031, 2032, 2033, 2034, 2039, 2040, 2041, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2059, 2062, 2065, 2066, 2068, 2071, 2072, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2088, 2089, 2090, 2091, 2092, 2097, 2098, 2099, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2118, 2119, 2120, 2121, 2122, 2125, 2126, 2127, 2129, 2132, 2133, 2135, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2150, 2151, 2152, 2153, 2154, 2158, 2159, 2160, 2161, 2162, 2167, 2168, 2169, 2176, 2177, 2178, 2179, 2180, 2184, 2185, 2186, 2187, 2192, 2200, 2203, 2204, 2206, 2209, 2210, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2226, 2227, 2228, 2229, 2230, 2235, 2236, 2237, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2255, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2272, 2273, 2274, 2275, 2278, 2279, 2280, 2286, 2287, 2288, 2289, 2290, 2295, 2296, 2297, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, 2337, 2345, 2346, 2348, 2349, 2350, 2351, 2352, 2353, 2360, 2361, 2362, 2368, 2369, 2370, 2371, 2372, 2377, 2378, 2379, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2397, 2400, 2401, 2402, 2403, 2409, 2410, 2411, 2412, 2419, 2420, 2421, 2423, 2424, 2425, 2431, 2432, 2433, 2434, 2435, 2439, 2440, 2441, 2442, 2444, 2445, 2453, 2455, 2457, 2458, 2459, 2460, 2461, 2462, 2466, 2467, 2472, 2473, 2474, 2475, 2477, 2478, 2479, 2483, 2484, 2485, 2486, 2492, 2493, 2494, 2496, 2497, 2498, 2500, 2501, 2505, 2506, 2507, 2509, 2513, 2514, 2515, 2522, 2523, 2524, 2525, 2526, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2539, 2541, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563, 2564, 2565, 2567, 2568, 2569, 2570, 2573, 2574, 2575, 2576, 2577, 2578, 2584, 2587, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2601, 2602, 2606, 2607, 2608, 2609, 2616, 2617, 2618, 2619, 2620, 2623, 2624, 2625, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, 2645, 2646, 2647, 2648, 2649, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, 2662, 2663, 2664, 2665, 2666, 2667, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2677, 2679, 2680, 2685, 2687, 2688, 2689, 2690, 2692, 2696, 2697, 2699, 2700, 2701, 2703, 2704, 2705, 2706, 2713, 2714, 2715, 2716, 2721, 2722, 2724, 2728, 2729, 2730, 2731, 2732, 2733, 2735, 2736, 2737, 2738, 2740, 2756, 2758, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2772, 2773, 2780, 2781, 2782, 2783, 2784, 2785, 2786, 2787, 2788, 2789, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 2812, 2813, 2814, 2815, 2819, 2821, 2822, 2823, 2824, 2827, 2828, 2829, 2830, 2833, 2834, 2835, 2836, 2837, 2838, 2839, 2840, 2841, 2842, 2843, 2844, 2845, 2852, 2853, 2857, 2859, 2860, 2861, 2862, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874, 2875, 2876, 2877, 2878, 2879, 2880, 2887, 2888, 2889, 2890, 2892, 2893, 2894, 2895, 2896, 2902, 2906, 2908, 2909, 2910, 2911, 2914, 2915, 2916, 2917, 2920, 2921, 2922, 2923, 2924, 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2938, 2942, 2944, 2945, 2946, 2947, 2948, 2951, 2952, 2953, 2954, 2955, 2956, 2963, 2964, 2965, 2966, 2967, 2968, 2972, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2981, 2982, 2983, 2984, 2985, 2990, 2991, 2992, 2999, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3021, 3028, 3029, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3049, 3056, 3057, 3060, 3061, 3062, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3078, 3079, 3080, 3081, 3082, 3083, 3085, 3091, 3092, 3093, 3094, 3095, 3096, 3101, 3103, 3104, 3105, 3106, 3113, 3119, 3120, 3121, 3122, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3144, 3145, 3146, 3147, 3148, 3149, 3150, 3153, 3160, 3162, 3163, 3168, 3169, 3170, 3177, 3180, 3181, 3182, 3183, 3184, 3186, 3187, 3188, 3189, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198, 3206, 3207, 3208, 3215, 3218, 3219, 3220, 3221, 3224, 3225, 3226, 3228, 3230, 3231, 3232, 3233, 3234, 3235, 3237, 3243, 3244, 3245, 3251, 3255, 3258, 3259, 3260, 3261, 3263, 3267, 3270, 3271, 3272, 3273, 3275, 3279, 3286, 3287, 3288, 3289, 3290, 3291, 3293, 3297, 3299, 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3320, 3323, 3329, 3339, 3340, 3341, 3342, 3344, 3350, 3356, 3360, 3367, 3368, 3369, 3370, 3371, 3372, 3374, 3378, 3380, 3387, 3390, 3396, 3403, 3407, 3408, 3409, 3410, 3412, 3418, 3424, 3430, 3434, 3435, 3439, 3440, 3444, 3451, 3452, 3453, 3454, 3455, 3456, 3458, 3462, 3464, 3471, 3472, 3473, 3474, 3475, 3476, 3479, 3480, 3481, 3482, 3483, 3487, 3490, 3496, 3504, 3505, 3507, 3512, 3513, 3514, 3515, 3516, 3518, 3524, 3525, 3526, 3527, 3534, 3541, 3547, 3553, 3560, 3561, 3562, 3563, 3564, 3565, 3567, 3571, 3573, 3580, 3581, 3582, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3594, 3597, 3603, 3615, 3616, 3618, 3621, 3622, 3623, 3626, 3627, 3632, 3634, 3635, 3636, 3641, 3642, 3643, 3650, 3651, 3652, 3653, 3654, 3656, 3657, 3658, 3659, 3660, 3662, 3663, 3664, 3671, 3672, 3673, 3674, 3675, 3676, 3677, 3679, 3682, 3683, 3684, 3687, 3688, 3689, 3690, 3691, 3692, 3693, 3694, 3698, 3699, 3700, 3702, 3703, 3704, 3705, 3706, 3709, 3715, 3716, 3717, 3718, 3719, 3720, 3721, 3722, 3723, 3724, 3725, 3726, 3732, 3733, 3734, 3735, 3736, 3737, 3738, 3739, 3740, 3741, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3752, 3753, 3754, 3755, 3756, 3757, 3758, 3759, 3762, 3763, 3764, 3765, 3768, 3769, 3770, 3771, 3776, 3777, 3778, 3779, 3780, 3781, 3782, 3783, 3784, 3785, 3788, 3789, 3790, 3791, 3792, 3793, 3794, 3795, 3796, 3797, 3798, 3799, 3800, 3801, 3802, 3803, 3804, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3815, 3816, 3817, 3818, 3819, 3820, 3821, 3822, 3823, 3824, 3825, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3839, 3840, 3846, 3850, 3854, 3855, 3858, 3859, 3860, 3861, 3863, 3866, 3867, 3869, 3872, 3873, 3876, 3877, 3878, 3879, 3880, 3885, 3886, 3887, 3892, 3893, 3896, 3897, 3898, 3899, 3900, 3901, 3902, 3903, 3904, 3905, 3906, 3911, 3913, 3916, 3919, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3940, 3941, 3942, 3943, 3946, 3947, 3948, 3951, 3952, 3953, 3954, 3955, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3977, 3978, 3979, 3981, 3982, 3983, 3984, 3988, 3995, 3996, 3997, 4004, 4005, 4006, 4007, 4008, 4012, 4013, 4015, 4016, 4017, 4019, 4025, 4026, 4027, 4028, 4033, 4034, 4035, 4036, 4037, 4038, 4045, 4046, 4047, 4054, 4055, 4056, 4057, 4065, 4066, 4067, 4068, 4069, 4071, 4072, 4073, 4074, 4075, 4076, 4077, 4085, 4086, 4087, 4088, 4089, 4092, 4098, 4104, 4105, 4106, 4107, 4108, 4109, 4110, 4111, 4112, 4113, 4114, 4115, 4117, 4120, 4121, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4135, 4136, 4141, 4142, 4143, 4148, 4154, 4155, 4156, 4157, 4158, 4159, 4165, 4166, 4167, 4172, 4173, 4174, 4189, 4190, 4191, 4198, 4199, 4202, 4209, 4210, 4211, 4212, 4213, 4214, 4215, 4216, 4217, 4223, 4224, 4230, 4233, 4234, 4235, 4236, 4237, 4238, 4239, 4240, 4241, 4243, 4244, 4252, 4253, 4259, 4260, 4261, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274, 4280, 4282, 4283, 4284, 4285, 4286, 4289, 4290, 4291, 4292, 4293, 4296, 4297, 4299, 4300, 4305, 4306, 4307, 4308, 4315, 4316, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4327, 4328, 4329, 4330, 4331, 4341, 4342, 4343, 4345, 4348, 4350, 4352, 4353, 4354, 4355, 4358, 4359, 4360, 4361, 4363, 4365, 4366, 4367, 4368, 4369, 4370, 4371, 4386, 4387, 4388, 4395, 4396, 4400, 4406, 4407, 4410, 4411, 4412, 4415, 4418, 4419, 4422, 4423, 4424, 4431, 4432, 4433, 4434, 4436, 4439, 4440, 4443, 4444, 4446, 4447, 4448, 4449, 4451, 4454, 4460, 4461, 4462, 4465, 4466, 4467, 4468, 4480, 4481, 4482, 4483, 4485, 4486, 4487, 4488, 4489, 4491, 4492, 4493, 4495, 4496, 4497, 4499, 4500, 4501, 4502, 4503, 4509, 4510, 4511, 4512, 4513, 4526, 4527, 4528, 4529, 4530, 4537, 4538, 4539, 4540, 4543, 4544, 4549, 4550, 4551, 4553, 4554, 4555, 4556, 4558, 4559, 4564, 4565, 4568, 4569, 4570, 4571, 4575, 4576, 4577, 4578, 4581, 4582, 4585, 4587, 4588, 4591, 4593, 4595, 4596, 4597, 4598, 4599, 4602, 4603, 4604, 4606, 4607, 4608, 4610, 4611, 4621, 4624, 4626, 4627, 4628, 4637, 4638, 4639, 4640, 4641, 4644, 4645, 4646, 4650, 4651, 4653, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4674, 4675, 4676, 4679, 4680, 4681, 4682, 4683, 4685, 4686, 4687, 4689, 4692, 4693, 4694, 4695, 4698, 4701, 4702, 4703, 4708, 4709, 4710, 4711, 4712, 4714, 4715, 4716, 4718, 4722, 4723, 4724, 4725, 4727, 4728, 4729, 4730, 4731, 4732, 4738, 4739, 4744, 4745, 4751, 4757, 4758, 4759, 4760], "excluded_lines": [1804, 1805, 1832, 1833, 2221, 2222, 2281, 2282, 2363, 2364, 2426, 2427, 2741, 2742, 2743, 2816, 2817, 2818, 2854, 2855, 2856, 2903, 2904, 2905, 2939, 2940, 2941, 2969, 2970, 2971, 3772, 3773], "functions": {"AuditLogger.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139], "excluded_lines": []}, "AuditLogger.log": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [142, 143, 148, 149, 152, 153, 154, 155], "excluded_lines": []}, "calculate_profile_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [160, 161], "excluded_lines": []}, "restore_backup_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [174, 175, 176, 177, 180, 182, 183, 185, 186], "excluded_lines": []}, "requires_unlocked": {"executed_lines": [200, 201, 206], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "requires_unlocked.wrapper": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [202, 203, 204], "excluded_lines": []}, "AuthGuard.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [215, 216], "excluded_lines": []}, "AuthGuard.check_timeout": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [220, 221, 222, 223, 224], "excluded_lines": []}, "PasswordManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 55, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 55, "excluded_lines": 0}, "missing_lines": [254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 277, 278, 279, 280, 281, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 304, 305, 306, 309, 310, 311, 314, 316, 318, 321, 323], "excluded_lines": []}, "PasswordManager.get_bip85_entropy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [333, 334, 335], "excluded_lines": []}, "PasswordManager.clear_bip85_cache": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [343], "excluded_lines": []}, "PasswordManager.derive_key_hierarchy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [348, 349, 350, 351, 352, 353], "excluded_lines": []}, "PasswordManager.ensure_key_hierarchy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [357, 363, 364, 365, 366, 367], "excluded_lines": []}, "PasswordManager.ensure_script_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [371, 372, 373, 374, 375, 376, 377, 378], "excluded_lines": []}, "PasswordManager.get_password_prompt": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [389], "excluded_lines": []}, "PasswordManager.parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [400, 401, 402, 403, 405], "excluded_lines": []}, "PasswordManager.header_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [410, 411, 412, 413, 414, 417, 418, 419, 420], "excluded_lines": []}, "PasswordManager.header_fingerprint_args": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [425, 426, 427, 428, 429, 430], "excluded_lines": []}, "PasswordManager.update_activity": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [434, 435, 436, 437, 438, 439], "excluded_lines": []}, "PasswordManager.notify": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [443, 444, 445, 446, 447, 448], "excluded_lines": []}, "PasswordManager.get_current_notification": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [452, 453, 454, 455, 456, 458, 462, 463], "excluded_lines": []}, "PasswordManager.poll_background_errors": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [467, 468, 469, 470, 471, 472, 473, 474, 475], "excluded_lines": []}, "PasswordManager.menu_handler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [479, 480, 481], "excluded_lines": []}, "PasswordManager.profile_service": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [485, 486, 487], "excluded_lines": []}, "PasswordManager.entry_service": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [491, 492, 493, 494, 495], "excluded_lines": []}, "PasswordManager.lock_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [499, 500, 501, 502, 503], "excluded_lines": []}, "PasswordManager.unlock_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 536, 541, 542, 543, 546, 547, 548, 549], "excluded_lines": []}, "PasswordManager.initialize_fingerprint_manager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [555, 556, 557, 558, 559, 560, 563], "excluded_lines": []}, "PasswordManager.setup_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [569, 570, 572, 575], "excluded_lines": []}, "PasswordManager.select_or_add_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [581, 582, 583, 586, 587, 588, 590, 591, 592, 597, 598, 600, 602, 603, 604, 605, 607, 608, 610, 613, 614, 616, 617, 618, 619], "excluded_lines": []}, "PasswordManager.add_new_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [626, 627, 634, 635, 636, 637, 638, 639, 641, 642, 644, 645, 648, 649, 657, 658, 660, 662, 663, 664, 665], "excluded_lines": []}, "PasswordManager.select_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [670, 671, 672, 675, 676, 682, 686, 688, 689, 690, 697, 698], "excluded_lines": []}, "PasswordManager.setup_encryption_manager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 59, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 59, "excluded_lines": 0}, "missing_lines": [709, 710, 711, 712, 713, 714, 716, 721, 726, 727, 729, 730, 731, 733, 734, 735, 736, 737, 738, 739, 741, 744, 745, 746, 747, 752, 753, 754, 755, 757, 758, 759, 760, 761, 762, 764, 765, 766, 767, 768, 770, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792], "excluded_lines": []}, "PasswordManager.load_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 0}, "missing_lines": [799, 800, 802, 803, 805, 806, 811, 816, 817, 818, 819, 820, 822, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837], "excluded_lines": []}, "PasswordManager.handle_switch_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [842], "excluded_lines": []}, "PasswordManager.load_managed_account": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [847, 848, 850, 851, 852, 853, 855, 859, 860, 861, 863, 864, 865, 866, 867, 869, 870, 871, 872, 873], "excluded_lines": []}, "PasswordManager.exit_managed_account": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [878, 879, 880, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 894, 895, 896, 897, 898], "excluded_lines": []}, "PasswordManager.handle_existing_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 44, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 44, "excluded_lines": 0}, "missing_lines": [906, 907, 908, 911, 912, 915, 916, 917, 923, 927, 928, 929, 934, 936, 937, 938, 939, 941, 942, 943, 946, 947, 948, 951, 956, 960, 961, 962, 963, 964, 965, 966, 967, 970, 975, 976, 977, 978, 980, 981, 982, 983, 984, 985], "excluded_lines": []}, "PasswordManager.handle_new_seed_setup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [993, 995, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1025, 1026, 1029, 1030], "excluded_lines": []}, "PasswordManager.setup_existing_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [1052, 1053, 1054, 1055, 1056, 1058, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069], "excluded_lines": []}, "PasswordManager.setup_existing_seed_word_by_word": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1075], "excluded_lines": []}, "PasswordManager._finalize_existing_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 53, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 53, "excluded_lines": 0}, "missing_lines": [1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1093, 1094, 1095, 1096, 1102, 1106, 1109, 1110, 1113, 1115, 1116, 1117, 1118, 1119, 1120, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1133, 1137, 1138, 1139, 1141, 1146, 1147, 1149, 1150, 1152, 1153, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1165, 1166, 1167], "excluded_lines": []}, "PasswordManager.generate_new_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 48, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 48, "excluded_lines": 0}, "missing_lines": [1177, 1178, 1179, 1180, 1182, 1184, 1185, 1186, 1187, 1188, 1189, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1203, 1204, 1205, 1206, 1212, 1214, 1217, 1218, 1221, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1233, 1234, 1235, 1238, 1239, 1240, 1241, 1243, 1244, 1246, 1248, 1249], "excluded_lines": []}, "PasswordManager.validate_bip85_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269], "excluded_lines": []}, "PasswordManager.generate_bip85_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290], "excluded_lines": []}, "PasswordManager.save_and_encrypt_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 31, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 31, "excluded_lines": 0}, "missing_lines": [1303, 1304, 1305, 1309, 1313, 1314, 1315, 1318, 1320, 1321, 1323, 1324, 1325, 1326, 1331, 1335, 1336, 1338, 1342, 1347, 1348, 1350, 1351, 1353, 1354, 1358, 1359, 1360, 1361, 1362, 1363], "excluded_lines": []}, "PasswordManager.initialize_bip85": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [1369, 1370, 1371, 1372, 1373, 1374, 1376, 1386, 1387, 1389, 1390, 1391, 1392, 1393], "excluded_lines": []}, "PasswordManager.initialize_bip85.cached_derive": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [1379, 1380, 1381, 1384], "excluded_lines": []}, "PasswordManager.initialize_managers": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 62, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 62, "excluded_lines": 0}, "missing_lines": [1400, 1402, 1403, 1406, 1409, 1413, 1414, 1419, 1420, 1421, 1427, 1428, 1431, 1432, 1433, 1435, 1440, 1441, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1469, 1470, 1471, 1472, 1473, 1474, 1485, 1488, 1490, 1491, 1492, 1499, 1500, 1501, 1502, 1503, 1504, 1507, 1508, 1509, 1516, 1523, 1530, 1532, 1533, 1534, 1535], "excluded_lines": []}, "PasswordManager.sync_index_from_nostr_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 59, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 59, "excluded_lines": 0}, "missing_lines": [1539, 1540, 1541, 1542, 1543, 1544, 1545, 1546, 1547, 1548, 1553, 1557, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1594, 1595, 1596, 1597, 1604, 1610, 1611, 1616, 1623, 1629, 1630, 1631, 1632, 1633, 1638, 1639, 1642, 1647, 1648, 1649], "excluded_lines": []}, "PasswordManager.sync_index_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1652], "excluded_lines": []}, "PasswordManager.start_background_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [1656, 1657, 1658, 1659, 1660, 1663, 1665, 1674, 1675, 1676, 1677, 1680, 1681, 1683], "excluded_lines": []}, "PasswordManager.start_background_sync._worker": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [1666, 1667, 1668, 1669, 1670, 1671, 1672], "excluded_lines": []}, "PasswordManager.cleanup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [1687, 1688, 1689, 1690, 1691], "excluded_lines": []}, "PasswordManager.start_background_relay_check": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [1695, 1700, 1702, 1719, 1720], "excluded_lines": []}, "PasswordManager.start_background_relay_check._worker": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [1703, 1704, 1707, 1708, 1709, 1714, 1715, 1716, 1717], "excluded_lines": []}, "PasswordManager.start_background_vault_sync": {"executed_lines": [1724, 1727, 1737, 1738, 1739, 1740, 1743, 1744, 1745, 1746, 1748], "summary": {"covered_lines": 11, "num_statements": 12, "percent_covered": 91.66666666666667, "percent_covered_display": "92", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1725], "excluded_lines": []}, "PasswordManager.start_background_vault_sync._worker": {"executed_lines": [1728, 1729, 1730, 1731], "summary": {"covered_lines": 4, "num_statements": 8, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [1732, 1733, 1734, 1735], "excluded_lines": []}, "PasswordManager.attempt_initial_sync_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 37, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 37, "excluded_lines": 2}, "missing_lines": [1757, 1758, 1760, 1761, 1762, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1807, 1808, 1809, 1811], "excluded_lines": [1804, 1805]}, "PasswordManager.attempt_initial_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1814], "excluded_lines": []}, "PasswordManager.sync_index_from_nostr_if_missing": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1822], "excluded_lines": []}, "PasswordManager.sync_index_from_nostr_if_missing_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 2}, "missing_lines": [1825, 1826, 1827, 1828, 1829, 1830, 1831], "excluded_lines": [1832, 1833]}, "PasswordManager.check_nostr_backup_exists": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [1837, 1838, 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1848, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1859], "excluded_lines": []}, "PasswordManager.restore_from_nostr_with_guidance": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [1863, 1864, 1866, 1867, 1868, 1869, 1871, 1872, 1873, 1875, 1876, 1877, 1878, 1879, 1880, 1882, 1885, 1887, 1888], "excluded_lines": []}, "PasswordManager.handle_add_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1892], "excluded_lines": []}, "PasswordManager.handle_add_totp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 76, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 76, "excluded_lines": 0}, "missing_lines": [1897, 1898, 1899, 1900, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1922, 1923, 1924, 1927, 1932, 1933, 1934, 1939, 1949, 1950, 1951, 1953, 1954, 1955, 1956, 1957, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1983, 1984, 1985, 1986, 1987, 1988, 1991, 1996, 1997, 2007, 2008, 2009, 2015, 2016, 2017, 2018, 2019, 2023, 2024, 2025, 2026, 2027, 2028, 2030, 2031, 2032, 2033, 2034], "excluded_lines": []}, "PasswordManager.handle_add_ssh_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 0}, "missing_lines": [2039, 2040, 2041, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2059, 2062, 2065, 2066, 2068, 2071, 2072, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2088, 2089, 2090, 2091, 2092], "excluded_lines": []}, "PasswordManager.handle_add_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 0}, "missing_lines": [2097, 2098, 2099, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2118, 2119, 2120, 2121, 2122, 2125, 2126, 2127, 2129, 2132, 2133, 2135, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2150, 2151, 2152, 2153, 2154, 2158, 2159, 2160, 2161, 2162], "excluded_lines": []}, "PasswordManager.handle_add_pgp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 2}, "missing_lines": [2167, 2168, 2169, 2176, 2177, 2178, 2179, 2180, 2184, 2185, 2186, 2187, 2192, 2200, 2203, 2204, 2206, 2209, 2210, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2226, 2227, 2228, 2229, 2230], "excluded_lines": [2221, 2222]}, "PasswordManager.handle_add_nostr_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 31, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 31, "excluded_lines": 2}, "missing_lines": [2235, 2236, 2237, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2255, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2272, 2273, 2274, 2275, 2278, 2279, 2280, 2286, 2287, 2288, 2289, 2290], "excluded_lines": [2281, 2282]}, "PasswordManager.handle_add_key_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 2}, "missing_lines": [2295, 2296, 2297, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, 2337, 2345, 2346, 2348, 2349, 2350, 2351, 2352, 2353, 2360, 2361, 2362, 2368, 2369, 2370, 2371, 2372], "excluded_lines": [2363, 2364]}, "PasswordManager.handle_add_managed_account": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 30, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 30, "excluded_lines": 2}, "missing_lines": [2377, 2378, 2379, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2397, 2400, 2401, 2402, 2403, 2409, 2410, 2411, 2412, 2419, 2420, 2421, 2423, 2424, 2425, 2431, 2432, 2433, 2434, 2435], "excluded_lines": [2426, 2427]}, "PasswordManager.show_entry_details_by_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [2439, 2440, 2441, 2442, 2444, 2445, 2453, 2455, 2457, 2458, 2459, 2460, 2461, 2462], "excluded_lines": []}, "PasswordManager._prompt_toggle_archive": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [2466, 2467, 2472, 2473, 2474, 2475, 2477, 2478, 2479], "excluded_lines": []}, "PasswordManager._entry_type_str": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [2483, 2484, 2485, 2486], "excluded_lines": []}, "PasswordManager._generate_password_for_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [2492, 2493, 2494, 2496, 2497, 2498, 2500, 2501, 2505, 2506, 2507, 2509], "excluded_lines": []}, "PasswordManager._entry_actions_menu": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 61, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 61, "excluded_lines": 0}, "missing_lines": [2513, 2514, 2515, 2522, 2523, 2524, 2525, 2526, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2539, 2541, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563, 2564, 2565, 2567, 2568, 2569, 2570, 2573, 2574, 2575, 2576, 2577, 2578, 2584, 2587, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2601, 2602], "excluded_lines": []}, "PasswordManager._entry_edit_menu": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 62, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 62, "excluded_lines": 0}, "missing_lines": [2606, 2607, 2608, 2609, 2616, 2617, 2618, 2619, 2620, 2623, 2624, 2625, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, 2645, 2646, 2647, 2648, 2649, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, 2662, 2663, 2664, 2665, 2666, 2667, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2677, 2679, 2680], "excluded_lines": []}, "PasswordManager._entry_qr_menu": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 3}, "missing_lines": [2685, 2687, 2688, 2689, 2690, 2692, 2696, 2697, 2699, 2700, 2701, 2703, 2704, 2705, 2706, 2713, 2714, 2715, 2716, 2721, 2722, 2724, 2728, 2729, 2730, 2731, 2732, 2733, 2735, 2736, 2737, 2738, 2740], "excluded_lines": [2741, 2742, 2743]}, "PasswordManager.display_sensitive_entry_info": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 257, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 257, "excluded_lines": 15}, "missing_lines": [2756, 2758, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2772, 2773, 2780, 2781, 2782, 2783, 2784, 2785, 2786, 2787, 2788, 2789, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 2812, 2813, 2814, 2815, 2819, 2821, 2822, 2823, 2824, 2827, 2828, 2829, 2830, 2833, 2834, 2835, 2836, 2837, 2838, 2839, 2840, 2841, 2842, 2843, 2844, 2845, 2852, 2853, 2857, 2859, 2860, 2861, 2862, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874, 2875, 2876, 2877, 2878, 2879, 2880, 2887, 2888, 2889, 2890, 2892, 2893, 2894, 2895, 2896, 2902, 2906, 2908, 2909, 2910, 2911, 2914, 2915, 2916, 2917, 2920, 2921, 2922, 2923, 2924, 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2938, 2942, 2944, 2945, 2946, 2947, 2948, 2951, 2952, 2953, 2954, 2955, 2956, 2963, 2964, 2965, 2966, 2967, 2968, 2972, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2981, 2982, 2983, 2984, 2985, 2990, 2991, 2992, 2999, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3021, 3028, 3029, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3049, 3056, 3057, 3060, 3061, 3062, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3078, 3079, 3080, 3081, 3082, 3083, 3085, 3091, 3092, 3093, 3094, 3095, 3096, 3101, 3103, 3104, 3105, 3106, 3113, 3119, 3120, 3121, 3122, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3144, 3145, 3146, 3147, 3148, 3149, 3150, 3153, 3160, 3162, 3163], "excluded_lines": [2816, 2817, 2818, 2854, 2855, 2856, 2903, 2904, 2905, 2939, 2940, 2941, 2969, 2970, 2971]}, "PasswordManager.handle_retrieve_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [3168, 3169, 3170, 3177, 3180, 3181, 3182, 3183, 3184, 3186, 3187, 3188, 3189, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198], "excluded_lines": []}, "PasswordManager.handle_modify_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 168, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 168, "excluded_lines": 0}, "missing_lines": [3206, 3207, 3208, 3215, 3218, 3219, 3220, 3221, 3224, 3225, 3226, 3228, 3230, 3231, 3232, 3233, 3234, 3235, 3237, 3243, 3244, 3245, 3251, 3255, 3258, 3259, 3260, 3261, 3263, 3267, 3270, 3271, 3272, 3273, 3275, 3279, 3286, 3287, 3288, 3289, 3290, 3291, 3293, 3297, 3299, 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3320, 3323, 3329, 3339, 3340, 3341, 3342, 3344, 3350, 3356, 3360, 3367, 3368, 3369, 3370, 3371, 3372, 3374, 3378, 3380, 3387, 3390, 3396, 3403, 3407, 3408, 3409, 3410, 3412, 3418, 3424, 3430, 3434, 3435, 3439, 3440, 3444, 3451, 3452, 3453, 3454, 3455, 3456, 3458, 3462, 3464, 3471, 3472, 3473, 3474, 3475, 3476, 3479, 3480, 3481, 3482, 3483, 3487, 3490, 3496, 3504, 3505, 3507, 3512, 3513, 3514, 3515, 3516, 3518, 3524, 3525, 3526, 3527, 3534, 3541, 3547, 3553, 3560, 3561, 3562, 3563, 3564, 3565, 3567, 3571, 3573, 3580, 3581, 3582, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3594, 3597, 3603, 3615, 3616, 3618, 3621, 3622, 3623, 3626, 3627, 3632, 3634, 3635, 3636], "excluded_lines": []}, "PasswordManager.handle_search_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 35, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 35, "excluded_lines": 0}, "missing_lines": [3641, 3642, 3643, 3650, 3651, 3652, 3653, 3654, 3656, 3657, 3658, 3659, 3660, 3662, 3663, 3664, 3671, 3672, 3673, 3674, 3675, 3676, 3677, 3679, 3682, 3683, 3684, 3687, 3688, 3689, 3690, 3691, 3692, 3693, 3694], "excluded_lines": []}, "PasswordManager.display_entry_details": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 116, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 116, "excluded_lines": 2}, "missing_lines": [3698, 3699, 3700, 3702, 3703, 3704, 3705, 3706, 3709, 3715, 3716, 3717, 3718, 3719, 3720, 3721, 3722, 3723, 3724, 3725, 3726, 3732, 3733, 3734, 3735, 3736, 3737, 3738, 3739, 3740, 3741, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3752, 3753, 3754, 3755, 3756, 3757, 3758, 3759, 3762, 3763, 3764, 3765, 3768, 3769, 3770, 3771, 3776, 3777, 3778, 3779, 3780, 3781, 3782, 3783, 3784, 3785, 3788, 3789, 3790, 3791, 3792, 3793, 3794, 3795, 3796, 3797, 3798, 3799, 3800, 3801, 3802, 3803, 3804, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3815, 3816, 3817, 3818, 3819, 3820, 3821, 3822, 3823, 3824, 3825, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3839, 3840, 3846], "excluded_lines": [3772, 3773]}, "PasswordManager.handle_list_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [3850], "excluded_lines": []}, "PasswordManager.delete_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [3854, 3855, 3858, 3859, 3860, 3861, 3863, 3866, 3867, 3869, 3872, 3873, 3876, 3877, 3878, 3879, 3880, 3885, 3886, 3887], "excluded_lines": []}, "PasswordManager.handle_archive_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [3892, 3893, 3896, 3897, 3898, 3899, 3900, 3901, 3902, 3903, 3904, 3905, 3906], "excluded_lines": []}, "PasswordManager.handle_view_archived_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 49, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 49, "excluded_lines": 0}, "missing_lines": [3911, 3913, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3940, 3941, 3942, 3943, 3946, 3947, 3948, 3951, 3952, 3953, 3954, 3955, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3977, 3978, 3979, 3981, 3982, 3983, 3984], "excluded_lines": []}, "PasswordManager.handle_view_archived_entries._load_archived_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [3916, 3919], "excluded_lines": []}, "PasswordManager.handle_display_totp_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [3988], "excluded_lines": []}, "PasswordManager.handle_verify_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [3995, 3996, 3997, 4004, 4005, 4006, 4007, 4008, 4012, 4013, 4015, 4016, 4017, 4019, 4025, 4026, 4027, 4028], "excluded_lines": []}, "PasswordManager.handle_update_script_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [4033, 4034, 4035, 4036, 4037, 4038, 4045, 4046, 4047, 4054, 4055, 4056, 4057], "excluded_lines": []}, "PasswordManager.get_encrypted_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [4065, 4066, 4067, 4068, 4069, 4071, 4072, 4073, 4074, 4075, 4076, 4077], "excluded_lines": []}, "PasswordManager.decrypt_and_save_index_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [4085, 4086, 4087, 4088, 4089, 4092, 4098], "excluded_lines": []}, "PasswordManager.sync_vault_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 29, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 29, "excluded_lines": 0}, "missing_lines": [4104, 4105, 4106, 4107, 4108, 4109, 4110, 4111, 4112, 4113, 4114, 4115, 4117, 4120, 4121, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4135, 4136, 4141, 4142, 4143], "excluded_lines": []}, "PasswordManager.sync_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [4148], "excluded_lines": []}, "PasswordManager.backup_database": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [4154, 4155, 4156, 4157, 4158, 4159], "excluded_lines": []}, "PasswordManager.restore_database": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [4165, 4166, 4167, 4172, 4173, 4174], "excluded_lines": []}, "PasswordManager.handle_export_database": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [4189, 4190, 4191, 4198, 4199, 4202, 4209, 4210, 4211, 4212, 4213, 4214, 4215, 4216, 4217], "excluded_lines": []}, "PasswordManager.handle_import_database": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 42, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 42, "excluded_lines": 0}, "missing_lines": [4223, 4224, 4230, 4233, 4234, 4235, 4236, 4237, 4238, 4239, 4240, 4241, 4243, 4244, 4252, 4253, 4259, 4260, 4261, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274, 4280, 4282, 4283, 4284, 4285, 4286, 4289, 4290, 4291, 4292, 4293, 4296, 4297, 4299, 4300], "excluded_lines": []}, "PasswordManager.handle_export_totp_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 0}, "missing_lines": [4305, 4306, 4307, 4308, 4315, 4316, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4327, 4328, 4329, 4330, 4331, 4341, 4342, 4343, 4345, 4348, 4350, 4352, 4353, 4354, 4355, 4358, 4359, 4360, 4361, 4363, 4365, 4366, 4367, 4368, 4369, 4370, 4371], "excluded_lines": []}, "PasswordManager.handle_backup_reveal_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 39, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 39, "excluded_lines": 0}, "missing_lines": [4386, 4387, 4388, 4395, 4396, 4400, 4406, 4407, 4410, 4411, 4412, 4415, 4418, 4419, 4422, 4423, 4424, 4431, 4432, 4433, 4434, 4436, 4439, 4440, 4443, 4444, 4446, 4447, 4448, 4449, 4451, 4454, 4460, 4461, 4462, 4465, 4466, 4467, 4468], "excluded_lines": []}, "PasswordManager.verify_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [4480, 4481, 4482, 4483, 4485, 4486, 4487, 4488, 4489, 4491, 4492, 4493, 4495, 4496, 4497, 4499, 4500, 4501, 4502, 4503, 4509, 4510, 4511, 4512, 4513], "excluded_lines": []}, "PasswordManager.is_valid_filename": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [4526, 4527, 4528, 4529, 4530], "excluded_lines": []}, "PasswordManager.store_hashed_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [4537, 4538, 4539, 4540, 4543, 4544, 4549, 4550, 4551, 4553, 4554, 4555, 4556, 4558, 4559, 4564, 4565, 4568, 4569, 4570, 4571], "excluded_lines": []}, "PasswordManager.change_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 37, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 37, "excluded_lines": 0}, "missing_lines": [4575, 4576, 4577, 4578, 4581, 4582, 4585, 4587, 4588, 4591, 4593, 4595, 4596, 4597, 4598, 4599, 4602, 4603, 4604, 4606, 4607, 4608, 4610, 4611, 4621, 4624, 4626, 4627, 4628, 4637, 4638, 4639, 4640, 4641, 4644, 4645, 4646], "excluded_lines": []}, "PasswordManager.get_profile_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 47, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 47, "excluded_lines": 0}, "missing_lines": [4650, 4651, 4653, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4674, 4675, 4676, 4679, 4680, 4681, 4682, 4683, 4685, 4686, 4687, 4689, 4692, 4693, 4694, 4695, 4698, 4701, 4702, 4703, 4708, 4709, 4710, 4711, 4712, 4714, 4715, 4716, 4718], "excluded_lines": []}, "PasswordManager.display_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [4722, 4723, 4724, 4725, 4727, 4728, 4729, 4730, 4731, 4732, 4738, 4739, 4744, 4745, 4751, 4757, 4758, 4759, 4760], "excluded_lines": []}, "": {"executed_lines": [3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 52, 53, 60, 66, 67, 68, 69, 75, 76, 77, 78, 79, 81, 94, 95, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 112, 113, 114, 115, 118, 121, 122, 124, 141, 158, 164, 189, 190, 191, 193, 194, 197, 209, 210, 212, 218, 227, 228, 237, 238, 239, 240, 241, 242, 244, 327, 328, 339, 340, 345, 355, 369, 386, 387, 391, 392, 398, 399, 407, 408, 422, 423, 432, 441, 450, 465, 477, 478, 483, 484, 489, 490, 497, 505, 551, 565, 577, 621, 667, 700, 794, 839, 840, 841, 844, 845, 875, 876, 900, 901, 987, 988, 1032, 1071, 1077, 1169, 1170, 1251, 1271, 1292, 1293, 1365, 1395, 1537, 1651, 1654, 1685, 1693, 1722, 1750, 1813, 1816, 1824, 1835, 1861, 1890, 1891, 1894, 1895, 2036, 2037, 2094, 2095, 2164, 2165, 2232, 2233, 2292, 2293, 2374, 2375, 2437, 2464, 2481, 2488, 2511, 2604, 2682, 2745, 3165, 3166, 3200, 3201, 3638, 3639, 3696, 3848, 3849, 3852, 3889, 3890, 3908, 3909, 3986, 3987, 3990, 3991, 4030, 4031, 4059, 4079, 4100, 4145, 4150, 4161, 4176, 4177, 4219, 4220, 4302, 4303, 4373, 4374, 4470, 4515, 4532, 4573, 4648, 4720], "summary": {"covered_lines": 219, "num_statements": 219, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"AuditLogger": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 142, 143, 148, 149, 152, 153, 154, 155], "excluded_lines": []}, "Notification": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AuthGuard": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [215, 216, 220, 221, 222, 223, 224], "excluded_lines": []}, "PasswordManager": {"executed_lines": [1724, 1727, 1728, 1729, 1730, 1731, 1737, 1738, 1739, 1740, 1743, 1744, 1745, 1746, 1748], "summary": {"covered_lines": 15, "num_statements": 2437, "percent_covered": 0.6155108740254411, "percent_covered_display": "1", "missing_lines": 2422, "excluded_lines": 32}, "missing_lines": [254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 277, 278, 279, 280, 281, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 304, 305, 306, 309, 310, 311, 314, 316, 318, 321, 323, 333, 334, 335, 343, 348, 349, 350, 351, 352, 353, 357, 363, 364, 365, 366, 367, 371, 372, 373, 374, 375, 376, 377, 378, 389, 394, 395, 396, 400, 401, 402, 403, 405, 410, 411, 412, 413, 414, 417, 418, 419, 420, 425, 426, 427, 428, 429, 430, 434, 435, 436, 437, 438, 439, 443, 444, 445, 446, 447, 448, 452, 453, 454, 455, 456, 458, 462, 463, 467, 468, 469, 470, 471, 472, 473, 474, 475, 479, 480, 481, 485, 486, 487, 491, 492, 493, 494, 495, 499, 500, 501, 502, 503, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 536, 541, 542, 543, 546, 547, 548, 549, 555, 556, 557, 558, 559, 560, 563, 569, 570, 572, 575, 581, 582, 583, 586, 587, 588, 590, 591, 592, 597, 598, 600, 602, 603, 604, 605, 607, 608, 610, 613, 614, 616, 617, 618, 619, 626, 627, 634, 635, 636, 637, 638, 639, 641, 642, 644, 645, 648, 649, 657, 658, 660, 662, 663, 664, 665, 670, 671, 672, 675, 676, 682, 686, 688, 689, 690, 697, 698, 709, 710, 711, 712, 713, 714, 716, 721, 726, 727, 729, 730, 731, 733, 734, 735, 736, 737, 738, 739, 741, 744, 745, 746, 747, 752, 753, 754, 755, 757, 758, 759, 760, 761, 762, 764, 765, 766, 767, 768, 770, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 799, 800, 802, 803, 805, 806, 811, 816, 817, 818, 819, 820, 822, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 842, 847, 848, 850, 851, 852, 853, 855, 859, 860, 861, 863, 864, 865, 866, 867, 869, 870, 871, 872, 873, 878, 879, 880, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 894, 895, 896, 897, 898, 906, 907, 908, 911, 912, 915, 916, 917, 923, 927, 928, 929, 934, 936, 937, 938, 939, 941, 942, 943, 946, 947, 948, 951, 956, 960, 961, 962, 963, 964, 965, 966, 967, 970, 975, 976, 977, 978, 980, 981, 982, 983, 984, 985, 993, 995, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1025, 1026, 1029, 1030, 1052, 1053, 1054, 1055, 1056, 1058, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1075, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1093, 1094, 1095, 1096, 1102, 1106, 1109, 1110, 1113, 1115, 1116, 1117, 1118, 1119, 1120, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1133, 1137, 1138, 1139, 1141, 1146, 1147, 1149, 1150, 1152, 1153, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1165, 1166, 1167, 1177, 1178, 1179, 1180, 1182, 1184, 1185, 1186, 1187, 1188, 1189, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1203, 1204, 1205, 1206, 1212, 1214, 1217, 1218, 1221, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1233, 1234, 1235, 1238, 1239, 1240, 1241, 1243, 1244, 1246, 1248, 1249, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1303, 1304, 1305, 1309, 1313, 1314, 1315, 1318, 1320, 1321, 1323, 1324, 1325, 1326, 1331, 1335, 1336, 1338, 1342, 1347, 1348, 1350, 1351, 1353, 1354, 1358, 1359, 1360, 1361, 1362, 1363, 1369, 1370, 1371, 1372, 1373, 1374, 1376, 1379, 1380, 1381, 1384, 1386, 1387, 1389, 1390, 1391, 1392, 1393, 1400, 1402, 1403, 1406, 1409, 1413, 1414, 1419, 1420, 1421, 1427, 1428, 1431, 1432, 1433, 1435, 1440, 1441, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1469, 1470, 1471, 1472, 1473, 1474, 1485, 1488, 1490, 1491, 1492, 1499, 1500, 1501, 1502, 1503, 1504, 1507, 1508, 1509, 1516, 1523, 1530, 1532, 1533, 1534, 1535, 1539, 1540, 1541, 1542, 1543, 1544, 1545, 1546, 1547, 1548, 1553, 1557, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1594, 1595, 1596, 1597, 1604, 1610, 1611, 1616, 1623, 1629, 1630, 1631, 1632, 1633, 1638, 1639, 1642, 1647, 1648, 1649, 1652, 1656, 1657, 1658, 1659, 1660, 1663, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1674, 1675, 1676, 1677, 1680, 1681, 1683, 1687, 1688, 1689, 1690, 1691, 1695, 1700, 1702, 1703, 1704, 1707, 1708, 1709, 1714, 1715, 1716, 1717, 1719, 1720, 1725, 1732, 1733, 1734, 1735, 1757, 1758, 1760, 1761, 1762, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1807, 1808, 1809, 1811, 1814, 1822, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1837, 1838, 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1848, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1859, 1863, 1864, 1866, 1867, 1868, 1869, 1871, 1872, 1873, 1875, 1876, 1877, 1878, 1879, 1880, 1882, 1885, 1887, 1888, 1892, 1897, 1898, 1899, 1900, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1922, 1923, 1924, 1927, 1932, 1933, 1934, 1939, 1949, 1950, 1951, 1953, 1954, 1955, 1956, 1957, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1983, 1984, 1985, 1986, 1987, 1988, 1991, 1996, 1997, 2007, 2008, 2009, 2015, 2016, 2017, 2018, 2019, 2023, 2024, 2025, 2026, 2027, 2028, 2030, 2031, 2032, 2033, 2034, 2039, 2040, 2041, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2059, 2062, 2065, 2066, 2068, 2071, 2072, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2088, 2089, 2090, 2091, 2092, 2097, 2098, 2099, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2118, 2119, 2120, 2121, 2122, 2125, 2126, 2127, 2129, 2132, 2133, 2135, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2150, 2151, 2152, 2153, 2154, 2158, 2159, 2160, 2161, 2162, 2167, 2168, 2169, 2176, 2177, 2178, 2179, 2180, 2184, 2185, 2186, 2187, 2192, 2200, 2203, 2204, 2206, 2209, 2210, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2226, 2227, 2228, 2229, 2230, 2235, 2236, 2237, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2255, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2272, 2273, 2274, 2275, 2278, 2279, 2280, 2286, 2287, 2288, 2289, 2290, 2295, 2296, 2297, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, 2337, 2345, 2346, 2348, 2349, 2350, 2351, 2352, 2353, 2360, 2361, 2362, 2368, 2369, 2370, 2371, 2372, 2377, 2378, 2379, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2397, 2400, 2401, 2402, 2403, 2409, 2410, 2411, 2412, 2419, 2420, 2421, 2423, 2424, 2425, 2431, 2432, 2433, 2434, 2435, 2439, 2440, 2441, 2442, 2444, 2445, 2453, 2455, 2457, 2458, 2459, 2460, 2461, 2462, 2466, 2467, 2472, 2473, 2474, 2475, 2477, 2478, 2479, 2483, 2484, 2485, 2486, 2492, 2493, 2494, 2496, 2497, 2498, 2500, 2501, 2505, 2506, 2507, 2509, 2513, 2514, 2515, 2522, 2523, 2524, 2525, 2526, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2539, 2541, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563, 2564, 2565, 2567, 2568, 2569, 2570, 2573, 2574, 2575, 2576, 2577, 2578, 2584, 2587, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2601, 2602, 2606, 2607, 2608, 2609, 2616, 2617, 2618, 2619, 2620, 2623, 2624, 2625, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, 2645, 2646, 2647, 2648, 2649, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, 2662, 2663, 2664, 2665, 2666, 2667, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2677, 2679, 2680, 2685, 2687, 2688, 2689, 2690, 2692, 2696, 2697, 2699, 2700, 2701, 2703, 2704, 2705, 2706, 2713, 2714, 2715, 2716, 2721, 2722, 2724, 2728, 2729, 2730, 2731, 2732, 2733, 2735, 2736, 2737, 2738, 2740, 2756, 2758, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2772, 2773, 2780, 2781, 2782, 2783, 2784, 2785, 2786, 2787, 2788, 2789, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 2812, 2813, 2814, 2815, 2819, 2821, 2822, 2823, 2824, 2827, 2828, 2829, 2830, 2833, 2834, 2835, 2836, 2837, 2838, 2839, 2840, 2841, 2842, 2843, 2844, 2845, 2852, 2853, 2857, 2859, 2860, 2861, 2862, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874, 2875, 2876, 2877, 2878, 2879, 2880, 2887, 2888, 2889, 2890, 2892, 2893, 2894, 2895, 2896, 2902, 2906, 2908, 2909, 2910, 2911, 2914, 2915, 2916, 2917, 2920, 2921, 2922, 2923, 2924, 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2938, 2942, 2944, 2945, 2946, 2947, 2948, 2951, 2952, 2953, 2954, 2955, 2956, 2963, 2964, 2965, 2966, 2967, 2968, 2972, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2981, 2982, 2983, 2984, 2985, 2990, 2991, 2992, 2999, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3021, 3028, 3029, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3049, 3056, 3057, 3060, 3061, 3062, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3078, 3079, 3080, 3081, 3082, 3083, 3085, 3091, 3092, 3093, 3094, 3095, 3096, 3101, 3103, 3104, 3105, 3106, 3113, 3119, 3120, 3121, 3122, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3144, 3145, 3146, 3147, 3148, 3149, 3150, 3153, 3160, 3162, 3163, 3168, 3169, 3170, 3177, 3180, 3181, 3182, 3183, 3184, 3186, 3187, 3188, 3189, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198, 3206, 3207, 3208, 3215, 3218, 3219, 3220, 3221, 3224, 3225, 3226, 3228, 3230, 3231, 3232, 3233, 3234, 3235, 3237, 3243, 3244, 3245, 3251, 3255, 3258, 3259, 3260, 3261, 3263, 3267, 3270, 3271, 3272, 3273, 3275, 3279, 3286, 3287, 3288, 3289, 3290, 3291, 3293, 3297, 3299, 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3320, 3323, 3329, 3339, 3340, 3341, 3342, 3344, 3350, 3356, 3360, 3367, 3368, 3369, 3370, 3371, 3372, 3374, 3378, 3380, 3387, 3390, 3396, 3403, 3407, 3408, 3409, 3410, 3412, 3418, 3424, 3430, 3434, 3435, 3439, 3440, 3444, 3451, 3452, 3453, 3454, 3455, 3456, 3458, 3462, 3464, 3471, 3472, 3473, 3474, 3475, 3476, 3479, 3480, 3481, 3482, 3483, 3487, 3490, 3496, 3504, 3505, 3507, 3512, 3513, 3514, 3515, 3516, 3518, 3524, 3525, 3526, 3527, 3534, 3541, 3547, 3553, 3560, 3561, 3562, 3563, 3564, 3565, 3567, 3571, 3573, 3580, 3581, 3582, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3594, 3597, 3603, 3615, 3616, 3618, 3621, 3622, 3623, 3626, 3627, 3632, 3634, 3635, 3636, 3641, 3642, 3643, 3650, 3651, 3652, 3653, 3654, 3656, 3657, 3658, 3659, 3660, 3662, 3663, 3664, 3671, 3672, 3673, 3674, 3675, 3676, 3677, 3679, 3682, 3683, 3684, 3687, 3688, 3689, 3690, 3691, 3692, 3693, 3694, 3698, 3699, 3700, 3702, 3703, 3704, 3705, 3706, 3709, 3715, 3716, 3717, 3718, 3719, 3720, 3721, 3722, 3723, 3724, 3725, 3726, 3732, 3733, 3734, 3735, 3736, 3737, 3738, 3739, 3740, 3741, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3752, 3753, 3754, 3755, 3756, 3757, 3758, 3759, 3762, 3763, 3764, 3765, 3768, 3769, 3770, 3771, 3776, 3777, 3778, 3779, 3780, 3781, 3782, 3783, 3784, 3785, 3788, 3789, 3790, 3791, 3792, 3793, 3794, 3795, 3796, 3797, 3798, 3799, 3800, 3801, 3802, 3803, 3804, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3815, 3816, 3817, 3818, 3819, 3820, 3821, 3822, 3823, 3824, 3825, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3839, 3840, 3846, 3850, 3854, 3855, 3858, 3859, 3860, 3861, 3863, 3866, 3867, 3869, 3872, 3873, 3876, 3877, 3878, 3879, 3880, 3885, 3886, 3887, 3892, 3893, 3896, 3897, 3898, 3899, 3900, 3901, 3902, 3903, 3904, 3905, 3906, 3911, 3913, 3916, 3919, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3940, 3941, 3942, 3943, 3946, 3947, 3948, 3951, 3952, 3953, 3954, 3955, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3977, 3978, 3979, 3981, 3982, 3983, 3984, 3988, 3995, 3996, 3997, 4004, 4005, 4006, 4007, 4008, 4012, 4013, 4015, 4016, 4017, 4019, 4025, 4026, 4027, 4028, 4033, 4034, 4035, 4036, 4037, 4038, 4045, 4046, 4047, 4054, 4055, 4056, 4057, 4065, 4066, 4067, 4068, 4069, 4071, 4072, 4073, 4074, 4075, 4076, 4077, 4085, 4086, 4087, 4088, 4089, 4092, 4098, 4104, 4105, 4106, 4107, 4108, 4109, 4110, 4111, 4112, 4113, 4114, 4115, 4117, 4120, 4121, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4135, 4136, 4141, 4142, 4143, 4148, 4154, 4155, 4156, 4157, 4158, 4159, 4165, 4166, 4167, 4172, 4173, 4174, 4189, 4190, 4191, 4198, 4199, 4202, 4209, 4210, 4211, 4212, 4213, 4214, 4215, 4216, 4217, 4223, 4224, 4230, 4233, 4234, 4235, 4236, 4237, 4238, 4239, 4240, 4241, 4243, 4244, 4252, 4253, 4259, 4260, 4261, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274, 4280, 4282, 4283, 4284, 4285, 4286, 4289, 4290, 4291, 4292, 4293, 4296, 4297, 4299, 4300, 4305, 4306, 4307, 4308, 4315, 4316, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4327, 4328, 4329, 4330, 4331, 4341, 4342, 4343, 4345, 4348, 4350, 4352, 4353, 4354, 4355, 4358, 4359, 4360, 4361, 4363, 4365, 4366, 4367, 4368, 4369, 4370, 4371, 4386, 4387, 4388, 4395, 4396, 4400, 4406, 4407, 4410, 4411, 4412, 4415, 4418, 4419, 4422, 4423, 4424, 4431, 4432, 4433, 4434, 4436, 4439, 4440, 4443, 4444, 4446, 4447, 4448, 4449, 4451, 4454, 4460, 4461, 4462, 4465, 4466, 4467, 4468, 4480, 4481, 4482, 4483, 4485, 4486, 4487, 4488, 4489, 4491, 4492, 4493, 4495, 4496, 4497, 4499, 4500, 4501, 4502, 4503, 4509, 4510, 4511, 4512, 4513, 4526, 4527, 4528, 4529, 4530, 4537, 4538, 4539, 4540, 4543, 4544, 4549, 4550, 4551, 4553, 4554, 4555, 4556, 4558, 4559, 4564, 4565, 4568, 4569, 4570, 4571, 4575, 4576, 4577, 4578, 4581, 4582, 4585, 4587, 4588, 4591, 4593, 4595, 4596, 4597, 4598, 4599, 4602, 4603, 4604, 4606, 4607, 4608, 4610, 4611, 4621, 4624, 4626, 4627, 4628, 4637, 4638, 4639, 4640, 4641, 4644, 4645, 4646, 4650, 4651, 4653, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4674, 4675, 4676, 4679, 4680, 4681, 4682, 4683, 4685, 4686, 4687, 4689, 4692, 4693, 4694, 4695, 4698, 4701, 4702, 4703, 4708, 4709, 4710, 4711, 4712, 4714, 4715, 4716, 4718, 4722, 4723, 4724, 4725, 4727, 4728, 4729, 4730, 4731, 4732, 4738, 4739, 4744, 4745, 4751, 4757, 4758, 4759, 4760], "excluded_lines": [1804, 1805, 1832, 1833, 2221, 2222, 2281, 2282, 2363, 2364, 2426, 2427, 2741, 2742, 2743, 2816, 2817, 2818, 2854, 2855, 2856, 2903, 2904, 2905, 2939, 2940, 2941, 2969, 2970, 2971, 3772, 3773]}, "": {"executed_lines": [3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 52, 53, 60, 66, 67, 68, 69, 75, 76, 77, 78, 79, 81, 94, 95, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 112, 113, 114, 115, 118, 121, 122, 124, 141, 158, 164, 189, 190, 191, 193, 194, 197, 200, 201, 206, 209, 210, 212, 218, 227, 228, 237, 238, 239, 240, 241, 242, 244, 327, 328, 339, 340, 345, 355, 369, 386, 387, 391, 392, 398, 399, 407, 408, 422, 423, 432, 441, 450, 465, 477, 478, 483, 484, 489, 490, 497, 505, 551, 565, 577, 621, 667, 700, 794, 839, 840, 841, 844, 845, 875, 876, 900, 901, 987, 988, 1032, 1071, 1077, 1169, 1170, 1251, 1271, 1292, 1293, 1365, 1395, 1537, 1651, 1654, 1685, 1693, 1722, 1750, 1813, 1816, 1824, 1835, 1861, 1890, 1891, 1894, 1895, 2036, 2037, 2094, 2095, 2164, 2165, 2232, 2233, 2292, 2293, 2374, 2375, 2437, 2464, 2481, 2488, 2511, 2604, 2682, 2745, 3165, 3166, 3200, 3201, 3638, 3639, 3696, 3848, 3849, 3852, 3889, 3890, 3908, 3909, 3986, 3987, 3990, 3991, 4030, 4031, 4059, 4079, 4100, 4145, 4150, 4161, 4176, 4177, 4219, 4220, 4302, 4303, 4373, 4374, 4470, 4515, 4532, 4573, 4648, 4720], "summary": {"covered_lines": 222, "num_statements": 236, "percent_covered": 94.0677966101695, "percent_covered_display": "94", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [160, 161, 174, 175, 176, 177, 180, 182, 183, 185, 186, 202, 203, 204], "excluded_lines": []}}}, "src/seedpass/core/menu_handler.py": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 16, 20, 21, 23, 26, 27, 102, 103], "summary": {"covered_lines": 17, "num_statements": 127, "percent_covered": 13.385826771653543, "percent_covered_display": "13", "missing_lines": 110, "excluded_lines": 8}, "missing_lines": [24, 29, 30, 31, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 55, 56, 58, 59, 62, 63, 64, 66, 67, 73, 74, 75, 82, 83, 84, 85, 86, 88, 89, 92, 93, 94, 95, 96, 97, 105, 106, 107, 108, 115, 116, 117, 118, 119, 122, 123, 124, 125, 127, 128, 129, 131, 133, 134, 135, 136, 137, 138, 139, 141, 142, 143, 144, 151, 152, 153, 154, 155, 156, 157, 158, 163, 164, 165, 166, 167, 170, 174, 177, 178, 179, 180, 181, 186, 187, 188, 189, 190, 193, 197, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209], "excluded_lines": [16, 17, 98, 99, 100, 210, 211, 212], "functions": {"MenuHandler.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [24], "excluded_lines": []}, "MenuHandler.handle_list_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 44, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 44, "excluded_lines": 3}, "missing_lines": [29, 30, 31, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 55, 56, 58, 59, 62, 63, 64, 66, 67, 73, 74, 75, 82, 83, 84, 85, 86, 88, 89, 92, 93, 94, 95, 96, 97], "excluded_lines": [98, 99, 100]}, "MenuHandler.handle_display_totp_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 65, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 65, "excluded_lines": 3}, "missing_lines": [105, 106, 107, 108, 115, 116, 117, 118, 119, 122, 123, 124, 125, 127, 128, 129, 131, 133, 134, 135, 136, 137, 138, 139, 141, 142, 143, 144, 151, 152, 153, 154, 155, 156, 157, 158, 163, 164, 165, 166, 167, 170, 174, 177, 178, 179, 180, 181, 186, 187, 188, 189, 190, 193, 197, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209], "excluded_lines": [210, 211, 212]}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 16, 20, 21, 23, 26, 27, 102, 103], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [16, 17]}}, "classes": {"MenuHandler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 110, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 110, "excluded_lines": 6}, "missing_lines": [24, 29, 30, 31, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 55, 56, 58, 59, 62, 63, 64, 66, 67, 73, 74, 75, 82, 83, 84, 85, 86, 88, 89, 92, 93, 94, 95, 96, 97, 105, 106, 107, 108, 115, 116, 117, 118, 119, 122, 123, 124, 125, 127, 128, 129, 131, 133, 134, 135, 136, 137, 138, 139, 141, 142, 143, 144, 151, 152, 153, 154, 155, 156, 157, 158, 163, 164, 165, 166, 167, 170, 174, 177, 178, 179, 180, 181, 186, 187, 188, 189, 190, 193, 197, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209], "excluded_lines": [98, 99, 100, 210, 211, 212]}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 16, 20, 21, 23, 26, 27, 102, 103], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [16, 17]}}}, "src/seedpass/core/migrations.py": {"executed_lines": [1, 3, 5, 7, 10, 15, 16, 17, 19, 22, 23, 29, 30, 46, 47, 61, 62, 71, 74], "summary": {"covered_lines": 18, "num_statements": 58, "percent_covered": 31.03448275862069, "percent_covered_display": "31", "missing_lines": 40, "excluded_lines": 0}, "missing_lines": [25, 26, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 64, 65, 66, 67, 68, 76, 77, 78, 80, 81, 82, 83, 84, 85, 87], "excluded_lines": [], "functions": {"migration": {"executed_lines": [15, 19], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "migration.decorator": {"executed_lines": [16, 17], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_v0_to_v1": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [25, 26], "excluded_lines": []}, "_v1_to_v2": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43], "excluded_lines": []}, "_v2_to_v3": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [49, 50, 51, 52, 53, 54, 55, 56, 57, 58], "excluded_lines": []}, "_v3_to_v4": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [64, 65, 66, 67, 68], "excluded_lines": []}, "apply_migrations": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [76, 77, 78, 80, 81, 82, 83, 84, 85, 87], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 7, 10, 22, 23, 29, 30, 46, 47, 61, 62, 71, 74], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 7, 10, 15, 16, 17, 19, 22, 23, 29, 30, 46, 47, 61, 62, 71, 74], "summary": {"covered_lines": 18, "num_statements": 58, "percent_covered": 31.03448275862069, "percent_covered_display": "31", "missing_lines": 40, "excluded_lines": 0}, "missing_lines": [25, 26, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 64, 65, 66, 67, 68, 76, 77, 78, 80, 81, 82, 83, 84, 85, 87], "excluded_lines": []}}}, "src/seedpass/core/password_generation.py": {"executed_lines": [3, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 47, 49, 55, 58, 61, 62, 63, 76, 77, 78, 79, 80, 81, 82, 83, 86, 87, 95, 129, 148, 154, 172, 181, 275, 436, 441, 464, 469], "summary": {"covered_lines": 42, "num_statements": 277, "percent_covered": 15.16245487364621, "percent_covered_display": "15", "missing_lines": 235, "excluded_lines": 13}, "missing_lines": [110, 111, 112, 113, 114, 116, 117, 119, 123, 124, 125, 126, 127, 131, 132, 134, 141, 142, 144, 145, 146, 150, 151, 152, 163, 164, 165, 166, 167, 168, 169, 170, 175, 176, 177, 178, 179, 202, 204, 205, 208, 211, 212, 215, 219, 221, 222, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 236, 238, 239, 240, 243, 246, 247, 248, 249, 250, 251, 252, 259, 260, 263, 264, 268, 270, 271, 272, 273, 291, 292, 293, 294, 295, 297, 298, 299, 300, 301, 303, 306, 307, 308, 309, 311, 316, 317, 318, 319, 322, 323, 325, 327, 328, 329, 332, 333, 334, 335, 336, 337, 339, 340, 341, 342, 343, 344, 346, 347, 348, 349, 350, 351, 353, 354, 355, 356, 357, 358, 361, 362, 363, 364, 366, 367, 368, 369, 370, 371, 372, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 404, 405, 406, 411, 414, 415, 420, 421, 422, 423, 424, 428, 430, 431, 432, 433, 438, 444, 445, 446, 448, 449, 455, 456, 461, 466, 480, 481, 482, 490, 497, 498, 499, 500, 501, 502, 504, 505, 507, 509, 512, 513, 514, 524, 525, 526, 527, 528, 529, 530, 531, 532, 534, 535, 536, 538, 539, 542, 543, 544, 545, 548, 550, 551, 552, 554, 555, 556, 557, 558, 559, 571], "excluded_lines": [39, 40, 41, 42, 43, 45, 516, 517, 518, 519, 520, 521, 522], "functions": {"PasswordGenerator.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [110, 111, 112, 113, 114, 116, 117, 119, 123, 124, 125, 126, 127], "excluded_lines": []}, "PasswordGenerator._derive_password_entropy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [131, 132, 134, 141, 142, 144, 145, 146], "excluded_lines": []}, "PasswordGenerator._map_entropy_to_chars": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [150, 151, 152], "excluded_lines": []}, "PasswordGenerator._fisher_yates_hmac": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [163, 164, 165, 166, 167, 168, 169, 170], "excluded_lines": []}, "PasswordGenerator._shuffle_deterministically": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [175, 176, 177, 178, 179], "excluded_lines": []}, "PasswordGenerator.generate_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 0}, "missing_lines": [202, 204, 205, 208, 211, 212, 215, 219, 221, 222, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 236, 238, 239, 240, 243, 246, 247, 248, 249, 250, 251, 252, 259, 260, 263, 264, 268, 270, 271, 272, 273], "excluded_lines": []}, "PasswordGenerator._enforce_complexity": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 98, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 98, "excluded_lines": 0}, "missing_lines": [291, 292, 293, 294, 295, 297, 298, 299, 300, 301, 303, 306, 307, 308, 309, 311, 316, 317, 318, 319, 322, 323, 325, 332, 333, 334, 335, 336, 337, 339, 340, 341, 342, 343, 344, 346, 347, 348, 349, 350, 351, 353, 354, 355, 356, 357, 358, 361, 362, 363, 364, 366, 367, 368, 369, 370, 371, 372, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 404, 405, 406, 411, 414, 415, 420, 421, 422, 423, 424, 428, 430, 431, 432, 433], "excluded_lines": []}, "PasswordGenerator._enforce_complexity.get_dk_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [327, 328, 329], "excluded_lines": []}, "derive_ssh_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [438], "excluded_lines": []}, "derive_ssh_key_pair": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [444, 445, 446, 448, 449, 455, 456, 461], "excluded_lines": []}, "derive_seed_phrase": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [466], "excluded_lines": []}, "derive_pgp_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 44, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 44, "excluded_lines": 1}, "missing_lines": [480, 481, 482, 490, 497, 498, 499, 500, 501, 502, 504, 505, 507, 509, 512, 524, 525, 526, 527, 528, 529, 530, 531, 532, 534, 535, 536, 538, 539, 542, 543, 544, 545, 548, 550, 551, 552, 554, 555, 556, 557, 558, 559, 571], "excluded_lines": [516]}, "derive_pgp_key.DRNG.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [513, 514], "excluded_lines": []}, "derive_pgp_key.DRNG.__call__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [517, 518, 519, 520, 521, 522]}, "": {"executed_lines": [3, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 47, 49, 55, 58, 61, 62, 63, 76, 77, 78, 79, 80, 81, 82, 83, 86, 87, 95, 129, 148, 154, 172, 181, 275, 436, 441, 464, 469], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [39, 40, 41, 42, 43, 45]}}, "classes": {"PasswordPolicy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordGenerator": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 179, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 179, "excluded_lines": 0}, "missing_lines": [110, 111, 112, 113, 114, 116, 117, 119, 123, 124, 125, 126, 127, 131, 132, 134, 141, 142, 144, 145, 146, 150, 151, 152, 163, 164, 165, 166, 167, 168, 169, 170, 175, 176, 177, 178, 179, 202, 204, 205, 208, 211, 212, 215, 219, 221, 222, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 236, 238, 239, 240, 243, 246, 247, 248, 249, 250, 251, 252, 259, 260, 263, 264, 268, 270, 271, 272, 273, 291, 292, 293, 294, 295, 297, 298, 299, 300, 301, 303, 306, 307, 308, 309, 311, 316, 317, 318, 319, 322, 323, 325, 327, 328, 329, 332, 333, 334, 335, 336, 337, 339, 340, 341, 342, 343, 344, 346, 347, 348, 349, 350, 351, 353, 354, 355, 356, 357, 358, 361, 362, 363, 364, 366, 367, 368, 369, 370, 371, 372, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 404, 405, 406, 411, 414, 415, 420, 421, 422, 423, 424, 428, 430, 431, 432, 433], "excluded_lines": []}, "derive_pgp_key.DRNG": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 6}, "missing_lines": [513, 514], "excluded_lines": [517, 518, 519, 520, 521, 522]}, "": {"executed_lines": [3, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 47, 49, 55, 58, 61, 62, 63, 76, 77, 78, 79, 80, 81, 82, 83, 86, 87, 95, 129, 148, 154, 172, 181, 275, 436, 441, 464, 469], "summary": {"covered_lines": 42, "num_statements": 96, "percent_covered": 43.75, "percent_covered_display": "44", "missing_lines": 54, "excluded_lines": 7}, "missing_lines": [438, 444, 445, 446, 448, 449, 455, 456, 461, 466, 480, 481, 482, 490, 497, 498, 499, 500, 501, 502, 504, 505, 507, 509, 512, 524, 525, 526, 527, 528, 529, 530, 531, 532, 534, 535, 536, 538, 539, 542, 543, 544, 545, 548, 550, 551, 552, 554, 555, 556, 557, 558, 559, 571], "excluded_lines": [39, 40, 41, 42, 43, 45, 516]}}}, "src/seedpass/core/portable_backup.py": {"executed_lines": [2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 22, 23, 24, 26, 28, 29, 32, 33, 35, 36, 39, 45, 124], "summary": {"covered_lines": 25, "num_statements": 84, "percent_covered": 29.761904761904763, "percent_covered_display": "30", "missing_lines": 59, "excluded_lines": 0}, "missing_lines": [42, 62, 63, 64, 65, 66, 68, 69, 71, 72, 77, 78, 79, 80, 81, 83, 84, 85, 87, 89, 99, 100, 101, 102, 104, 105, 106, 107, 108, 109, 110, 111, 117, 118, 119, 121, 132, 133, 134, 136, 137, 138, 140, 141, 143, 144, 149, 150, 151, 152, 153, 154, 156, 158, 160, 161, 162, 164, 165], "excluded_lines": [], "functions": {"_derive_export_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [42], "excluded_lines": []}, "export_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 35, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 35, "excluded_lines": 0}, "missing_lines": [62, 63, 64, 65, 66, 68, 69, 71, 72, 77, 78, 79, 80, 81, 83, 84, 85, 87, 89, 99, 100, 101, 102, 104, 105, 106, 107, 108, 109, 110, 111, 117, 118, 119, 121], "excluded_lines": []}, "import_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [132, 133, 134, 136, 137, 138, 140, 141, 143, 144, 149, 150, 151, 152, 153, 154, 156, 158, 160, 161, 162, 164, 165], "excluded_lines": []}, "": {"executed_lines": [2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 22, 23, 24, 26, 28, 29, 32, 33, 35, 36, 39, 45, 124], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"PortableMode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 22, 23, 24, 26, 28, 29, 32, 33, 35, 36, 39, 45, 124], "summary": {"covered_lines": 25, "num_statements": 84, "percent_covered": 29.761904761904763, "percent_covered_display": "30", "missing_lines": 59, "excluded_lines": 0}, "missing_lines": [42, 62, 63, 64, 65, 66, 68, 69, 71, 72, 77, 78, 79, 80, 81, 83, 84, 85, 87, 89, 99, 100, 101, 102, 104, 105, 106, 107, 108, 109, 110, 111, 117, 118, 119, 121, 132, 133, 134, 136, 137, 138, 140, 141, 143, 144, 149, 150, 151, 152, 153, 154, 156, 158, 160, 161, 162, 164, 165], "excluded_lines": []}}}, "src/seedpass/core/profile_service.py": {"executed_lines": [1, 3, 4, 6, 8, 10, 12, 17, 18, 20, 23], "summary": {"covered_lines": 9, "num_statements": 51, "percent_covered": 17.647058823529413, "percent_covered_display": "18", "missing_lines": 42, "excluded_lines": 7}, "missing_lines": [21, 25, 26, 27, 28, 29, 30, 35, 37, 38, 39, 40, 42, 43, 44, 45, 46, 48, 49, 50, 56, 58, 59, 63, 66, 68, 69, 70, 71, 73, 74, 82, 85, 87, 88, 89, 95, 98, 99, 100, 103, 105], "excluded_lines": [12, 13, 14, 106, 107, 108, 109], "functions": {"ProfileService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [21], "excluded_lines": []}, "ProfileService.handle_switch_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 4}, "missing_lines": [25, 26, 27, 28, 29, 30, 35, 37, 38, 39, 40, 42, 43, 44, 45, 46, 48, 49, 50, 56, 58, 59, 63, 66, 68, 69, 70, 71, 73, 74, 82, 85, 87, 88, 89, 95, 98, 99, 100, 103, 105], "excluded_lines": [106, 107, 108, 109]}, "": {"executed_lines": [1, 3, 4, 6, 8, 10, 12, 17, 18, 20, 23], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [12, 13, 14]}}, "classes": {"ProfileService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 42, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 42, "excluded_lines": 4}, "missing_lines": [21, 25, 26, 27, 28, 29, 30, 35, 37, 38, 39, 40, 42, 43, 44, 45, 46, 48, 49, 50, 56, 58, 59, 63, 66, 68, 69, 70, 71, 73, 74, 82, 85, 87, 88, 89, 95, 98, 99, 100, 103, 105], "excluded_lines": [106, 107, 108, 109]}, "": {"executed_lines": [1, 3, 4, 6, 8, 10, 12, 17, 18, 20, 23], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [12, 13, 14]}}}, "src/seedpass/core/pubsub.py": {"executed_lines": [1, 2, 5, 6, 8, 9, 11, 15, 20, 27], "summary": {"covered_lines": 9, "num_statements": 14, "percent_covered": 64.28571428571429, "percent_covered_display": "64", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [13, 17, 18, 22, 23], "excluded_lines": [], "functions": {"PubSub.__init__": {"executed_lines": [9], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PubSub.subscribe": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [13], "excluded_lines": []}, "PubSub.unsubscribe": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [17, 18], "excluded_lines": []}, "PubSub.publish": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [22, 23], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 8, 11, 15, 20, 27], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"PubSub": {"executed_lines": [9], "summary": {"covered_lines": 1, "num_statements": 6, "percent_covered": 16.666666666666668, "percent_covered_display": "17", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [13, 17, 18, 22, 23], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 8, 11, 15, 20, 27], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/seedqr.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [3, 5, 6, 9, 11, 12, 13, 14], "excluded_lines": [], "functions": {"encode_seedqr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [11, 12, 13, 14], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [3, 5, 6, 9], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [3, 5, 6, 9, 11, 12, 13, 14], "excluded_lines": []}}}, "src/seedpass/core/state_manager.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 12, 13, 15, 17, 21, 55, 63, 64, 67, 73, 76, 85], "summary": {"covered_lines": 18, "num_statements": 65, "percent_covered": 27.692307692307693, "percent_covered_display": "28", "missing_lines": 47, "excluded_lines": 0}, "missing_lines": [18, 19, 22, 23, 31, 32, 33, 34, 35, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 56, 57, 58, 59, 60, 61, 65, 68, 69, 70, 74, 77, 78, 79, 80, 81, 82, 83, 86, 87, 88, 89, 90, 91, 92, 93, 94], "excluded_lines": [], "functions": {"StateManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [18, 19], "excluded_lines": []}, "StateManager._load": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [22, 23, 31, 32, 33, 34, 35, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53], "excluded_lines": []}, "StateManager._save": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [56, 57, 58, 59, 60, 61], "excluded_lines": []}, "StateManager.state": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [65], "excluded_lines": []}, "StateManager.update_state": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [68, 69, 70], "excluded_lines": []}, "StateManager.list_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [74], "excluded_lines": []}, "StateManager.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [77, 78, 79, 80, 81, 82, 83], "excluded_lines": []}, "StateManager.remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [86, 87, 88, 89, 90, 91, 92, 93, 94], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 12, 13, 15, 17, 21, 55, 63, 64, 67, 73, 76, 85], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"StateManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 47, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 47, "excluded_lines": 0}, "missing_lines": [18, 19, 22, 23, 31, 32, 33, 34, 35, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 56, 57, 58, 59, 60, 61, 65, 68, 69, 70, 74, 77, 78, 79, 80, 81, 82, 83, 86, 87, 88, 89, 90, 91, 92, 93, 94], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 12, 13, 15, 17, 21, 55, 63, 64, 67, 73, 76, 85], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/stats_manager.py": {"executed_lines": [1, 3, 6, 7, 9, 12, 18], "summary": {"covered_lines": 5, "num_statements": 10, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [10, 14, 15, 16, 20], "excluded_lines": [], "functions": {"StatsManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [10], "excluded_lines": []}, "StatsManager.display_stats_once": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [14, 15, 16], "excluded_lines": []}, "StatsManager.reset": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [20], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 9, 12, 18], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"StatsManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [10, 14, 15, 16, 20], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 9, 12, 18], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/totp.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 20, 25, 26, 28, 29, 33, 34, 44, 45, 50, 51, 65, 66, 73, 74, 80, 81, 97, 98], "summary": {"covered_lines": 29, "num_statements": 71, "percent_covered": 40.84507042253521, "percent_covered_display": "41", "missing_lines": 42, "excluded_lines": 0}, "missing_lines": [22, 31, 38, 39, 40, 41, 42, 47, 48, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 70, 71, 76, 77, 78, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 100, 101, 102, 103], "excluded_lines": [], "functions": {"random_totp_secret": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": []}, "TotpManager.derive_secret": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [31], "excluded_lines": []}, "TotpManager.current_code": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [38, 39, 40, 41, 42], "excluded_lines": []}, "TotpManager.current_code_from_secret": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [47, 48], "excluded_lines": []}, "TotpManager.parse_otpauth": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63], "excluded_lines": []}, "TotpManager.make_otpauth_uri": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [70, 71], "excluded_lines": []}, "TotpManager.time_remaining": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [76, 77, 78], "excluded_lines": []}, "TotpManager.print_progress_bar": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95], "excluded_lines": []}, "TotpManager.print_qr_code": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [100, 101, 102, 103], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 20, 25, 26, 28, 29, 33, 34, 44, 45, 50, 51, 65, 66, 73, 74, 80, 81, 97, 98], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"TotpManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 0}, "missing_lines": [31, 38, 39, 40, 41, 42, 47, 48, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 70, 71, 76, 77, 78, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 100, 101, 102, 103], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 20, 25, 26, 28, 29, 33, 34, 44, 45, 50, 51, 65, 66, 73, 74, 80, 81, 97, 98], "summary": {"covered_lines": 29, "num_statements": 30, "percent_covered": 96.66666666666667, "percent_covered_display": "97", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": []}}}, "src/seedpass/core/vault.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 17, 18, 21, 22, 24, 25, 27, 38, 42, 48, 239, 245, 249, 275, 279], "summary": {"covered_lines": 21, "num_statements": 140, "percent_covered": 15.0, "percent_covered_display": "15", "missing_lines": 119, "excluded_lines": 0}, "missing_lines": [32, 33, 34, 35, 36, 40, 43, 63, 64, 65, 66, 67, 68, 69, 74, 75, 77, 80, 81, 82, 83, 84, 86, 87, 88, 93, 94, 95, 96, 97, 98, 99, 100, 102, 103, 110, 111, 114, 117, 118, 124, 127, 128, 129, 130, 136, 142, 143, 144, 145, 146, 147, 149, 152, 155, 156, 157, 160, 161, 163, 164, 165, 168, 169, 172, 173, 174, 175, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 191, 192, 194, 196, 197, 198, 201, 203, 204, 205, 206, 209, 210, 211, 212, 213, 216, 217, 218, 219, 220, 221, 224, 225, 226, 227, 229, 230, 232, 235, 236, 237, 241, 247, 264, 267, 270, 271, 272, 277, 281], "excluded_lines": [], "functions": {"Vault.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [32, 33, 34, 35, 36], "excluded_lines": []}, "Vault.set_encryption_manager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [40], "excluded_lines": []}, "Vault._hkdf_kdf": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [43], "excluded_lines": []}, "Vault.load_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 103, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 103, "excluded_lines": 0}, "missing_lines": [63, 64, 65, 66, 67, 68, 69, 74, 75, 77, 80, 81, 82, 83, 84, 86, 87, 88, 93, 94, 95, 96, 97, 98, 99, 100, 102, 103, 110, 111, 114, 117, 118, 124, 127, 128, 129, 130, 136, 142, 143, 144, 145, 146, 147, 149, 152, 155, 156, 157, 160, 161, 163, 164, 165, 168, 169, 172, 173, 174, 175, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 191, 192, 194, 196, 197, 198, 201, 203, 204, 205, 206, 209, 210, 211, 212, 213, 216, 217, 218, 219, 220, 221, 224, 225, 226, 227, 229, 230, 232, 235, 236, 237], "excluded_lines": []}, "Vault.save_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [241], "excluded_lines": []}, "Vault.get_encrypted_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [247], "excluded_lines": []}, "Vault.decrypt_and_save_index_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [264, 267, 270, 271, 272], "excluded_lines": []}, "Vault.load_config": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [277], "excluded_lines": []}, "Vault.save_config": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [281], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 17, 18, 21, 22, 24, 25, 27, 38, 42, 48, 239, 245, 249, 275, 279], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"Vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 119, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 119, "excluded_lines": 0}, "missing_lines": [32, 33, 34, 35, 36, 40, 43, 63, 64, 65, 66, 67, 68, 69, 74, 75, 77, 80, 81, 82, 83, 84, 86, 87, 88, 93, 94, 95, 96, 97, 98, 99, 100, 102, 103, 110, 111, 114, 117, 118, 124, 127, 128, 129, 130, 136, 142, 143, 144, 145, 146, 147, 149, 152, 155, 156, 157, 160, 161, 163, 164, 165, 168, 169, 172, 173, 174, 175, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 191, 192, 194, 196, 197, 198, 201, 203, 204, 205, 206, 209, 210, 211, 212, 213, 216, 217, 218, 219, 220, 221, 224, 225, 226, 227, 229, 230, 232, 235, 236, 237, 241, 247, 264, 267, 270, 271, 272, 277, 281], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 17, 18, 21, 22, 24, 25, 27, 38, 42, 48, 239, 245, 249, 275, 279], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/errors.py": {"executed_lines": [1, 3, 6, 7, 9, 13], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [10], "excluded_lines": [], "functions": {"VaultLockedError.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [10], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 9, 13], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"VaultLockedError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [10], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 9, 13], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass_gui/__init__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [3, 6, 8, 11], "excluded_lines": [], "functions": {"main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [8], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [3, 6, 11], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [3, 6, 8, 11], "excluded_lines": []}}}, "src/seedpass_gui/__main__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1, 3, 4], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1, 3, 4], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1, 3, 4], "excluded_lines": []}}}, "src/seedpass_gui/app.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 303, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 303, "excluded_lines": 24}, "missing_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 21, 24, 27, 33, 36, 37, 38, 40, 41, 42, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 60, 66, 67, 68, 71, 74, 81, 84, 85, 86, 87, 88, 89, 90, 91, 93, 94, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 115, 117, 118, 119, 120, 121, 123, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 150, 151, 152, 154, 155, 156, 157, 158, 159, 161, 162, 163, 165, 166, 167, 169, 170, 171, 173, 176, 177, 179, 182, 183, 185, 186, 187, 189, 190, 191, 192, 194, 195, 196, 197, 198, 199, 200, 203, 206, 207, 208, 209, 210, 212, 213, 217, 218, 219, 220, 223, 224, 226, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 261, 262, 263, 264, 265, 266, 267, 268, 270, 271, 272, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 289, 290, 292, 293, 294, 295, 296, 297, 298, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 312, 320, 321, 323, 324, 325, 326, 327, 329, 331, 334, 337, 338, 339, 340, 341, 344, 345, 346, 347, 348, 350, 351, 352, 353, 354, 355, 364, 367, 370, 371, 372, 373, 375, 380, 381, 382, 384, 385, 386, 388, 389, 390, 391, 393, 394, 395, 398, 399, 400, 401, 402, 404, 405, 408, 411, 412, 413, 414, 416, 417, 418, 419, 420, 422, 423, 424, 425, 426, 427, 428, 429, 430, 432, 434, 435, 436, 437, 439, 440, 441, 442, 443, 444, 448, 449, 451, 452, 453, 454, 455, 456, 457, 461, 464, 466, 469], "excluded_lines": [57, 58, 59, 445, 446, 447, 458, 459, 460, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 484, 485, 486], "functions": {"LockScreenWindow.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [33, 36, 37, 38, 40, 41, 42, 46, 47, 48, 49, 50, 51], "excluded_lines": []}, "LockScreenWindow.handle_unlock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 3}, "missing_lines": [54, 55, 56, 60, 66, 67, 68], "excluded_lines": [57, 58, 59]}, "MainWindow.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 31, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 31, "excluded_lines": 0}, "missing_lines": [81, 84, 85, 86, 87, 88, 89, 90, 91, 93, 94, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 115, 117, 118, 119, 120, 121, 123], "excluded_lines": []}, "MainWindow.refresh_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139], "excluded_lines": []}, "MainWindow.add_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [151, 152], "excluded_lines": []}, "MainWindow.edit_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [155, 156, 157, 158, 159], "excluded_lines": []}, "MainWindow.search_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [162, 163], "excluded_lines": []}, "MainWindow.manage_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [166, 167], "excluded_lines": []}, "MainWindow.show_totp_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [170, 171], "excluded_lines": []}, "MainWindow.start_vault_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [176, 179], "excluded_lines": []}, "MainWindow.start_vault_sync._runner": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [177], "excluded_lines": []}, "MainWindow.sync_started": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [183], "excluded_lines": []}, "MainWindow.sync_finished": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [186, 187], "excluded_lines": []}, "MainWindow.vault_locked": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [190, 191, 192], "excluded_lines": []}, "MainWindow.cleanup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [195, 196, 197, 198, 199, 200], "excluded_lines": []}, "EntryDialog.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 42, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 42, "excluded_lines": 0}, "missing_lines": [207, 208, 209, 210, 212, 213, 217, 218, 219, 220, 223, 224, 226, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259], "excluded_lines": []}, "EntryDialog.save": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 51, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 51, "excluded_lines": 0}, "missing_lines": [262, 263, 264, 265, 266, 267, 268, 270, 271, 272, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 289, 290, 292, 293, 294, 295, 296, 297, 298, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 312, 320, 321, 323, 324, 325, 326, 327, 329, 331], "excluded_lines": []}, "SearchDialog.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [338, 339, 340, 341, 344, 345, 346, 347, 348], "excluded_lines": []}, "SearchDialog.do_search": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [351, 352, 353, 354, 355, 364], "excluded_lines": []}, "TotpViewerWindow.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [371, 372, 373, 375, 380, 381, 382, 384, 385, 386], "excluded_lines": []}, "TotpViewerWindow._update_loop": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [389, 390, 391], "excluded_lines": []}, "TotpViewerWindow.refresh_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [394, 395, 398, 399, 400, 401, 402], "excluded_lines": []}, "TotpViewerWindow.cleanup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [405], "excluded_lines": []}, "RelayManagerDialog.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [412, 413, 414, 416, 417, 418, 419, 420, 422, 423, 424, 425, 426, 427, 428, 429, 430, 432], "excluded_lines": []}, "RelayManagerDialog.refresh": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [435, 436, 437], "excluded_lines": []}, "RelayManagerDialog.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 3}, "missing_lines": [440, 441, 442, 443, 444, 448, 449], "excluded_lines": [445, 446, 447]}, "RelayManagerDialog.remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 3}, "missing_lines": [452, 453, 454, 455, 456, 457, 461], "excluded_lines": [458, 459, 460]}, "build": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [466], "excluded_lines": []}, "SeedPassApp.startup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 11}, "missing_lines": [], "excluded_lines": [471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481]}, "main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [485, 486]}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 46, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 46, "excluded_lines": 2}, "missing_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 21, 24, 27, 53, 71, 74, 125, 150, 154, 161, 165, 169, 173, 182, 185, 189, 194, 203, 206, 261, 334, 337, 350, 367, 370, 388, 393, 404, 408, 411, 434, 439, 451, 464, 469], "excluded_lines": [470, 484]}}, "classes": {"LockScreenWindow": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 3}, "missing_lines": [33, 36, 37, 38, 40, 41, 42, 46, 47, 48, 49, 50, 51, 54, 55, 56, 60, 66, 67, 68], "excluded_lines": [57, 58, 59]}, "MainWindow": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 72, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 72, "excluded_lines": 0}, "missing_lines": [81, 84, 85, 86, 87, 88, 89, 90, 91, 93, 94, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 115, 117, 118, 119, 120, 121, 123, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 151, 152, 155, 156, 157, 158, 159, 162, 163, 166, 167, 170, 171, 176, 177, 179, 183, 186, 187, 190, 191, 192, 195, 196, 197, 198, 199, 200], "excluded_lines": []}, "EntryDialog": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 93, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 93, "excluded_lines": 0}, "missing_lines": [207, 208, 209, 210, 212, 213, 217, 218, 219, 220, 223, 224, 226, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 262, 263, 264, 265, 266, 267, 268, 270, 271, 272, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 289, 290, 292, 293, 294, 295, 296, 297, 298, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 312, 320, 321, 323, 324, 325, 326, 327, 329, 331], "excluded_lines": []}, "SearchDialog": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [338, 339, 340, 341, 344, 345, 346, 347, 348, 351, 352, 353, 354, 355, 364], "excluded_lines": []}, "TotpViewerWindow": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [371, 372, 373, 375, 380, 381, 382, 384, 385, 386, 389, 390, 391, 394, 395, 398, 399, 400, 401, 402, 405], "excluded_lines": []}, "RelayManagerDialog": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 35, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 35, "excluded_lines": 6}, "missing_lines": [412, 413, 414, 416, 417, 418, 419, 420, 422, 423, 424, 425, 426, 427, 428, 429, 430, 432, 435, 436, 437, 440, 441, 442, 443, 444, 448, 449, 452, 453, 454, 455, 456, 457, 461], "excluded_lines": [445, 446, 447, 458, 459, 460]}, "SeedPassApp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 11}, "missing_lines": [], "excluded_lines": [471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481]}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 47, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 47, "excluded_lines": 4}, "missing_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 21, 24, 27, 53, 71, 74, 125, 150, 154, 161, 165, 169, 173, 182, 185, 189, 194, 203, 206, 261, 334, 337, 350, 367, 370, 388, 393, 404, 408, 411, 434, 439, 451, 464, 466, 469], "excluded_lines": [470, 484, 485, 486]}}}, "src/tests/conftest.py": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 14, 15, 26, 27, 28, 29, 30, 33, 36, 40, 41, 42, 45, 46, 52, 58, 66, 67, 68, 71, 74, 77, 78, 79, 82, 83, 84, 85, 89, 90, 95, 96, 115, 116, 153, 154, 194, 195], "summary": {"covered_lines": 48, "num_statements": 105, "percent_covered": 45.714285714285715, "percent_covered_display": "46", "missing_lines": 57, "excluded_lines": 0}, "missing_lines": [37, 75, 80, 86, 91, 92, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 117, 145, 146, 147, 148, 149, 150, 156, 157, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 172, 174, 175, 176, 178, 179, 181, 182, 183, 185, 186, 187, 188, 189, 191, 196], "excluded_lines": [], "functions": {"anyio_backend": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [37], "excluded_lines": []}, "mute_logging": {"executed_lines": [42], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pytest_addoption": {"executed_lines": [46, 52, 58], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pytest_configure": {"executed_lines": [67, 68], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pytest_collection_modifyitems": {"executed_lines": [74, 77, 78, 79, 82, 83, 84, 85], "summary": {"covered_lines": 8, "num_statements": 11, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [75, 80, 86], "excluded_lines": []}, "vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [91, 92], "excluded_lines": []}, "password_manager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112], "excluded_lines": []}, "client": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [117, 145, 146, 147, 148, 149, 150], "excluded_lines": []}, "make_dummy_nostr_client": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [156, 157, 159, 191], "excluded_lines": []}, "make_dummy_nostr_client._make": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 172, 174, 175, 178, 181, 182, 185, 186, 187, 188, 189], "excluded_lines": []}, "make_dummy_nostr_client._make.DummyKeys.private_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [176], "excluded_lines": []}, "make_dummy_nostr_client._make.DummyKeys.public_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [179], "excluded_lines": []}, "make_dummy_nostr_client._make.DummyKeyManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [183], "excluded_lines": []}, "dummy_nostr_client": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [196], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 14, 15, 26, 27, 28, 29, 30, 33, 36, 40, 41, 45, 66, 71, 89, 90, 95, 96, 115, 116, 153, 154, 194, 195], "summary": {"covered_lines": 34, "num_statements": 34, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"make_dummy_nostr_client._make.DummyKeys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [176, 179], "excluded_lines": []}, "make_dummy_nostr_client._make.DummyKeyManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [183], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 14, 15, 26, 27, 28, 29, 30, 33, 36, 40, 41, 42, 45, 46, 52, 58, 66, 67, 68, 71, 74, 77, 78, 79, 82, 83, 84, 85, 89, 90, 95, 96, 115, 116, 153, 154, 194, 195], "summary": {"covered_lines": 48, "num_statements": 102, "percent_covered": 47.05882352941177, "percent_covered_display": "47", "missing_lines": 54, "excluded_lines": 0}, "missing_lines": [37, 75, 80, 86, 91, 92, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 117, 145, 146, 147, 148, 149, 150, 156, 157, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 172, 174, 175, 178, 181, 182, 185, 186, 187, 188, 189, 191, 196], "excluded_lines": []}}}, "src/tests/helpers.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 11, 12, 18, 22, 25, 42, 43, 49, 53, 54, 59, 63, 64, 74, 79, 83, 84, 85, 88, 89, 92, 93, 96, 97, 101, 102, 109, 112, 121, 125, 130, 134, 139, 140, 143, 144, 148, 149, 152, 155, 156, 160, 161, 165, 166, 174, 177, 180, 183, 186, 209], "summary": {"covered_lines": 57, "num_statements": 167, "percent_covered": 34.131736526946106, "percent_covered_display": "34", "missing_lines": 110, "excluded_lines": 0}, "missing_lines": [31, 32, 33, 34, 36, 37, 38, 39, 44, 45, 46, 47, 50, 55, 56, 57, 60, 65, 66, 67, 68, 70, 71, 72, 76, 77, 80, 86, 90, 94, 98, 103, 104, 105, 106, 107, 110, 113, 114, 115, 116, 118, 119, 122, 123, 126, 127, 128, 131, 132, 135, 136, 141, 145, 150, 153, 157, 162, 167, 168, 169, 170, 171, 172, 175, 178, 181, 184, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 226, 227, 228, 230, 231, 233], "excluded_lines": [], "functions": {"create_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [31, 32, 33, 34, 36, 37, 38, 39], "excluded_lines": []}, "DummyEvent.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [44, 45, 46, 47], "excluded_lines": []}, "DummyEvent.content": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [50], "excluded_lines": []}, "DummyUnsignedEvent.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [55, 56, 57], "excluded_lines": []}, "DummyUnsignedEvent.sign_with_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [60], "excluded_lines": []}, "DummyBuilder.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [65, 66, 67, 68, 70, 71, 72], "excluded_lines": []}, "DummyBuilder.tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [76, 77], "excluded_lines": []}, "DummyBuilder.build": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [80], "excluded_lines": []}, "DummyTag.identifier": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [86], "excluded_lines": []}, "DummyTag.event": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [90], "excluded_lines": []}, "DummyTag.alt": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [94], "excluded_lines": []}, "DummyTag.expiration": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [98], "excluded_lines": []}, "DummyFilter.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [103, 104, 105, 106, 107], "excluded_lines": []}, "DummyFilter.author": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [110], "excluded_lines": []}, "DummyFilter.kind": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [113, 114, 115, 116, 118, 119], "excluded_lines": []}, "DummyFilter.identifier": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [122, 123], "excluded_lines": []}, "DummyFilter.id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [126, 127, 128], "excluded_lines": []}, "DummyFilter.limit": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [131, 132], "excluded_lines": []}, "DummyFilter.since": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [135, 136], "excluded_lines": []}, "DummyTimestamp.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [141], "excluded_lines": []}, "DummyTimestamp.from_secs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [145], "excluded_lines": []}, "DummyEventId.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [150], "excluded_lines": []}, "DummyEventId.to_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [153], "excluded_lines": []}, "DummyEventId.parse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [157], "excluded_lines": []}, "DummySendResult.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [162], "excluded_lines": []}, "DummyRelayClient.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [167, 168, 169, 170, 171, 172], "excluded_lines": []}, "DummyRelayClient.add_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [175], "excluded_lines": []}, "DummyRelayClient.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [178], "excluded_lines": []}, "DummyRelayClient.connect": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [181], "excluded_lines": []}, "DummyRelayClient.disconnect": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [184], "excluded_lines": []}, "DummyRelayClient.send_event": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207], "excluded_lines": []}, "DummyRelayClient.fetch_events": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 226, 227, 230, 233], "excluded_lines": []}, "DummyRelayClient.fetch_events.Result.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [228], "excluded_lines": []}, "DummyRelayClient.fetch_events.Result.to_vec": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [231], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 11, 12, 18, 22, 25, 42, 43, 49, 53, 54, 59, 63, 64, 74, 79, 83, 84, 85, 88, 89, 92, 93, 96, 97, 101, 102, 109, 112, 121, 125, 130, 134, 139, 140, 143, 144, 148, 149, 152, 155, 156, 160, 161, 165, 166, 174, 177, 180, 183, 186, 209], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEvent": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [44, 45, 46, 47, 50], "excluded_lines": []}, "DummyUnsignedEvent": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [55, 56, 57, 60], "excluded_lines": []}, "DummyBuilder": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [65, 66, 67, 68, 70, 71, 72, 76, 77, 80], "excluded_lines": []}, "DummyTag": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [86, 90, 94, 98], "excluded_lines": []}, "DummyFilter": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [103, 104, 105, 106, 107, 110, 113, 114, 115, 116, 118, 119, 122, 123, 126, 127, 128, 131, 132, 135, 136], "excluded_lines": []}, "DummyTimestamp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [141, 145], "excluded_lines": []}, "DummyEventId": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [150, 153, 157], "excluded_lines": []}, "DummySendResult": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [162], "excluded_lines": []}, "DummyRelayClient": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 50, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 50, "excluded_lines": 0}, "missing_lines": [167, 168, 169, 170, 171, 172, 175, 178, 181, 184, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 226, 227, 230, 233], "excluded_lines": []}, "DummyRelayClient.fetch_events.Result": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [228, 231], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 11, 12, 18, 22, 25, 42, 43, 49, 53, 54, 59, 63, 64, 74, 79, 83, 84, 85, 88, 89, 92, 93, 96, 97, 101, 102, 109, 112, 121, 125, 130, 134, 139, 140, 143, 144, 148, 149, 152, 155, 156, 160, 161, 165, 166, 174, 177, 180, 183, 186, 209], "summary": {"covered_lines": 57, "num_statements": 65, "percent_covered": 87.6923076923077, "percent_covered_display": "88", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [31, 32, 33, 34, 36, 37, 38, 39], "excluded_lines": []}}}, "src/tests/test_background_vault_sync_paths.py": {"executed_lines": [1, 3, 4, 7, 8, 9, 11, 13, 14, 16, 17, 21, 22, 23, 24, 26, 27, 29, 31, 33, 34, 37, 38, 39, 41, 43, 44, 46, 47, 51, 52, 53, 55, 57, 58], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"test_start_background_vault_sync_thread_worker_path": {"executed_lines": [8, 9, 11, 13, 16, 17, 21, 22, 26, 29, 31, 33, 34], "summary": {"covered_lines": 13, "num_statements": 13, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_vault_sync_thread_worker_path.fake_sync_vault_async": {"executed_lines": [14], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_vault_sync_thread_worker_path.ImmediateThread.__init__": {"executed_lines": [23, 24], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_vault_sync_thread_worker_path.ImmediateThread.start": {"executed_lines": [27], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_vault_sync_async_worker_path": {"executed_lines": [38, 39, 41, 43, 46, 47, 51, 55, 57, 58], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_vault_sync_async_worker_path.fake_sync_vault_async": {"executed_lines": [44], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_start_background_vault_sync_async_worker_path.runner": {"executed_lines": [52, 53], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 7, 37], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_start_background_vault_sync_thread_worker_path.ImmediateThread": {"executed_lines": [23, 24, 27], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 7, 8, 9, 11, 13, 14, 16, 17, 21, 22, 26, 29, 31, 33, 34, 37, 38, 39, 41, 43, 44, 46, 47, 51, 52, 53, 55, 57, 58], "summary": {"covered_lines": 32, "num_statements": 32, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/utils/__init__.py": {"executed_lines": [3, 5, 7, 9, 10, 19, 27, 28, 29, 30, 31, 37, 40, 41, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 10}, "missing_lines": [], "excluded_lines": [40, 41, 42, 43, 45, 46, 48, 49, 50, 51], "functions": {"": {"executed_lines": [3, 5, 7, 9, 10, 19, 27, 28, 29, 30, 31, 37, 40, 41, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 10}, "missing_lines": [], "excluded_lines": [40, 41, 42, 43, 45, 46, 48, 49, 50, 51]}}, "classes": {"": {"executed_lines": [3, 5, 7, 9, 10, 19, 27, 28, 29, 30, 31, 37, 40, 41, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 10}, "missing_lines": [], "excluded_lines": [40, 41, 42, 43, 45, 46, 48, 49, 50, 51]}}}, "src/utils/atomic_write.py": {"executed_lines": [1, 14, 16, 17, 18, 19, 22, 62], "summary": {"covered_lines": 7, "num_statements": 22, "percent_covered": 31.818181818181817, "percent_covered_display": "32", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [44, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59], "excluded_lines": [], "functions": {"atomic_write": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [44, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59], "excluded_lines": []}, "": {"executed_lines": [1, 14, 16, 17, 18, 19, 22, 62], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 14, 16, 17, 18, 19, 22, 62], "summary": {"covered_lines": 7, "num_statements": 22, "percent_covered": 31.818181818181817, "percent_covered_display": "32", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [44, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59], "excluded_lines": []}}}, "src/utils/checksum.py": {"executed_lines": [3, 13, 14, 15, 16, 17, 18, 20, 22, 23, 26, 29, 34, 40, 78, 109, 140, 165, 201], "summary": {"covered_lines": 18, "num_statements": 95, "percent_covered": 18.94736842105263, "percent_covered_display": "19", "missing_lines": 77, "excluded_lines": 0}, "missing_lines": [31, 36, 37, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 65, 66, 67, 70, 75, 89, 90, 91, 92, 93, 94, 95, 96, 99, 101, 102, 103, 105, 106, 120, 121, 122, 123, 124, 125, 126, 127, 128, 131, 137, 151, 152, 153, 155, 156, 157, 158, 160, 161, 162, 176, 177, 178, 180, 181, 182, 185, 186, 187, 188, 192, 198, 203, 204, 205, 206, 207, 208, 211, 212, 213, 217, 223], "excluded_lines": [], "functions": {"canonical_json_dumps": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [31], "excluded_lines": []}, "json_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [36, 37], "excluded_lines": []}, "calculate_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 65, 66, 67, 70, 75], "excluded_lines": []}, "verify_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [89, 90, 91, 92, 93, 94, 95, 96, 99, 101, 102, 103, 105, 106], "excluded_lines": []}, "update_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [120, 121, 122, 123, 124, 125, 126, 127, 128, 131, 137], "excluded_lines": []}, "verify_and_update_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [151, 152, 153, 155, 156, 157, 158, 160, 161, 162], "excluded_lines": []}, "initialize_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [176, 177, 178, 180, 181, 182, 185, 186, 187, 188, 192, 198], "excluded_lines": []}, "update_checksum_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [203, 204, 205, 206, 207, 208, 211, 212, 213, 217, 223], "excluded_lines": []}, "": {"executed_lines": [3, 13, 14, 15, 16, 17, 18, 20, 22, 23, 26, 29, 34, 40, 78, 109, 140, 165, 201], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 13, 14, 15, 16, 17, 18, 20, 22, 23, 26, 29, 34, 40, 78, 109, 140, 165, 201], "summary": {"covered_lines": 18, "num_statements": 95, "percent_covered": 18.94736842105263, "percent_covered_display": "19", "missing_lines": 77, "excluded_lines": 0}, "missing_lines": [31, 36, 37, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 65, 66, 67, 70, 75, 89, 90, 91, 92, 93, 94, 95, 96, 99, 101, 102, 103, 105, 106, 120, 121, 122, 123, 124, 125, 126, 127, 128, 131, 137, 151, 152, 153, 155, 156, 157, 158, 160, 161, 162, 176, 177, 178, 180, 181, 182, 185, 186, 187, 188, 192, 198, 203, 204, 205, 206, 207, 208, 211, 212, 213, 217, 223], "excluded_lines": []}}}, "src/utils/clipboard.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 11, 12, 15, 18, 35, 52], "summary": {"covered_lines": 10, "num_statements": 26, "percent_covered": 38.46153846153846, "percent_covered_display": "38", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [20, 21, 22, 23, 24, 25, 29, 38, 40, 42, 43, 44, 46, 47, 48, 49], "excluded_lines": [], "functions": {"_ensure_clipboard": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [20, 21, 22, 23, 24, 25, 29], "excluded_lines": []}, "copy_to_clipboard": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [38, 40, 42, 46, 47, 48, 49], "excluded_lines": []}, "copy_to_clipboard.clear_clipboard": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [43, 44], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 11, 12, 15, 18, 35, 52], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"ClipboardUnavailableError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 11, 12, 15, 18, 35, 52], "summary": {"covered_lines": 10, "num_statements": 26, "percent_covered": 38.46153846153846, "percent_covered_display": "38", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [20, 21, 22, 23, 24, 25, 29, 38, 40, 42, 43, 44, 46, 47, 48, 49], "excluded_lines": []}}}, "src/utils/color_scheme.py": {"executed_lines": [1, 3, 6, 7, 10, 16, 29], "summary": {"covered_lines": 6, "num_statements": 12, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [12, 31, 32, 33, 34, 35], "excluded_lines": [], "functions": {"_apply_orange": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [12], "excluded_lines": []}, "color_text": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [31, 32, 33, 34, 35], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 10, 16, 29], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 6, 7, 10, 16, 29], "summary": {"covered_lines": 6, "num_statements": 12, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [12, 31, 32, 33, 34, 35], "excluded_lines": []}}}, "src/utils/file_lock.py": {"executed_lines": [1, 3, 4, 5, 6, 7, 10, 11, 42, 43], "summary": {"covered_lines": 9, "num_statements": 27, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [21, 22, 23, 24, 25, 26, 32, 38, 39, 53, 54, 55, 56, 57, 63, 69, 70, 71], "excluded_lines": [], "functions": {"exclusive_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [21, 22, 23, 24, 25, 26, 32, 38, 39], "excluded_lines": []}, "shared_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [53, 54, 55, 56, 57, 63, 69, 70, 71], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 7, 10, 11, 42, 43], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 6, 7, 10, 11, 42, 43], "summary": {"covered_lines": 9, "num_statements": 27, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [21, 22, 23, 24, 25, 26, 32, 38, 39, 53, 54, 55, 56, 57, 63, 69, 70, 71], "excluded_lines": []}}}, "src/utils/fingerprint.py": {"executed_lines": [3, 11, 12, 13, 16, 19], "summary": {"covered_lines": 5, "num_statements": 16, "percent_covered": 31.25, "percent_covered_display": "31", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [30, 32, 33, 36, 37, 40, 41, 43, 44, 45, 46], "excluded_lines": [], "functions": {"generate_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [30, 32, 33, 36, 37, 40, 41, 43, 44, 45, 46], "excluded_lines": []}, "": {"executed_lines": [3, 11, 12, 13, 16, 19], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 11, 12, 13, 16, 19], "summary": {"covered_lines": 5, "num_statements": 16, "percent_covered": 31.25, "percent_covered_display": "31", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [30, 32, 33, 36, 37, 40, 41, 43, 44, 45, 46], "excluded_lines": []}}}, "src/utils/fingerprint_manager.py": {"executed_lines": [3, 4, 5, 6, 7, 9, 11, 12, 15, 18, 19, 27, 43, 56, 69, 90, 111, 141, 185, 195, 214, 225, 229, 234], "summary": {"covered_lines": 23, "num_statements": 122, "percent_covered": 18.852459016393443, "percent_covered_display": "19", "missing_lines": 99, "excluded_lines": 0}, "missing_lines": [34, 35, 36, 37, 50, 51, 53, 54, 60, 61, 62, 63, 64, 67, 71, 72, 73, 74, 75, 76, 77, 78, 81, 82, 85, 86, 87, 88, 94, 95, 100, 104, 107, 108, 109, 122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 138, 139, 154, 155, 156, 157, 158, 159, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 180, 182, 183, 192, 193, 205, 206, 207, 208, 209, 211, 212, 216, 217, 218, 219, 221, 222, 223, 227, 231, 232, 244, 245, 246, 248, 249], "excluded_lines": [], "functions": {"FingerprintManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [34, 35, 36, 37], "excluded_lines": []}, "FingerprintManager.get_current_fingerprint_dir": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [50, 51, 53, 54], "excluded_lines": []}, "FingerprintManager._ensure_app_directory": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [60, 61, 62, 63, 64, 67], "excluded_lines": []}, "FingerprintManager._load_fingerprints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [71, 72, 73, 74, 75, 76, 77, 78, 81, 82, 85, 86, 87, 88], "excluded_lines": []}, "FingerprintManager._save_fingerprints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [94, 95, 100, 104, 107, 108, 109], "excluded_lines": []}, "FingerprintManager.add_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 138, 139], "excluded_lines": []}, "FingerprintManager.remove_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 24, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 24, "excluded_lines": 0}, "missing_lines": [154, 155, 156, 157, 158, 159, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 180, 182, 183], "excluded_lines": []}, "FingerprintManager.list_fingerprints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [192, 193], "excluded_lines": []}, "FingerprintManager.select_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [205, 206, 207, 208, 209, 211, 212], "excluded_lines": []}, "FingerprintManager.set_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [216, 217, 218, 219, 221, 222, 223], "excluded_lines": []}, "FingerprintManager.get_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [227], "excluded_lines": []}, "FingerprintManager.display_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [231, 232], "excluded_lines": []}, "FingerprintManager.get_fingerprint_directory": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [244, 245, 246, 248, 249], "excluded_lines": []}, "": {"executed_lines": [3, 4, 5, 6, 7, 9, 11, 12, 15, 18, 19, 27, 43, 56, 69, 90, 111, 141, 185, 195, 214, 225, 229, 234], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FingerprintManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 99, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 99, "excluded_lines": 0}, "missing_lines": [34, 35, 36, 37, 50, 51, 53, 54, 60, 61, 62, 63, 64, 67, 71, 72, 73, 74, 75, 76, 77, 78, 81, 82, 85, 86, 87, 88, 94, 95, 100, 104, 107, 108, 109, 122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 138, 139, 154, 155, 156, 157, 158, 159, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 180, 182, 183, 192, 193, 205, 206, 207, 208, 209, 211, 212, 216, 217, 218, 219, 221, 222, 223, 227, 231, 232, 244, 245, 246, 248, 249], "excluded_lines": []}, "": {"executed_lines": [3, 4, 5, 6, 7, 9, 11, 12, 15, 18, 19, 27, 43, 56, 69, 90, 111, 141, 185, 195, 214, 225, 229, 234], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/utils/imghdr_stub.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 77, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 77, "excluded_lines": 39}, "missing_lines": [7, 9, 10, 12, 14, 25, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 51, 54, 56, 57, 58, 59, 62, 65, 67, 68, 71, 74, 76, 77, 80, 83, 85, 86, 89, 92, 94, 95, 98, 101, 103, 104, 107, 110, 112, 113, 116, 119, 121, 122, 125, 128, 130, 131, 134, 137, 139, 140, 143, 146, 148, 149, 152, 155, 157, 158, 161, 164, 166, 167, 170], "excluded_lines": [178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 219, 220], "functions": {"what": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44], "excluded_lines": []}, "test_jpeg": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [56, 57, 58, 59], "excluded_lines": []}, "test_png": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [67, 68], "excluded_lines": []}, "test_gif": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [76, 77], "excluded_lines": []}, "test_tiff": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [85, 86], "excluded_lines": []}, "test_rgb": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [94, 95], "excluded_lines": []}, "test_pbm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [103, 104], "excluded_lines": []}, "test_pgm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [112, 113], "excluded_lines": []}, "test_ppm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [121, 122], "excluded_lines": []}, "test_rast": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [130, 131], "excluded_lines": []}, "test_xbm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [139, 140], "excluded_lines": []}, "test_bmp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [148, 149], "excluded_lines": []}, "test_webp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [157, 158], "excluded_lines": []}, "test_exr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [166, 167], "excluded_lines": []}, "test": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 14}, "missing_lines": [], "excluded_lines": [179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192]}, "testall": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 21}, "missing_lines": [], "excluded_lines": [196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216]}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 4}, "missing_lines": [7, 9, 10, 12, 14, 25, 51, 54, 62, 65, 71, 74, 80, 83, 89, 92, 98, 101, 107, 110, 116, 119, 125, 128, 134, 137, 143, 146, 152, 155, 161, 164, 170], "excluded_lines": [178, 195, 219, 220]}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 77, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 77, "excluded_lines": 39}, "missing_lines": [7, 9, 10, 12, 14, 25, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 51, 54, 56, 57, 58, 59, 62, 65, 67, 68, 71, 74, 76, 77, 80, 83, 85, 86, 89, 92, 94, 95, 98, 101, 103, 104, 107, 110, 112, 113, 116, 119, 121, 122, 125, 128, 130, 131, 134, 137, 139, 140, 143, 146, 148, 149, 152, 155, 157, 158, 161, 164, 166, 167, 170], "excluded_lines": [178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 219, 220]}}}, "src/utils/input_utils.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 13, 25, 48], "summary": {"covered_lines": 10, "num_statements": 40, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 30, "excluded_lines": 4}, "missing_lines": [15, 16, 17, 18, 19, 20, 21, 22, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 50, 51, 52, 54, 55, 58], "excluded_lines": [9, 10, 27, 28], "functions": {"_timed_input_posix": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [15, 16, 17, 18, 19, 20, 21, 22], "excluded_lines": []}, "_timed_input_windows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 2}, "missing_lines": [29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45], "excluded_lines": [27, 28]}, "timed_input": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [50, 51, 52, 54, 55, 58], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 13, 25, 48], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [9, 10]}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 13, 25, 48], "summary": {"covered_lines": 10, "num_statements": 40, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 30, "excluded_lines": 4}, "missing_lines": [15, 16, 17, 18, 19, 20, 21, 22, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 50, 51, 52, 54, 55, 58], "excluded_lines": [9, 10, 27, 28]}}}, "src/utils/key_derivation.py": {"executed_lines": [3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 30, 31, 32, 35, 38, 39, 41, 44, 47, 49, 53, 54, 55, 57, 58, 59, 66, 71, 74, 136, 172, 214, 222, 227, 251], "summary": {"covered_lines": 35, "num_statements": 117, "percent_covered": 29.914529914529915, "percent_covered_display": "30", "missing_lines": 82, "excluded_lines": 5}, "missing_lines": [96, 97, 98, 100, 101, 104, 105, 108, 109, 111, 113, 115, 116, 123, 126, 127, 129, 131, 132, 133, 147, 148, 149, 151, 152, 153, 155, 156, 157, 166, 181, 183, 186, 188, 189, 191, 194, 201, 203, 204, 208, 209, 210, 211, 216, 217, 218, 219, 224, 229, 230, 231, 233, 234, 236, 237, 238, 239, 240, 242, 243, 244, 245, 246, 247, 248, 279, 280, 281, 282, 283, 284, 285, 289, 290, 291, 292, 293, 295, 296, 297, 298], "excluded_lines": [49, 50, 167, 168, 169], "functions": {"derive_key_from_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [96, 97, 98, 100, 101, 104, 105, 108, 109, 111, 113, 115, 116, 123, 126, 127, 129, 131, 132, 133], "excluded_lines": []}, "derive_key_from_password_argon2": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 3}, "missing_lines": [147, 148, 149, 151, 152, 153, 155, 156, 157, 166], "excluded_lines": [167, 168, 169]}, "derive_key_from_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [181, 183, 186, 188, 189, 191, 194, 201, 203, 204, 208, 209, 210, 211], "excluded_lines": []}, "derive_index_key_seed_only": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [216, 217, 218, 219], "excluded_lines": []}, "derive_index_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [224], "excluded_lines": []}, "derive_totp_secret": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [229, 230, 231, 233, 234, 236, 237, 238, 239, 240, 242, 243, 244, 245, 246, 247, 248], "excluded_lines": []}, "calibrate_argon2_time_cost": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [279, 280, 281, 282, 283, 284, 285, 289, 290, 291, 292, 293, 295, 296, 297, 298], "excluded_lines": []}, "": {"executed_lines": [3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 30, 31, 32, 35, 38, 39, 41, 44, 47, 49, 53, 54, 55, 57, 58, 59, 66, 71, 74, 136, 172, 214, 222, 227, 251], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [49, 50]}}, "classes": {"EncryptionMode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "KdfConfig": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 30, 31, 32, 35, 38, 39, 41, 44, 47, 49, 53, 54, 55, 57, 58, 59, 66, 71, 74, 136, 172, 214, 222, 227, 251], "summary": {"covered_lines": 35, "num_statements": 117, "percent_covered": 29.914529914529915, "percent_covered_display": "30", "missing_lines": 82, "excluded_lines": 5}, "missing_lines": [96, 97, 98, 100, 101, 104, 105, 108, 109, 111, 113, 115, 116, 123, 126, 127, 129, 131, 132, 133, 147, 148, 149, 151, 152, 153, 155, 156, 157, 166, 181, 183, 186, 188, 189, 191, 194, 201, 203, 204, 208, 209, 210, 211, 216, 217, 218, 219, 224, 229, 230, 231, 233, 234, 236, 237, 238, 239, 240, 242, 243, 244, 245, 246, 247, 248, 279, 280, 281, 282, 283, 284, 285, 289, 290, 291, 292, 293, 295, 296, 297, 298], "excluded_lines": [49, 50, 167, 168, 169]}}}, "src/utils/key_hierarchy.py": {"executed_lines": [1, 3, 4, 5, 8], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [21, 28], "excluded_lines": [], "functions": {"kd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [21, 28], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 8], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 8], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [21, 28], "excluded_lines": []}}}, "src/utils/key_validation.py": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 10, 13, 23, 41, 51, 63], "summary": {"covered_lines": 12, "num_statements": 29, "percent_covered": 41.37931034482759, "percent_covered_display": "41", "missing_lines": 17, "excluded_lines": 15}, "missing_lines": [15, 16, 17, 25, 26, 27, 35, 43, 44, 45, 53, 54, 55, 56, 57, 65, 66], "excluded_lines": [18, 19, 20, 36, 37, 38, 46, 47, 48, 58, 59, 60, 67, 68, 69], "functions": {"validate_totp_secret": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 3}, "missing_lines": [15, 16, 17], "excluded_lines": [18, 19, 20]}, "validate_ssh_key_pair": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 3}, "missing_lines": [25, 26, 27, 35], "excluded_lines": [36, 37, 38]}, "validate_pgp_private_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 3}, "missing_lines": [43, 44, 45], "excluded_lines": [46, 47, 48]}, "validate_nostr_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 3}, "missing_lines": [53, 54, 55, 56, 57], "excluded_lines": [58, 59, 60]}, "validate_seed_phrase": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 3}, "missing_lines": [65, 66], "excluded_lines": [67, 68, 69]}, "": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 10, 13, 23, 41, 51, 63], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 10, 13, 23, 41, 51, 63], "summary": {"covered_lines": 12, "num_statements": 29, "percent_covered": 41.37931034482759, "percent_covered_display": "41", "missing_lines": 17, "excluded_lines": 15}, "missing_lines": [15, 16, 17, 25, 26, 27, 35, 43, 44, 45, 53, 54, 55, 56, 57, 65, 66], "excluded_lines": [18, 19, 20, 36, 37, 38, 46, 47, 48, 58, 59, 60, 67, 68, 69]}}}, "src/utils/logging_utils.py": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 12, 18, 19, 21, 32, 38, 44, 45, 54, 57, 58, 62], "summary": {"covered_lines": 15, "num_statements": 23, "percent_covered": 65.21739130434783, "percent_covered_display": "65", "missing_lines": 8, "excluded_lines": 13}, "missing_lines": [35, 41, 47, 48, 49, 51, 59, 60], "excluded_lines": [12, 13, 14, 15, 21, 22, 23, 24, 25, 26, 27, 28, 29], "functions": {"ConsolePauseFilter.filter": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [15]}, "ChecksumWarningFilter.filter": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [24, 25, 26, 27, 28, 29]}, "pause_console_logging": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [35], "excluded_lines": []}, "resume_console_logging": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [41], "excluded_lines": []}, "console_logging_paused": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [47, 48, 49, 51], "excluded_lines": []}, "pause_logging_for_ui": {"executed_lines": [57, 58, 62], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pause_logging_for_ui.wrapper": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [59, 60], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 12, 18, 19, 21, 32, 38, 44, 45, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [12, 13, 14, 21, 22, 23]}}, "classes": {"ConsolePauseFilter": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [15]}, "ChecksumWarningFilter": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [24, 25, 26, 27, 28, 29]}, "": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 12, 18, 19, 21, 32, 38, 44, 45, 54, 57, 58, 62], "summary": {"covered_lines": 15, "num_statements": 23, "percent_covered": 65.21739130434783, "percent_covered_display": "65", "missing_lines": 8, "excluded_lines": 6}, "missing_lines": [35, 41, 47, 48, 49, 51, 59, 60], "excluded_lines": [12, 13, 14, 21, 22, 23]}}}, "src/utils/memory_protection.py": {"executed_lines": [1, 3, 4, 10, 11, 17, 25, 29, 36], "summary": {"covered_lines": 8, "num_statements": 20, "percent_covered": 40.0, "percent_covered_display": "40", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [18, 19, 20, 21, 22, 23, 27, 31, 32, 33, 34, 38], "excluded_lines": [], "functions": {"InMemorySecret.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [18, 19, 20, 21, 22, 23], "excluded_lines": []}, "InMemorySecret.get_bytes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [27], "excluded_lines": []}, "InMemorySecret.wipe": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [31, 32, 33, 34], "excluded_lines": []}, "InMemorySecret.get_str": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [38], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 10, 11, 17, 25, 29, 36], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"InMemorySecret": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [18, 19, 20, 21, 22, 23, 27, 31, 32, 33, 34, 38], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 10, 11, 17, 25, 29, 36], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/utils/password_prompt.py": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 22, 24, 27, 30, 33, 36, 42, 56, 65, 66, 68, 71, 158, 219, 259], "summary": {"covered_lines": 21, "num_statements": 126, "percent_covered": 16.666666666666668, "percent_covered_display": "17", "missing_lines": 105, "excluded_lines": 0}, "missing_lines": [39, 45, 46, 47, 48, 49, 50, 51, 52, 53, 59, 60, 61, 62, 89, 90, 91, 92, 93, 94, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 113, 114, 120, 123, 124, 125, 127, 128, 131, 132, 133, 134, 137, 138, 139, 141, 142, 143, 144, 145, 146, 149, 150, 151, 153, 154, 155, 180, 181, 182, 184, 185, 186, 187, 188, 190, 191, 194, 195, 196, 197, 199, 200, 201, 203, 204, 205, 206, 207, 208, 212, 213, 214, 216, 235, 236, 237, 238, 239, 240, 241, 242, 243, 245, 247, 248, 249, 250, 251, 252, 255, 256, 268], "excluded_lines": [], "functions": {"_env_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [39], "excluded_lines": []}, "_get_max_attempts": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [45, 46, 47, 48, 49, 50, 51, 52, 53], "excluded_lines": []}, "_apply_backoff": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [59, 60, 61, 62], "excluded_lines": []}, "prompt_new_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 45, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 45, "excluded_lines": 0}, "missing_lines": [89, 90, 91, 92, 93, 94, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 113, 114, 120, 123, 124, 125, 127, 128, 131, 132, 133, 134, 137, 138, 139, 141, 142, 143, 144, 145, 146, 149, 150, 151, 153, 154, 155], "excluded_lines": []}, "prompt_existing_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 27, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 27, "excluded_lines": 0}, "missing_lines": [180, 181, 182, 184, 185, 186, 187, 188, 190, 191, 194, 195, 196, 197, 199, 200, 201, 203, 204, 205, 206, 207, 208, 212, 213, 214, 216], "excluded_lines": []}, "confirm_action": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [235, 236, 237, 238, 239, 240, 241, 242, 243, 245, 247, 248, 249, 250, 251, 252, 255, 256], "excluded_lines": []}, "prompt_for_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [268], "excluded_lines": []}, "": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 22, 24, 27, 30, 33, 36, 42, 56, 65, 66, 68, 71, 158, 219, 259], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"PasswordPromptError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 22, 24, 27, 30, 33, 36, 42, 56, 65, 66, 68, 71, 158, 219, 259], "summary": {"covered_lines": 21, "num_statements": 126, "percent_covered": 16.666666666666668, "percent_covered_display": "17", "missing_lines": 105, "excluded_lines": 0}, "missing_lines": [39, 45, 46, 47, 48, 49, 50, 51, 52, 53, 59, 60, 61, 62, 89, 90, 91, 92, 93, 94, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 113, 114, 120, 123, 124, 125, 127, 128, 131, 132, 133, 134, 137, 138, 139, 141, 142, 143, 144, 145, 146, 149, 150, 151, 153, 154, 155, 180, 181, 182, 184, 185, 186, 187, 188, 190, 191, 194, 195, 196, 197, 199, 200, 201, 203, 204, 205, 206, 207, 208, 212, 213, 214, 216, 235, 236, 237, 238, 239, 240, 241, 242, 243, 245, 247, 248, 249, 250, 251, 252, 255, 256, 268], "excluded_lines": []}}}, "src/utils/seed_prompt.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 17, 18, 20, 23, 42, 51, 76, 107, 121], "summary": {"covered_lines": 17, "num_statements": 128, "percent_covered": 13.28125, "percent_covered_display": "13", "missing_lines": 111, "excluded_lines": 11}, "missing_lines": [31, 32, 33, 34, 35, 36, 37, 38, 39, 45, 46, 47, 48, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72, 73, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 102, 104, 109, 110, 111, 112, 113, 114, 118, 150, 152, 153, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 184, 185, 186, 187, 188, 189, 190, 191, 194, 195, 196, 197, 198, 199, 200, 201, 204, 205, 206, 207, 208, 209, 211, 212, 213, 214], "excluded_lines": [7, 8, 13, 14, 15, 53, 54, 78, 79, 115, 116], "functions": {"_get_max_attempts": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [31, 32, 33, 34, 35, 36, 37, 38, 39], "excluded_lines": []}, "_apply_backoff": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [45, 46, 47, 48], "excluded_lines": []}, "_masked_input_windows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 2}, "missing_lines": [56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72, 73], "excluded_lines": [53, 54]}, "_masked_input_posix": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 2}, "missing_lines": [81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 102, 104], "excluded_lines": [78, 79]}, "masked_input": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 2}, "missing_lines": [109, 110, 111, 112, 113, 114, 118], "excluded_lines": [115, 116]}, "prompt_seed_words": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 52, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 52, "excluded_lines": 0}, "missing_lines": [150, 152, 153, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 184, 185, 186, 187, 188, 189, 190, 191, 194, 195, 196, 197, 198, 199, 200, 201, 204, 205, 206, 207, 208, 209, 211, 212, 213, 214], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 17, 18, 20, 23, 42, 51, 76, 107, 121], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 5}, "missing_lines": [], "excluded_lines": [7, 8, 13, 14, 15]}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 17, 18, 20, 23, 42, 51, 76, 107, 121], "summary": {"covered_lines": 17, "num_statements": 128, "percent_covered": 13.28125, "percent_covered_display": "13", "missing_lines": 111, "excluded_lines": 11}, "missing_lines": [31, 32, 33, 34, 35, 36, 37, 38, 39, 45, 46, 47, 48, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72, 73, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 102, 104, 109, 110, 111, 112, 113, 114, 118, 150, 152, 153, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 184, 185, 186, 187, 188, 189, 190, 191, 194, 195, 196, 197, 198, 199, 200, 201, 204, 205, 206, 207, 208, 209, 211, 212, 213, 214], "excluded_lines": [7, 8, 13, 14, 15, 53, 54, 78, 79, 115, 116]}}}, "src/utils/terminal_utils.py": {"executed_lines": [1, 3, 4, 5, 7, 9, 12, 29, 34, 57, 73, 116], "summary": {"covered_lines": 11, "num_statements": 75, "percent_covered": 14.666666666666666, "percent_covered_display": "15", "missing_lines": 64, "excluded_lines": 6}, "missing_lines": [14, 15, 16, 17, 18, 19, 20, 26, 31, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 106, 107, 108, 109, 110, 111, 113, 118, 119, 120, 121, 122, 123], "excluded_lines": [21, 22, 25, 102, 103, 104], "functions": {"format_profile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 3}, "missing_lines": [14, 15, 16, 17, 18, 19, 20, 26], "excluded_lines": [21, 22, 25]}, "clear_screen": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [31], "excluded_lines": []}, "clear_and_print_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54], "excluded_lines": []}, "clear_and_print_profile_chain": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [61, 62, 63, 64, 65, 66, 67, 68, 69, 70], "excluded_lines": []}, "clear_header_with_notification": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 3}, "missing_lines": [82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 106, 107, 108, 109, 110, 111, 113], "excluded_lines": [102, 103, 104]}, "pause": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [118, 119, 120, 121, 122, 123], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 12, 29, 34, 57, 73, 116], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 7, 9, 12, 29, 34, 57, 73, 116], "summary": {"covered_lines": 11, "num_statements": 75, "percent_covered": 14.666666666666666, "percent_covered_display": "15", "missing_lines": 64, "excluded_lines": 6}, "missing_lines": [14, 15, 16, 17, 18, 19, 20, 26, 31, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 106, 107, 108, 109, 110, 111, 113, 118, 119, 120, 121, 122, 123], "excluded_lines": [21, 22, 25, 102, 103, 104]}}}}, "totals": {"covered_lines": 1400, "num_statements": 9702, "percent_covered": 14.43001443001443, "percent_covered_display": "14", "missing_lines": 8302, "excluded_lines": 274}} \ No newline at end of file diff --git a/artifacts/coverage/coverage.smoke.json b/artifacts/coverage/coverage.smoke.json new file mode 100644 index 00000000..dfb657bc --- /dev/null +++ b/artifacts/coverage/coverage.smoke.json @@ -0,0 +1 @@ +{"meta": {"format": 3, "version": "7.10.1", "timestamp": "2026-02-23T15:07:05.469990", "branch_coverage": false, "show_contexts": false}, "files": {"src/constants.py": {"executed_lines": [3, 4, 7, 15, 16, 17, 22, 23, 28, 33, 45, 46, 47, 50, 53, 56, 62], "summary": {"covered_lines": 17, "num_statements": 22, "percent_covered": 77.27272727272727, "percent_covered_display": "77", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [35, 36, 37, 38, 39], "excluded_lines": [], "functions": {"initialize_app": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [35, 36, 37, 38, 39], "excluded_lines": []}, "": {"executed_lines": [3, 4, 7, 15, 16, 17, 22, 23, 28, 33, 45, 46, 47, 50, 53, 56, 62], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 4, 7, 15, 16, 17, 22, 23, 28, 33, 45, 46, 47, 50, 53, 56, 62], "summary": {"covered_lines": 17, "num_statements": 22, "percent_covered": 77.27272727272727, "percent_covered_display": "77", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [35, 36, 37, 38, 39], "excluded_lines": []}}}, "src/local_bip85/__init__.py": {"executed_lines": [3, 5, 7, 8, 15], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [9, 10, 11], "excluded_lines": [], "functions": {"": {"executed_lines": [3, 5, 7, 8, 15], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [9, 10, 11], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 5, 7, 8, 15], "summary": {"covered_lines": 5, "num_statements": 8, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [9, 10, 11], "excluded_lines": []}}}, "src/local_bip85/bip85.py": {"executed_lines": [3, 16, 17, 18, 19, 20, 21, 23, 25, 27, 28, 29, 32, 35, 36, 38, 41, 42, 61, 125, 149], "summary": {"covered_lines": 19, "num_statements": 75, "percent_covered": 25.333333333333332, "percent_covered_display": "25", "missing_lines": 56, "excluded_lines": 0}, "missing_lines": [50, 51, 52, 54, 55, 56, 57, 58, 59, 86, 87, 88, 89, 90, 91, 94, 96, 97, 98, 99, 101, 102, 103, 105, 107, 108, 111, 114, 118, 119, 120, 121, 122, 123, 126, 127, 128, 129, 130, 132, 138, 139, 142, 143, 144, 145, 146, 147, 151, 152, 153, 154, 155, 156, 157, 158], "excluded_lines": [], "functions": {"BIP85.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [50, 51, 52, 54, 55, 56, 57, 58, 59], "excluded_lines": []}, "BIP85.derive_entropy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [86, 87, 88, 89, 90, 91, 94, 96, 97, 98, 99, 101, 102, 103, 105, 107, 108, 111, 114, 118, 119, 120, 121, 122, 123], "excluded_lines": []}, "BIP85.derive_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [126, 127, 128, 129, 130, 132, 138, 139, 142, 143, 144, 145, 146, 147], "excluded_lines": []}, "BIP85.derive_symmetric_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [151, 152, 153, 154, 155, 156, 157, 158], "excluded_lines": []}, "": {"executed_lines": [3, 16, 17, 18, 19, 20, 21, 23, 25, 27, 28, 29, 32, 35, 36, 38, 41, 42, 61, 125, 149], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"Bip85Error": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BIP85": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 56, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 56, "excluded_lines": 0}, "missing_lines": [50, 51, 52, 54, 55, 56, 57, 58, 59, 86, 87, 88, 89, 90, 91, 94, 96, 97, 98, 99, 101, 102, 103, 105, 107, 108, 111, 114, 118, 119, 120, 121, 122, 123, 126, 127, 128, 129, 130, 132, 138, 139, 142, 143, 144, 145, 146, 147, 151, 152, 153, 154, 155, 156, 157, 158], "excluded_lines": []}, "": {"executed_lines": [3, 16, 17, 18, 19, 20, 21, 23, 25, 27, 28, 29, 32, 35, 36, 38, 41, 42, 61, 125, 149], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/main.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1067, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1067, "excluded_lines": 5}, "missing_lines": [2, 3, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 33, 40, 41, 42, 47, 49, 51, 58, 60, 61, 62, 63, 64, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 84, 87, 88, 90, 91, 92, 93, 95, 96, 98, 101, 102, 104, 105, 106, 107, 108, 110, 112, 113, 116, 117, 124, 125, 126, 127, 128, 129, 131, 134, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 149, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 165, 166, 172, 173, 174, 175, 181, 183, 184, 185, 186, 188, 189, 190, 191, 193, 194, 195, 200, 201, 202, 204, 205, 206, 207, 210, 216, 217, 218, 219, 220, 223, 225, 226, 227, 228, 229, 231, 232, 233, 234, 236, 237, 238, 239, 241, 242, 245, 247, 248, 249, 250, 251, 252, 254, 257, 260, 261, 268, 270, 271, 272, 273, 276, 282, 283, 284, 285, 286, 288, 289, 290, 291, 292, 293, 294, 295, 298, 302, 303, 304, 305, 306, 308, 309, 310, 311, 312, 313, 316, 324, 325, 326, 327, 328, 330, 331, 332, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 363, 365, 366, 372, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 398, 399, 400, 401, 402, 403, 404, 405, 408, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 426, 427, 428, 429, 430, 432, 435, 437, 438, 439, 440, 446, 447, 449, 450, 453, 454, 455, 456, 457, 458, 459, 465, 466, 467, 468, 470, 473, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 490, 492, 493, 494, 495, 496, 497, 498, 501, 503, 504, 505, 506, 507, 508, 509, 510, 511, 514, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 542, 545, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 570, 571, 572, 573, 574, 575, 576, 577, 579, 582, 584, 585, 586, 587, 588, 590, 591, 592, 593, 594, 595, 596, 598, 601, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 635, 637, 638, 640, 641, 642, 643, 644, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 684, 686, 687, 688, 689, 690, 691, 692, 693, 695, 696, 697, 698, 699, 701, 704, 705, 706, 707, 708, 709, 710, 711, 713, 714, 715, 716, 717, 718, 719, 720, 721, 723, 724, 725, 726, 727, 728, 729, 730, 733, 735, 736, 737, 738, 739, 740, 741, 743, 744, 745, 746, 747, 749, 752, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 803, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 840, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 878, 880, 881, 886, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 914, 917, 919, 920, 921, 922, 923, 924, 925, 926, 927, 929, 930, 935, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 968, 971, 973, 974, 979, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1070, 1073, 1081, 1092, 1093, 1094, 1095, 1096, 1097, 1102, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1117, 1118, 1119, 1123, 1124, 1126, 1129, 1130, 1131, 1132, 1133, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1165, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1234, 1237, 1247, 1248, 1249, 1250, 1251, 1253, 1254, 1255, 1256, 1260, 1265, 1270, 1276, 1278, 1279, 1280, 1286, 1287, 1289, 1290, 1292, 1293, 1295, 1296, 1298, 1300, 1301, 1302, 1303, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1335, 1336, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1350, 1351, 1352, 1353, 1355, 1356, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1416, 1418, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1430, 1431, 1433, 1434, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470, 1473, 1474], "excluded_lines": [333, 334, 367, 368, 369], "functions": {"_warn_missing_optional_dependencies": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [60, 61, 62, 63, 64], "excluded_lines": []}, "load_global_config": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [73, 74, 75, 76, 77, 78, 79, 80, 81], "excluded_lines": []}, "configure_logging": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [87, 88, 90, 91, 92, 93, 95, 96, 98, 101, 102, 104, 105, 106, 107, 108, 110, 112, 113], "excluded_lines": []}, "confirm_action": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [124, 125, 126, 127, 128, 129, 131], "excluded_lines": []}, "drain_notifications": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146], "excluded_lines": []}, "get_notification_text": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162], "excluded_lines": []}, "handle_switch_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [172, 173, 174, 175, 181, 183, 184, 185, 186, 188, 189, 190, 191, 193, 194, 195, 200, 201, 202, 204, 205, 206, 207], "excluded_lines": []}, "handle_add_new_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [216, 217, 218, 219, 220], "excluded_lines": []}, "handle_remove_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 0}, "missing_lines": [225, 226, 227, 228, 229, 231, 232, 233, 234, 236, 237, 238, 239, 241, 242, 245, 247, 254, 257, 260, 261, 268, 270, 271, 272, 273], "excluded_lines": []}, "handle_remove_fingerprint._cleanup_and_exit": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [248, 249, 250, 251, 252], "excluded_lines": []}, "handle_list_fingerprints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [282, 283, 284, 285, 286, 288, 289, 290, 291, 292, 293, 294, 295], "excluded_lines": []}, "handle_display_npub": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [302, 303, 304, 305, 306, 308, 309, 310, 311, 312, 313], "excluded_lines": []}, "_display_live_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 32, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 32, "excluded_lines": 2}, "missing_lines": [324, 325, 326, 327, 328, 330, 331, 332, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360], "excluded_lines": [333, 334]}, "handle_display_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 3}, "missing_lines": [365, 366], "excluded_lines": [367, 368, 369]}, "print_matches": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 28, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 28, "excluded_lines": 0}, "missing_lines": [377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 398, 399, 400, 401, 402, 403, 404, 405], "excluded_lines": []}, "handle_post_to_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 426, 427, 428, 429, 430, 432], "excluded_lines": []}, "handle_retrieve_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [437, 438, 439, 440, 446, 447, 449, 450, 453, 454, 455, 456, 457, 458, 459, 465, 466, 467, 468, 470], "excluded_lines": []}, "handle_view_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487], "excluded_lines": []}, "_safe_close_client_pool": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [492, 493, 494, 495, 496, 497, 498], "excluded_lines": []}, "_reload_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [503, 504, 505, 506, 507, 508, 509, 510, 511], "excluded_lines": []}, "handle_add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 0}, "missing_lines": [516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 542], "excluded_lines": []}, "handle_remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 27, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 27, "excluded_lines": 0}, "missing_lines": [547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 570, 571, 572, 573, 574, 575, 576, 577, 579], "excluded_lines": []}, "handle_reset_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [584, 585, 586, 587, 588, 590, 591, 592, 593, 594, 595, 596, 598], "excluded_lines": []}, "handle_set_inactivity_timeout": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 30, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 30, "excluded_lines": 0}, "missing_lines": [603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632], "excluded_lines": []}, "handle_set_kdf_iterations": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 38, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 38, "excluded_lines": 0}, "missing_lines": [637, 638, 640, 641, 642, 643, 644, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681], "excluded_lines": []}, "handle_set_additional_backup_location": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 39, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 39, "excluded_lines": 0}, "missing_lines": [686, 687, 688, 689, 690, 691, 692, 693, 695, 696, 697, 698, 699, 701, 704, 705, 706, 707, 708, 709, 710, 711, 713, 714, 715, 716, 717, 718, 719, 720, 721, 723, 724, 725, 726, 727, 728, 729, 730], "excluded_lines": []}, "handle_set_profile_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [735, 736, 737, 738, 739, 740, 741, 743, 744, 745, 746, 747, 749], "excluded_lines": []}, "handle_toggle_secret_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 46, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 46, "excluded_lines": 0}, "missing_lines": [754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800], "excluded_lines": []}, "handle_toggle_quick_unlock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 32, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 32, "excluded_lines": 0}, "missing_lines": [805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837], "excluded_lines": []}, "handle_toggle_offline_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 0}, "missing_lines": [842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875], "excluded_lines": []}, "handle_profiles_menu": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [880, 881, 886, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 914], "excluded_lines": []}, "handle_nostr_menu": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 39, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 39, "excluded_lines": 0}, "missing_lines": [919, 920, 921, 922, 923, 924, 925, 926, 927, 929, 930, 935, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 968], "excluded_lines": []}, "handle_settings": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 88, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 88, "excluded_lines": 0}, "missing_lines": [973, 974, 979, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1070], "excluded_lines": []}, "display_menu": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 107, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 107, "excluded_lines": 0}, "missing_lines": [1081, 1092, 1093, 1094, 1095, 1096, 1097, 1102, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1117, 1118, 1119, 1123, 1124, 1126, 1129, 1130, 1131, 1132, 1133, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1165, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1234], "excluded_lines": []}, "main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 159, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 159, "excluded_lines": 0}, "missing_lines": [1247, 1248, 1249, 1250, 1251, 1253, 1254, 1255, 1256, 1260, 1265, 1270, 1276, 1278, 1279, 1280, 1286, 1287, 1289, 1290, 1292, 1293, 1295, 1296, 1298, 1300, 1301, 1302, 1303, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1335, 1336, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1350, 1351, 1352, 1353, 1355, 1356, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1416, 1418, 1430, 1431, 1433, 1434, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470], "excluded_lines": []}, "main.signal_handler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 68, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 68, "excluded_lines": 0}, "missing_lines": [2, 3, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 33, 40, 41, 42, 47, 49, 51, 58, 71, 84, 116, 117, 134, 149, 165, 166, 210, 223, 276, 298, 316, 363, 372, 408, 435, 473, 490, 501, 514, 545, 582, 601, 635, 684, 733, 752, 803, 840, 878, 917, 971, 1073, 1237, 1473, 1474], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1067, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1067, "excluded_lines": 5}, "missing_lines": [2, 3, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 33, 40, 41, 42, 47, 49, 51, 58, 60, 61, 62, 63, 64, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 84, 87, 88, 90, 91, 92, 93, 95, 96, 98, 101, 102, 104, 105, 106, 107, 108, 110, 112, 113, 116, 117, 124, 125, 126, 127, 128, 129, 131, 134, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 149, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 165, 166, 172, 173, 174, 175, 181, 183, 184, 185, 186, 188, 189, 190, 191, 193, 194, 195, 200, 201, 202, 204, 205, 206, 207, 210, 216, 217, 218, 219, 220, 223, 225, 226, 227, 228, 229, 231, 232, 233, 234, 236, 237, 238, 239, 241, 242, 245, 247, 248, 249, 250, 251, 252, 254, 257, 260, 261, 268, 270, 271, 272, 273, 276, 282, 283, 284, 285, 286, 288, 289, 290, 291, 292, 293, 294, 295, 298, 302, 303, 304, 305, 306, 308, 309, 310, 311, 312, 313, 316, 324, 325, 326, 327, 328, 330, 331, 332, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 363, 365, 366, 372, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 398, 399, 400, 401, 402, 403, 404, 405, 408, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 426, 427, 428, 429, 430, 432, 435, 437, 438, 439, 440, 446, 447, 449, 450, 453, 454, 455, 456, 457, 458, 459, 465, 466, 467, 468, 470, 473, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 490, 492, 493, 494, 495, 496, 497, 498, 501, 503, 504, 505, 506, 507, 508, 509, 510, 511, 514, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 542, 545, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 570, 571, 572, 573, 574, 575, 576, 577, 579, 582, 584, 585, 586, 587, 588, 590, 591, 592, 593, 594, 595, 596, 598, 601, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 635, 637, 638, 640, 641, 642, 643, 644, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 684, 686, 687, 688, 689, 690, 691, 692, 693, 695, 696, 697, 698, 699, 701, 704, 705, 706, 707, 708, 709, 710, 711, 713, 714, 715, 716, 717, 718, 719, 720, 721, 723, 724, 725, 726, 727, 728, 729, 730, 733, 735, 736, 737, 738, 739, 740, 741, 743, 744, 745, 746, 747, 749, 752, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 803, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 840, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 878, 880, 881, 886, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 914, 917, 919, 920, 921, 922, 923, 924, 925, 926, 927, 929, 930, 935, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 968, 971, 973, 974, 979, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1070, 1073, 1081, 1092, 1093, 1094, 1095, 1096, 1097, 1102, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1117, 1118, 1119, 1123, 1124, 1126, 1129, 1130, 1131, 1132, 1133, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1165, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1234, 1237, 1247, 1248, 1249, 1250, 1251, 1253, 1254, 1255, 1256, 1260, 1265, 1270, 1276, 1278, 1279, 1280, 1286, 1287, 1289, 1290, 1292, 1293, 1295, 1296, 1298, 1300, 1301, 1302, 1303, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1335, 1336, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1350, 1351, 1352, 1353, 1355, 1356, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1416, 1418, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1430, 1431, 1433, 1434, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470, 1473, 1474], "excluded_lines": [333, 334, 367, 368, 369]}}}, "src/nostr/__init__.py": {"executed_lines": [3, 5, 6, 8, 16, 18, 29, 30, 32, 34], "summary": {"covered_lines": 9, "num_statements": 11, "percent_covered": 81.81818181818181, "percent_covered_display": "82", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [31, 33], "excluded_lines": [], "functions": {"__getattr__": {"executed_lines": [30, 32, 34], "summary": {"covered_lines": 3, "num_statements": 5, "percent_covered": 60.0, "percent_covered_display": "60", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [31, 33], "excluded_lines": []}, "": {"executed_lines": [3, 5, 6, 8, 16, 18, 29], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 5, 6, 8, 16, 18, 29, 30, 32, 34], "summary": {"covered_lines": 9, "num_statements": 11, "percent_covered": 81.81818181818181, "percent_covered_display": "82", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [31, 33], "excluded_lines": []}}}, "src/nostr/backup_models.py": {"executed_lines": [1, 2, 5, 6, 7, 10, 11, 12, 14, 15, 16, 17, 20, 21, 22, 24, 25, 26, 27, 28], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [1, 2, 5, 6, 7, 10, 11, 12, 14, 15, 16, 17, 20, 21, 22, 24, 25, 26, 27, 28], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"ChunkMeta": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "Manifest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 7, 10, 11, 12, 14, 15, 16, 17, 20, 21, 22, 24, 25, 26, 27, 28], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/client.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 22, 24, 25, 27, 34, 35, 36, 38, 42, 43, 45, 46, 49, 50, 52, 113], "summary": {"covered_lines": 24, "num_statements": 58, "percent_covered": 41.37931034482759, "percent_covered_display": "41", "missing_lines": 34, "excluded_lines": 2}, "missing_lines": [63, 64, 65, 66, 67, 69, 70, 73, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 88, 90, 91, 92, 93, 94, 97, 99, 100, 101, 102, 103, 104, 107, 108, 110], "excluded_lines": [38, 39], "functions": {"NostrClient.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 34, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 34, "excluded_lines": 0}, "missing_lines": [63, 64, 65, 66, 67, 69, 70, 73, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 88, 90, 91, 92, 93, 94, 97, 99, 100, 101, 102, 103, 104, 107, 108, 110], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 22, 24, 25, 27, 34, 35, 36, 38, 42, 43, 45, 46, 49, 50, 52, 113], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [38, 39]}}, "classes": {"NostrClient": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 34, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 34, "excluded_lines": 0}, "missing_lines": [63, 64, 65, 66, 67, 69, 70, 73, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 88, 90, 91, 92, 93, 94, 97, 99, 100, 101, 102, 103, 104, 107, 108, 110], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 22, 24, 25, 27, 34, 35, 36, 38, 42, 43, 45, 46, 49, 50, 52, 113], "summary": {"covered_lines": 24, "num_statements": 24, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [38, 39]}}}, "src/nostr/coincurve_keys.py": {"executed_lines": [1, 3, 4, 7, 8, 10, 28, 29, 34, 35, 42, 45], "summary": {"covered_lines": 11, "num_statements": 33, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [11, 12, 13, 14, 15, 17, 18, 20, 21, 22, 23, 24, 26, 31, 32, 36, 37, 38, 39, 40, 43, 46], "excluded_lines": [], "functions": {"Keys.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [11, 12, 13, 14, 15, 17, 18, 20, 21, 22, 23, 24, 26], "excluded_lines": []}, "Keys.hex_to_bech32": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [31, 32], "excluded_lines": []}, "Keys.bech32_to_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [36, 37, 38, 39, 40], "excluded_lines": []}, "Keys.private_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [43], "excluded_lines": []}, "Keys.public_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [46], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 7, 8, 10, 28, 29, 34, 35, 42, 45], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"Keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [11, 12, 13, 14, 15, 17, 18, 20, 21, 22, 23, 24, 26, 31, 32, 36, 37, 38, 39, 40, 43, 46], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 7, 8, 10, 28, 29, 34, 35, 42, 45], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/connection.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 15, 22, 23, 25, 32, 38, 45, 69, 93, 103, 109, 148, 155, 164, 201, 225], "summary": {"covered_lines": 26, "num_statements": 155, "percent_covered": 16.774193548387096, "percent_covered_display": "17", "missing_lines": 129, "excluded_lines": 0}, "missing_lines": [27, 28, 29, 30, 34, 35, 36, 40, 41, 42, 43, 46, 47, 49, 50, 51, 52, 53, 54, 55, 57, 59, 60, 62, 63, 65, 66, 67, 71, 72, 73, 80, 81, 84, 85, 86, 87, 88, 89, 90, 91, 94, 95, 96, 97, 98, 101, 105, 106, 107, 116, 117, 118, 119, 120, 121, 123, 124, 125, 129, 130, 131, 132, 133, 135, 140, 141, 143, 144, 145, 146, 150, 151, 152, 153, 157, 158, 159, 160, 161, 162, 168, 169, 171, 172, 173, 174, 176, 181, 182, 183, 184, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 202, 203, 204, 205, 206, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 227, 228, 229, 230, 231, 232], "excluded_lines": [], "functions": {"ConnectionHandler.connect": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [27, 28, 29, 30], "excluded_lines": []}, "ConnectionHandler.initialize_client_pool": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [34, 35, 36], "excluded_lines": []}, "ConnectionHandler._connect_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [40, 41, 42, 43], "excluded_lines": []}, "ConnectionHandler._initialize_client_pool": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [46, 47, 49, 50, 51, 52, 53, 54, 55, 57, 59, 60, 62, 63, 65, 66, 67], "excluded_lines": []}, "ConnectionHandler._ping_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [71, 72, 73, 80, 81, 84, 85, 86, 87, 88, 89, 90, 91], "excluded_lines": []}, "ConnectionHandler._check_relay_health": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [94, 95, 96, 97, 98, 101], "excluded_lines": []}, "ConnectionHandler.check_relay_health": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [105, 106, 107], "excluded_lines": []}, "ConnectionHandler.publish_json_to_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [116, 117, 118, 119, 120, 121, 123, 124, 125, 129, 130, 131, 132, 133, 135, 140, 141, 143, 144, 145, 146], "excluded_lines": []}, "ConnectionHandler.publish_event": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [150, 151, 152, 153], "excluded_lines": []}, "ConnectionHandler.update_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [157, 158, 159, 160, 161, 162], "excluded_lines": []}, "ConnectionHandler.retrieve_json_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [168, 169, 171, 172, 173, 174, 176, 181, 182, 183, 184, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199], "excluded_lines": []}, "ConnectionHandler._retrieve_json_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [202, 203, 204, 205, 206, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223], "excluded_lines": []}, "ConnectionHandler.close_client_pool": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [227, 228, 229, 230, 231, 232], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 15, 22, 23, 25, 32, 38, 45, 69, 93, 103, 109, 148, 155, 164, 201, 225], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"ConnectionHandler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 129, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 129, "excluded_lines": 0}, "missing_lines": [27, 28, 29, 30, 34, 35, 36, 40, 41, 42, 43, 46, 47, 49, 50, 51, 52, 53, 54, 55, 57, 59, 60, 62, 63, 65, 66, 67, 71, 72, 73, 80, 81, 84, 85, 86, 87, 88, 89, 90, 91, 94, 95, 96, 97, 98, 101, 105, 106, 107, 116, 117, 118, 119, 120, 121, 123, 124, 125, 129, 130, 131, 132, 133, 135, 140, 141, 143, 144, 145, 146, 150, 151, 152, 153, 157, 158, 159, 160, 161, 162, 168, 169, 171, 172, 173, 174, 176, 181, 182, 183, 184, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 202, 203, 204, 205, 206, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 227, 228, 229, 230, 231, 232], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 15, 22, 23, 25, 32, 38, 45, 69, 93, 103, 109, 148, 155, 164, 201, 225], "summary": {"covered_lines": 26, "num_statements": 26, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/key_manager.py": {"executed_lines": [3, 4, 5, 7, 8, 9, 12, 13, 15, 18, 19, 21, 64, 80, 97, 111, 122, 131, 140, 157], "summary": {"covered_lines": 19, "num_statements": 84, "percent_covered": 22.61904761904762, "percent_covered_display": "23", "missing_lines": 65, "excluded_lines": 0}, "missing_lines": [36, 37, 38, 41, 42, 46, 47, 48, 49, 54, 57, 58, 60, 61, 62, 71, 72, 73, 74, 75, 76, 77, 78, 82, 83, 85, 89, 90, 91, 92, 93, 94, 95, 99, 100, 103, 106, 107, 108, 109, 113, 114, 117, 118, 119, 120, 129, 138, 147, 148, 149, 150, 151, 152, 153, 154, 155, 159, 160, 161, 162, 163, 164, 165, 166], "excluded_lines": [], "functions": {"KeyManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [36, 37, 38, 41, 42, 46, 47, 48, 49, 54, 57, 58, 60, 61, 62], "excluded_lines": []}, "KeyManager.initialize_bip85": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [71, 72, 73, 74, 75, 76, 77, 78], "excluded_lines": []}, "KeyManager.generate_nostr_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [82, 83, 85, 89, 90, 91, 92, 93, 94, 95], "excluded_lines": []}, "KeyManager.generate_v1_nostr_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [99, 100, 103, 106, 107, 108, 109], "excluded_lines": []}, "KeyManager.generate_legacy_nostr_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [113, 114, 117, 118, 119, 120], "excluded_lines": []}, "KeyManager.get_public_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [129], "excluded_lines": []}, "KeyManager.get_private_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [138], "excluded_lines": []}, "KeyManager.get_npub": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [147, 148, 149, 150, 151, 152, 153, 154, 155], "excluded_lines": []}, "KeyManager.get_nsec": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [159, 160, 161, 162, 163, 164, 165, 166], "excluded_lines": []}, "": {"executed_lines": [3, 4, 5, 7, 8, 9, 12, 13, 15, 18, 19, 21, 64, 80, 97, 111, 122, 131, 140, 157], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"KeyManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 65, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 65, "excluded_lines": 0}, "missing_lines": [36, 37, 38, 41, 42, 46, 47, 48, 49, 54, 57, 58, 60, 61, 62, 71, 72, 73, 74, 75, 76, 77, 78, 82, 83, 85, 89, 90, 91, 92, 93, 94, 95, 99, 100, 103, 106, 107, 108, 109, 113, 114, 117, 118, 119, 120, 129, 138, 147, 148, 149, 150, 151, 152, 153, 154, 155, 159, 160, 161, 162, 163, 164, 165, 166], "excluded_lines": []}, "": {"executed_lines": [3, 4, 5, 7, 8, 9, 12, 13, 15, 18, 19, 21, 64, 80, 97, 111, 122, 131, 140, 157], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/nostr/snapshot.py": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 25, 26, 29, 49, 62, 63, 65, 137, 221, 279, 312, 348, 394, 433, 437, 441], "summary": {"covered_lines": 29, "num_statements": 264, "percent_covered": 10.984848484848484, "percent_covered_display": "11", "missing_lines": 235, "excluded_lines": 11}, "missing_lines": [33, 34, 35, 36, 37, 45, 46, 57, 58, 59, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 90, 91, 92, 93, 96, 97, 99, 104, 105, 107, 108, 110, 120, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 140, 141, 142, 143, 144, 155, 156, 158, 159, 160, 162, 167, 168, 169, 170, 172, 173, 174, 175, 176, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 245, 246, 252, 253, 262, 263, 265, 266, 267, 268, 269, 277, 281, 282, 283, 284, 285, 286, 287, 290, 291, 292, 293, 294, 295, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 314, 315, 316, 317, 318, 319, 320, 321, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 349, 350, 351, 352, 353, 354, 355, 358, 359, 360, 361, 364, 365, 366, 367, 368, 369, 370, 381, 389, 390, 391, 392, 395, 396, 397, 398, 399, 405, 406, 407, 410, 411, 412, 413, 414, 415, 416, 420, 421, 422, 423, 424, 427, 430, 431, 434, 435, 438, 439, 442, 443], "excluded_lines": [236, 237, 238, 243, 254, 255, 256, 261, 270, 271, 272], "functions": {"prepare_snapshot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [33, 34, 35, 36, 37, 45, 46], "excluded_lines": []}, "new_manifest_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [57, 58, 59], "excluded_lines": []}, "SnapshotHandler.publish_snapshot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 0}, "missing_lines": [68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 90, 91, 92, 93, 96, 97, 99, 104, 105, 107, 108, 110, 120, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135], "excluded_lines": []}, "SnapshotHandler._fetch_chunks_with_retry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 57, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 57, "excluded_lines": 0}, "missing_lines": [140, 141, 142, 143, 144, 155, 156, 158, 159, 160, 162, 167, 168, 169, 170, 172, 173, 174, 175, 176, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219], "excluded_lines": []}, "SnapshotHandler._fetch_manifest_with_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 11}, "missing_lines": [225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 245, 246, 252, 253, 262, 263, 265, 266, 267, 268, 269, 277], "excluded_lines": [236, 237, 238, 243, 254, 255, 256, 261, 270, 271, 272]}, "SnapshotHandler.fetch_latest_snapshot": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 0}, "missing_lines": [281, 282, 283, 284, 285, 286, 287, 290, 291, 292, 293, 294, 295, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310], "excluded_lines": []}, "SnapshotHandler.ensure_manifest_is_current": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 27, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 27, "excluded_lines": 0}, "missing_lines": [314, 315, 316, 317, 318, 319, 320, 321, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346], "excluded_lines": []}, "SnapshotHandler.publish_delta": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [349, 350, 351, 352, 353, 354, 355, 358, 359, 360, 361, 364, 365, 366, 367, 368, 369, 370, 381, 389, 390, 391, 392], "excluded_lines": []}, "SnapshotHandler.fetch_deltas_since": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [395, 396, 397, 398, 399, 405, 406, 407, 410, 411, 412, 413, 414, 415, 416, 420, 421, 422, 423, 424, 427, 430, 431], "excluded_lines": []}, "SnapshotHandler.get_current_manifest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [434, 435], "excluded_lines": []}, "SnapshotHandler.get_current_manifest_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [438, 439], "excluded_lines": []}, "SnapshotHandler.get_delta_events": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [442, 443], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 25, 26, 29, 49, 62, 63, 65, 137, 221, 279, 312, 348, 394, 433, 437, 441], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"SnapshotHandler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 225, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 225, "excluded_lines": 11}, "missing_lines": [68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 90, 91, 92, 93, 96, 97, 99, 104, 105, 107, 108, 110, 120, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 140, 141, 142, 143, 144, 155, 156, 158, 159, 160, 162, 167, 168, 169, 170, 172, 173, 174, 175, 176, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 245, 246, 252, 253, 262, 263, 265, 266, 267, 268, 269, 277, 281, 282, 283, 284, 285, 286, 287, 290, 291, 292, 293, 294, 295, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 314, 315, 316, 317, 318, 319, 320, 321, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 349, 350, 351, 352, 353, 354, 355, 358, 359, 360, 361, 364, 365, 366, 367, 368, 369, 370, 381, 389, 390, 391, 392, 395, 396, 397, 398, 399, 405, 406, 407, 410, 411, 412, 413, 414, 415, 416, 420, 421, 422, 423, 424, 427, 430, 431, 434, 435, 438, 439, 442, 443], "excluded_lines": [236, 237, 238, 243, 254, 255, 256, 261, 270, 271, 272]}, "": {"executed_lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 25, 26, 29, 49, 62, 63, 65, 137, 221, 279, 312, 348, 394, 433, 437, 441], "summary": {"covered_lines": 29, "num_statements": 39, "percent_covered": 74.35897435897436, "percent_covered_display": "74", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [33, 34, 35, 36, 37, 45, 46, 57, 58, 59], "excluded_lines": []}}}, "src/seedpass/__init__.py": {"executed_lines": [1], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [1], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/api.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 20, 22, 23, 24, 25, 27, 28, 29, 31, 32, 33, 35, 36, 38, 41, 47, 56, 70, 104, 110, 123, 124, 143, 144, 159, 160, 279, 280, 310, 311, 321, 322, 332, 333, 345, 346, 379, 380, 400, 401, 409, 410, 420, 421, 431, 432, 446, 447, 460, 461, 486, 487, 496, 497, 513, 514, 520, 521, 529, 530, 551, 552, 571, 572, 586, 587, 597, 598, 608, 609, 625, 626, 668, 669, 694, 695, 706, 707, 732, 733, 743, 744], "summary": {"covered_lines": 95, "num_statements": 378, "percent_covered": 25.132275132275133, "percent_covered_display": "25", "missing_lines": 283, "excluded_lines": 0}, "missing_lines": [42, 43, 44, 48, 49, 50, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 89, 94, 95, 101, 105, 106, 107, 116, 117, 118, 119, 120, 127, 128, 129, 130, 150, 151, 152, 153, 154, 155, 156, 171, 172, 174, 176, 177, 187, 189, 197, 199, 200, 202, 214, 216, 217, 225, 227, 228, 238, 240, 241, 249, 251, 252, 259, 261, 262, 267, 274, 276, 291, 292, 293, 294, 305, 306, 307, 315, 316, 317, 318, 326, 327, 328, 329, 336, 337, 338, 340, 341, 342, 353, 354, 355, 356, 367, 369, 370, 372, 373, 375, 376, 384, 385, 386, 388, 390, 391, 392, 393, 394, 395, 396, 397, 404, 405, 406, 414, 415, 416, 417, 425, 426, 427, 428, 436, 437, 438, 440, 441, 442, 443, 453, 454, 455, 456, 457, 467, 468, 469, 470, 473, 474, 475, 476, 478, 480, 483, 491, 492, 493, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 515, 516, 517, 523, 524, 525, 526, 534, 535, 536, 538, 539, 540, 541, 543, 544, 545, 546, 547, 548, 556, 557, 558, 559, 561, 562, 563, 564, 565, 566, 567, 568, 576, 577, 578, 580, 581, 582, 583, 591, 592, 593, 594, 602, 603, 604, 605, 615, 616, 617, 618, 619, 620, 621, 622, 630, 631, 633, 635, 636, 637, 639, 640, 641, 642, 643, 644, 645, 646, 648, 650, 651, 653, 654, 656, 657, 658, 663, 664, 665, 676, 677, 678, 680, 682, 684, 686, 687, 688, 689, 690, 691, 699, 700, 701, 703, 711, 712, 713, 715, 725, 727, 728, 729, 737, 738, 739, 740, 747, 748, 750], "excluded_lines": [], "functions": {"_get_pm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [42, 43, 44], "excluded_lines": []}, "_check_token": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [48, 49, 50, 51, 52, 53], "excluded_lines": []}, "_reload_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [58, 59, 60, 61, 62, 63, 64, 65, 66, 67], "excluded_lines": []}, "start_server": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 89, 94, 95, 101], "excluded_lines": []}, "_require_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [105, 106, 107], "excluded_lines": []}, "_validate_encryption_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [116, 117, 118, 119, 120], "excluded_lines": []}, "search_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [127, 128, 129, 130], "excluded_lines": []}, "get_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [150, 151, 152, 153, 154, 155, 156], "excluded_lines": []}, "create_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 29, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 29, "excluded_lines": 0}, "missing_lines": [171, 172, 174, 176, 177, 187, 189, 197, 199, 200, 202, 214, 216, 217, 225, 227, 228, 238, 240, 241, 249, 251, 252, 259, 261, 262, 267, 274, 276], "excluded_lines": []}, "update_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [291, 292, 293, 294, 305, 306, 307], "excluded_lines": []}, "archive_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [315, 316, 317, 318], "excluded_lines": []}, "unarchive_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [326, 327, 328, 329], "excluded_lines": []}, "get_config": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [336, 337, 338, 340, 341, 342], "excluded_lines": []}, "update_config": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [353, 354, 355, 356, 367, 369, 370, 372, 373, 375, 376], "excluded_lines": []}, "set_secret_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [384, 385, 386, 388, 390, 391, 392, 393, 394, 395, 396, 397], "excluded_lines": []}, "list_fingerprints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [404, 405, 406], "excluded_lines": []}, "add_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [414, 415, 416, 417], "excluded_lines": []}, "remove_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [425, 426, 427, 428], "excluded_lines": []}, "select_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [436, 437, 438, 440, 441, 442, 443], "excluded_lines": []}, "export_totp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [453, 454, 455, 456, 457], "excluded_lines": []}, "get_totp_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [467, 468, 469, 470, 473, 474, 475, 476, 478, 480, 483], "excluded_lines": []}, "get_profile_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [491, 492, 493], "excluded_lines": []}, "get_notifications": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510], "excluded_lines": []}, "get_nostr_pubkey": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [515, 516, 517], "excluded_lines": []}, "list_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [523, 524, 525, 526], "excluded_lines": []}, "add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [534, 535, 536, 538, 539, 540, 541, 543, 544, 545, 546, 547, 548], "excluded_lines": []}, "remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [556, 557, 558, 559, 561, 562, 563, 564, 565, 566, 567, 568], "excluded_lines": []}, "reset_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [576, 577, 578, 580, 581, 582, 583], "excluded_lines": []}, "verify_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [591, 592, 593, 594], "excluded_lines": []}, "update_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [602, 603, 604, 605], "excluded_lines": []}, "export_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [615, 616, 617, 618, 619, 620, 621, 622], "excluded_lines": []}, "import_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [630, 631, 633, 635, 636, 637, 639, 640, 641, 642, 643, 644, 645, 646, 648, 650, 651, 653, 654, 656, 657, 658, 663, 664, 665], "excluded_lines": []}, "backup_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [676, 677, 678, 680, 682, 684, 686, 687, 688, 689, 690, 691], "excluded_lines": []}, "change_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [699, 700, 701, 703], "excluded_lines": []}, "generate_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [711, 712, 713, 715, 725, 727, 728, 729], "excluded_lines": []}, "lock_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [737, 738, 739, 740], "excluded_lines": []}, "shutdown_server": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [747, 748, 750], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 20, 22, 23, 24, 25, 27, 28, 29, 31, 32, 33, 35, 36, 38, 41, 47, 56, 70, 104, 110, 123, 124, 143, 144, 159, 160, 279, 280, 310, 311, 321, 322, 332, 333, 345, 346, 379, 380, 400, 401, 409, 410, 420, 421, 431, 432, 446, 447, 460, 461, 486, 487, 496, 497, 513, 514, 520, 521, 529, 530, 551, 552, 571, 572, 586, 587, 597, 598, 608, 609, 625, 626, 668, 669, 694, 695, 706, 707, 732, 733, 743, 744], "summary": {"covered_lines": 95, "num_statements": 95, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18, 20, 22, 23, 24, 25, 27, 28, 29, 31, 32, 33, 35, 36, 38, 41, 47, 56, 70, 104, 110, 123, 124, 143, 144, 159, 160, 279, 280, 310, 311, 321, 322, 332, 333, 345, 346, 379, 380, 400, 401, 409, 410, 420, 421, 431, 432, 446, 447, 460, 461, 486, 487, 496, 497, 513, 514, 520, 521, 529, 530, 551, 552, 571, 572, 586, 587, 597, 598, 608, 609, 625, 626, 668, 669, 694, 695, 706, 707, 732, 733, 743, 744], "summary": {"covered_lines": 95, "num_statements": 378, "percent_covered": 25.132275132275133, "percent_covered_display": "25", "missing_lines": 283, "excluded_lines": 0}, "missing_lines": [42, 43, 44, 48, 49, 50, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 89, 94, 95, 101, 105, 106, 107, 116, 117, 118, 119, 120, 127, 128, 129, 130, 150, 151, 152, 153, 154, 155, 156, 171, 172, 174, 176, 177, 187, 189, 197, 199, 200, 202, 214, 216, 217, 225, 227, 228, 238, 240, 241, 249, 251, 252, 259, 261, 262, 267, 274, 276, 291, 292, 293, 294, 305, 306, 307, 315, 316, 317, 318, 326, 327, 328, 329, 336, 337, 338, 340, 341, 342, 353, 354, 355, 356, 367, 369, 370, 372, 373, 375, 376, 384, 385, 386, 388, 390, 391, 392, 393, 394, 395, 396, 397, 404, 405, 406, 414, 415, 416, 417, 425, 426, 427, 428, 436, 437, 438, 440, 441, 442, 443, 453, 454, 455, 456, 457, 467, 468, 469, 470, 473, 474, 475, 476, 478, 480, 483, 491, 492, 493, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 515, 516, 517, 523, 524, 525, 526, 534, 535, 536, 538, 539, 540, 541, 543, 544, 545, 546, 547, 548, 556, 557, 558, 559, 561, 562, 563, 564, 565, 566, 567, 568, 576, 577, 578, 580, 581, 582, 583, 591, 592, 593, 594, 602, 603, 604, 605, 615, 616, 617, 618, 619, 620, 621, 622, 630, 631, 633, 635, 636, 637, 639, 640, 641, 642, 643, 644, 645, 646, 648, 650, 651, 653, 654, 656, 657, 658, 663, 664, 665, 676, 677, 678, 680, 682, 684, 686, 687, 688, 689, 690, 691, 699, 700, 701, 703, 711, 712, 713, 715, 725, 727, 728, 729, 737, 738, 739, 740, 747, 748, 750], "excluded_lines": []}}}, "src/seedpass/cli/__init__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 78, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 78, "excluded_lines": 2}, "missing_lines": [1, 3, 4, 5, 6, 7, 9, 11, 12, 14, 20, 27, 33, 40, 42, 43, 44, 45, 46, 47, 48, 51, 53, 54, 55, 56, 57, 60, 62, 63, 64, 65, 68, 69, 79, 84, 85, 86, 89, 90, 92, 93, 94, 97, 98, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 125, 129, 131, 132, 137, 139, 142, 143, 145, 150, 151, 162, 163, 164, 169, 171, 172, 176, 178, 180], "excluded_lines": [183, 184], "functions": {"run": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [53, 54, 55, 56, 57], "excluded_lines": []}, "_gui_backend_available": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [62, 63, 64, 65], "excluded_lines": []}, "main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [79, 84, 85, 86], "excluded_lines": []}, "root_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [92, 93, 94], "excluded_lines": []}, "gui": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 0}, "missing_lines": [111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 125, 129, 131, 132, 137, 139, 142, 143, 145, 150, 151, 162, 163, 164, 169, 171, 172, 176, 178, 180], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 29, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 29, "excluded_lines": 2}, "missing_lines": [1, 3, 4, 5, 6, 7, 9, 11, 12, 14, 20, 27, 33, 40, 42, 43, 44, 45, 46, 47, 48, 51, 60, 68, 69, 89, 90, 97, 98], "excluded_lines": [183, 184]}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 78, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 78, "excluded_lines": 2}, "missing_lines": [1, 3, 4, 5, 6, 7, 9, 11, 12, 14, 20, 27, 33, 40, 42, 43, 44, 45, 46, 47, 48, 51, 53, 54, 55, 56, 57, 60, 62, 63, 64, 65, 68, 69, 79, 84, 85, 86, 89, 90, 92, 93, 94, 97, 98, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 125, 129, 131, 132, 137, 139, 142, 143, 145, 150, 151, 162, 163, 164, 169, 171, 172, 176, 178, 180], "excluded_lines": [183, 184]}}}, "src/seedpass/cli/api.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 2}, "missing_lines": [1, 3, 4, 6, 8, 11, 12, 14, 15, 18, 21, 22, 28, 30, 31], "excluded_lines": [36, 37], "functions": {"api_start": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [14, 15, 18], "excluded_lines": []}, "api_stop": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 2}, "missing_lines": [28, 30, 31], "excluded_lines": [36, 37]}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [1, 3, 4, 6, 8, 11, 12, 21, 22], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 2}, "missing_lines": [1, 3, 4, 6, 8, 11, 12, 14, 15, 18, 21, 22, 28, 30, 31], "excluded_lines": [36, 37]}}}, "src/seedpass/cli/common.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 30, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 30, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 6, 7, 23, 25, 26, 27, 29, 30, 31, 32, 33, 34, 37, 42, 43, 46, 47, 48, 51, 52, 53, 56, 57, 58, 61, 62, 63], "excluded_lines": [], "functions": {"_get_pm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [25, 26, 27, 29, 30, 31, 32, 33, 34], "excluded_lines": []}, "_get_services": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [42, 43], "excluded_lines": []}, "_get_entry_service": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [47, 48], "excluded_lines": []}, "_get_config_service": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [52, 53], "excluded_lines": []}, "_get_util_service": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [57, 58], "excluded_lines": []}, "_get_nostr_service": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [62, 63], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 6, 7, 23, 37, 46, 51, 56, 61], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 30, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 30, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 6, 7, 23, 25, 26, 27, 29, 30, 31, 32, 33, 34, 37, 42, 43, 46, 47, 48, 51, 52, 53, 56, 57, 58, 61, 62, 63], "excluded_lines": []}}}, "src/seedpass/cli/config.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 62, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 62, "excluded_lines": 15}, "missing_lines": [1, 3, 5, 7, 10, 11, 13, 14, 15, 16, 18, 21, 22, 24, 26, 27, 32, 33, 34, 35, 40, 43, 44, 50, 51, 52, 53, 58, 59, 66, 67, 68, 69, 71, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 90, 91, 94, 95, 97, 98, 99, 104, 105, 112, 113, 114, 115, 117, 118, 123, 124], "excluded_lines": [36, 37, 38, 54, 55, 56, 86, 87, 88, 100, 101, 102, 119, 120, 121], "functions": {"config_get": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [13, 14, 15, 16, 18], "excluded_lines": []}, "config_set": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 3}, "missing_lines": [24, 26, 27, 32, 33, 34, 35, 40], "excluded_lines": [36, 37, 38]}, "config_toggle_secret_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 24, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 24, "excluded_lines": 6}, "missing_lines": [50, 51, 52, 53, 58, 59, 66, 67, 68, 69, 71, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 90, 91], "excluded_lines": [54, 55, 56, 86, 87, 88]}, "config_toggle_offline": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 6}, "missing_lines": [97, 98, 99, 104, 105, 112, 113, 114, 115, 117, 118, 123, 124], "excluded_lines": [100, 101, 102, 119, 120, 121]}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 7, 10, 11, 21, 22, 43, 44, 94, 95], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 62, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 62, "excluded_lines": 15}, "missing_lines": [1, 3, 5, 7, 10, 11, 13, 14, 15, 16, 18, 21, 22, 24, 26, 27, 32, 33, 34, 35, 40, 43, 44, 50, 51, 52, 53, 58, 59, 66, 67, 68, 69, 71, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 90, 91, 94, 95, 97, 98, 99, 104, 105, 112, 113, 114, 115, 117, 118, 123, 124], "excluded_lines": [36, 37, 38, 54, 55, 56, 86, 87, 88, 100, 101, 102, 119, 120, 121]}}}, "src/seedpass/cli/entry.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 156, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 156, "excluded_lines": 0}, "missing_lines": [1, 3, 4, 5, 6, 8, 9, 11, 12, 13, 15, 18, 19, 33, 34, 39, 40, 41, 42, 43, 44, 45, 46, 47, 50, 51, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 115, 118, 119, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 166, 167, 170, 171, 183, 184, 192, 195, 196, 203, 204, 209, 212, 213, 222, 223, 230, 233, 234, 241, 242, 247, 250, 251, 259, 260, 266, 269, 270, 278, 279, 280, 283, 284, 291, 292, 297, 300, 301, 316, 317, 318, 329, 330, 331, 332, 335, 336, 338, 339, 340, 343, 344, 346, 347, 348, 351, 352, 354, 355, 358, 359, 363, 364, 365, 366], "excluded_lines": [], "functions": {"entry_list": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [33, 34, 39, 40, 41, 42, 43, 44, 45, 46, 47], "excluded_lines": []}, "entry_search": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75], "excluded_lines": []}, "entry_get": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 29, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 29, "excluded_lines": 0}, "missing_lines": [81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 115], "excluded_lines": []}, "entry_add": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 166, 167], "excluded_lines": []}, "entry_add_totp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [183, 184, 192], "excluded_lines": []}, "entry_add_ssh": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [203, 204, 209], "excluded_lines": []}, "entry_add_pgp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [222, 223, 230], "excluded_lines": []}, "entry_add_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [241, 242, 247], "excluded_lines": []}, "entry_add_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [259, 260, 266], "excluded_lines": []}, "entry_add_key_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [278, 279, 280], "excluded_lines": []}, "entry_add_managed_account": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [291, 292, 297], "excluded_lines": []}, "entry_modify": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [316, 317, 318, 329, 330, 331, 332], "excluded_lines": []}, "entry_archive": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [338, 339, 340], "excluded_lines": []}, "entry_unarchive": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [346, 347, 348], "excluded_lines": []}, "entry_totp_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [354, 355], "excluded_lines": []}, "entry_export_totp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [363, 364, 365, 366], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 43, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 43, "excluded_lines": 0}, "missing_lines": [1, 3, 4, 5, 6, 8, 9, 11, 12, 13, 15, 18, 19, 50, 51, 78, 79, 118, 119, 170, 171, 195, 196, 212, 213, 233, 234, 250, 251, 269, 270, 283, 284, 300, 301, 335, 336, 343, 344, 351, 352, 358, 359], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 156, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 156, "excluded_lines": 0}, "missing_lines": [1, 3, 4, 5, 6, 8, 9, 11, 12, 13, 15, 18, 19, 33, 34, 39, 40, 41, 42, 43, 44, 45, 46, 47, 50, 51, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 115, 118, 119, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 166, 167, 170, 171, 183, 184, 192, 195, 196, 203, 204, 209, 212, 213, 222, 223, 230, 233, 234, 241, 242, 247, 250, 251, 259, 260, 266, 269, 270, 278, 279, 280, 283, 284, 291, 292, 297, 300, 301, 316, 317, 318, 329, 330, 331, 332, 335, 336, 338, 339, 340, 343, 344, 346, 347, 348, 351, 352, 354, 355, 358, 359, 363, 364, 365, 366], "excluded_lines": []}}}, "src/seedpass/cli/fingerprint.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 7, 10, 11, 13, 14, 15, 18, 19, 21, 22, 25, 26, 28, 29, 32, 33, 35, 36, 37], "excluded_lines": [], "functions": {"fingerprint_list": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [13, 14, 15], "excluded_lines": []}, "fingerprint_add": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [21, 22], "excluded_lines": []}, "fingerprint_remove": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [28, 29], "excluded_lines": []}, "fingerprint_switch": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [35, 36, 37], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 7, 10, 11, 18, 19, 25, 26, 32, 33], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 7, 10, 11, 13, 14, 15, 18, 19, 21, 22, 25, 26, 28, 29, 32, 33, 35, 36, 37], "excluded_lines": []}}}, "src/seedpass/cli/nostr.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 39, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 39, "excluded_lines": 6}, "missing_lines": [1, 3, 5, 7, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 28, 29, 31, 32, 33, 36, 37, 39, 40, 41, 42, 45, 46, 48, 49, 50, 54, 57, 58, 60, 61, 62, 66], "excluded_lines": [51, 52, 53, 63, 64, 65], "functions": {"nostr_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [15, 16, 17, 18, 19, 20, 21, 22, 23, 25], "excluded_lines": []}, "nostr_get_pubkey": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [31, 32, 33], "excluded_lines": []}, "nostr_list_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [39, 40, 41, 42], "excluded_lines": []}, "nostr_add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 3}, "missing_lines": [48, 49, 50, 54], "excluded_lines": [51, 52, 53]}, "nostr_remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 3}, "missing_lines": [60, 61, 62, 66], "excluded_lines": [63, 64, 65]}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 7, 12, 13, 28, 29, 36, 37, 45, 46, 57, 58], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 39, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 39, "excluded_lines": 6}, "missing_lines": [1, 3, 5, 7, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 28, 29, 31, 32, 33, 36, 37, 39, 40, 41, 42, 45, 46, 48, 49, 50, 54, 57, 58, 60, 61, 62, 66], "excluded_lines": [51, 52, 53, 63, 64, 65]}}}, "src/seedpass/cli/util.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 35, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 35, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 7, 9, 12, 13, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 57, 58, 61, 62, 64, 65, 68, 69, 71, 72], "excluded_lines": [], "functions": {"generate_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 57, 58], "excluded_lines": []}, "verify_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [64, 65], "excluded_lines": []}, "update_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [71, 72], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 7, 9, 12, 13, 61, 62, 68, 69], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 35, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 35, "excluded_lines": 0}, "missing_lines": [1, 3, 5, 7, 9, 12, 13, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 57, 58, 61, 62, 64, 65, 68, 69, 71, 72], "excluded_lines": []}}}, "src/seedpass/cli/vault.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 49, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 49, "excluded_lines": 6}, "missing_lines": [1, 3, 4, 5, 7, 9, 16, 19, 20, 24, 25, 26, 27, 30, 31, 35, 36, 37, 38, 41, 42, 44, 45, 46, 47, 48, 54, 57, 58, 60, 61, 62, 63, 67, 70, 71, 73, 74, 75, 78, 79, 81, 82, 83, 86, 87, 94, 95, 96], "excluded_lines": [51, 52, 53, 64, 65, 66], "functions": {"vault_export": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [24, 25, 26, 27], "excluded_lines": []}, "vault_import": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [35, 36, 37, 38], "excluded_lines": []}, "vault_change_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 3}, "missing_lines": [44, 45, 46, 47, 48, 54], "excluded_lines": [51, 52, 53]}, "vault_unlock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 3}, "missing_lines": [60, 61, 62, 63, 67], "excluded_lines": [64, 65, 66]}, "vault_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [73, 74, 75], "excluded_lines": []}, "vault_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [81, 82, 83], "excluded_lines": []}, "vault_reveal_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [94, 95, 96], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [1, 3, 4, 5, 7, 9, 16, 19, 20, 30, 31, 41, 42, 57, 58, 70, 71, 78, 79, 86, 87], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 49, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 49, "excluded_lines": 6}, "missing_lines": [1, 3, 4, 5, 7, 9, 16, 19, 20, 24, 25, 26, 27, 30, 31, 35, 36, 37, 38, 41, 42, 44, 45, 46, 47, 48, 54, 57, 58, 60, 61, 62, 63, 67, 70, 71, 73, 74, 75, 78, 79, 81, 82, 83, 86, 87, 94, 95, 96], "excluded_lines": [51, 52, 53, 64, 65, 66]}}}, "src/seedpass/core/__init__.py": {"executed_lines": [3, 5, 7, 17, 18, 20, 22, 24, 26, 28, 30], "summary": {"covered_lines": 10, "num_statements": 16, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [19, 21, 23, 25, 27, 29], "excluded_lines": [], "functions": {"__getattr__": {"executed_lines": [18, 20, 22, 24, 26, 28, 30], "summary": {"covered_lines": 7, "num_statements": 13, "percent_covered": 53.84615384615385, "percent_covered_display": "54", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [19, 21, 23, 25, 27, 29], "excluded_lines": []}, "": {"executed_lines": [3, 5, 7, 17], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 5, 7, 17, 18, 20, 22, 24, 26, 28, 30], "summary": {"covered_lines": 10, "num_statements": 16, "percent_covered": 62.5, "percent_covered_display": "62", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [19, 21, 23, 25, 27, 29], "excluded_lines": []}}}, "src/seedpass/core/api.py": {"executed_lines": [1, 3, 10, 11, 12, 13, 14, 16, 18, 19, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 41, 42, 44, 45, 48, 49, 51, 54, 55, 57, 60, 61, 63, 64, 67, 68, 70, 71, 74, 75, 77, 80, 81, 83, 84, 85, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 108, 109, 112, 113, 116, 117, 119, 123, 130, 137, 147, 158, 164, 171, 177, 185, 192, 193, 195, 199, 205, 214, 220, 227, 228, 230, 234, 245, 251, 258, 259, 261, 265, 278, 294, 298, 306, 313, 358, 382, 399, 420, 437, 456, 466, 483, 510, 515, 520, 527, 532, 533, 535, 539, 543, 597, 601, 605, 613, 617, 624, 625, 627, 631, 676, 680, 685, 686, 688, 692, 696, 700, 707], "summary": {"covered_lines": 116, "num_statements": 325, "percent_covered": 35.69230769230769, "percent_covered_display": "36", "missing_lines": 209, "excluded_lines": 0}, "missing_lines": [120, 121, 126, 127, 128, 133, 134, 135, 140, 141, 142, 145, 150, 151, 154, 155, 156, 161, 162, 167, 168, 169, 174, 175, 180, 181, 188, 189, 196, 197, 202, 203, 208, 209, 210, 217, 218, 223, 224, 231, 232, 237, 238, 239, 240, 241, 242, 243, 248, 249, 254, 255, 262, 263, 271, 272, 291, 292, 295, 296, 299, 300, 301, 302, 303, 304, 307, 308, 311, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 355, 356, 368, 369, 370, 379, 380, 389, 390, 396, 397, 408, 409, 417, 418, 427, 428, 434, 435, 445, 446, 453, 454, 459, 460, 463, 464, 473, 474, 480, 481, 496, 497, 508, 511, 512, 513, 516, 517, 518, 521, 522, 525, 528, 529, 536, 537, 540, 541, 544, 545, 581, 582, 583, 584, 585, 586, 587, 592, 593, 595, 598, 599, 602, 603, 606, 607, 608, 609, 610, 611, 614, 615, 618, 619, 620, 621, 628, 629, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 665, 666, 670, 671, 673, 674, 677, 678, 681, 682, 689, 690, 693, 694, 697, 698, 701, 702, 703, 708, 709, 710], "excluded_lines": [], "functions": {"VaultService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [120, 121], "excluded_lines": []}, "VaultService.export_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [126, 127, 128], "excluded_lines": []}, "VaultService.import_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [133, 134, 135], "excluded_lines": []}, "VaultService.export_profile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [140, 141, 142, 145], "excluded_lines": []}, "VaultService.import_profile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [150, 151, 154, 155, 156], "excluded_lines": []}, "VaultService.change_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [161, 162], "excluded_lines": []}, "VaultService.unlock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [167, 168, 169], "excluded_lines": []}, "VaultService.lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [174, 175], "excluded_lines": []}, "VaultService.backup_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [180, 181], "excluded_lines": []}, "VaultService.stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [188, 189], "excluded_lines": []}, "ProfileService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [196, 197], "excluded_lines": []}, "ProfileService.list_profiles": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [202, 203], "excluded_lines": []}, "ProfileService.add_profile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [208, 209, 210], "excluded_lines": []}, "ProfileService.remove_profile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [217, 218], "excluded_lines": []}, "ProfileService.switch_profile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [223, 224], "excluded_lines": []}, "SyncService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [231, 232], "excluded_lines": []}, "SyncService.sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [237, 238, 239, 240, 241, 242, 243], "excluded_lines": []}, "SyncService.start_background_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [248, 249], "excluded_lines": []}, "SyncService.start_background_vault_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [254, 255], "excluded_lines": []}, "EntryService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [262, 263], "excluded_lines": []}, "EntryService.list_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [271, 272], "excluded_lines": []}, "EntryService.search_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [291, 292], "excluded_lines": []}, "EntryService.retrieve_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [295, 296], "excluded_lines": []}, "EntryService.generate_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [299, 300, 301, 302, 303, 304], "excluded_lines": []}, "EntryService.get_totp_code": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [307, 308, 311], "excluded_lines": []}, "EntryService.add_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 355, 356], "excluded_lines": []}, "EntryService.add_totp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [368, 369, 370, 379, 380], "excluded_lines": []}, "EntryService.add_ssh_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [389, 390, 396, 397], "excluded_lines": []}, "EntryService.add_pgp_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [408, 409, 417, 418], "excluded_lines": []}, "EntryService.add_nostr_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [427, 428, 434, 435], "excluded_lines": []}, "EntryService.add_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [445, 446, 453, 454], "excluded_lines": []}, "EntryService.add_key_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [459, 460, 463, 464], "excluded_lines": []}, "EntryService.add_managed_account": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [473, 474, 480, 481], "excluded_lines": []}, "EntryService.modify_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [496, 497, 508], "excluded_lines": []}, "EntryService.archive_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [511, 512, 513], "excluded_lines": []}, "EntryService.restore_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [516, 517, 518], "excluded_lines": []}, "EntryService.export_totp_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [521, 522, 525], "excluded_lines": []}, "EntryService.display_totp_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [528, 529], "excluded_lines": []}, "ConfigService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [536, 537], "excluded_lines": []}, "ConfigService.get": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [540, 541], "excluded_lines": []}, "ConfigService.set": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [544, 545, 581, 582, 583, 584, 585, 586, 587, 592, 593, 595], "excluded_lines": []}, "ConfigService.get_secret_mode_enabled": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [598, 599], "excluded_lines": []}, "ConfigService.get_clipboard_clear_delay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [602, 603], "excluded_lines": []}, "ConfigService.set_secret_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [606, 607, 608, 609, 610, 611], "excluded_lines": []}, "ConfigService.get_offline_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [614, 615], "excluded_lines": []}, "ConfigService.set_offline_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [618, 619, 620, 621], "excluded_lines": []}, "UtilityService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [628, 629], "excluded_lines": []}, "UtilityService.generate_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 0}, "missing_lines": [644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 665, 666, 670, 671, 673, 674], "excluded_lines": []}, "UtilityService.verify_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [677, 678], "excluded_lines": []}, "UtilityService.update_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [681, 682], "excluded_lines": []}, "NostrService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [689, 690], "excluded_lines": []}, "NostrService.get_pubkey": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [693, 694], "excluded_lines": []}, "NostrService.list_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [697, 698], "excluded_lines": []}, "NostrService.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [701, 702, 703], "excluded_lines": []}, "NostrService.remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [708, 709, 710], "excluded_lines": []}, "": {"executed_lines": [1, 3, 10, 11, 12, 13, 14, 16, 18, 19, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 41, 42, 44, 45, 48, 49, 51, 54, 55, 57, 60, 61, 63, 64, 67, 68, 70, 71, 74, 75, 77, 80, 81, 83, 84, 85, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 108, 109, 112, 113, 116, 117, 119, 123, 130, 137, 147, 158, 164, 171, 177, 185, 192, 193, 195, 199, 205, 214, 220, 227, 228, 230, 234, 245, 251, 258, 259, 261, 265, 278, 294, 298, 306, 313, 358, 382, 399, 420, 437, 456, 466, 483, 510, 515, 520, 527, 532, 533, 535, 539, 543, 597, 601, 605, 613, 617, 624, 625, 627, 631, 676, 680, 685, 686, 688, 692, 696, 700, 707], "summary": {"covered_lines": 116, "num_statements": 116, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"VaultExportRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultExportResponse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultImportRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ChangePasswordRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "UnlockRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "UnlockResponse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "BackupParentSeedRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileSwitchRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "ProfileRemoveRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "SyncResponse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordPolicyOptions": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AddPasswordEntryRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "GeneratePasswordRequest": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "GeneratePasswordResponse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "VaultService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 28, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 28, "excluded_lines": 0}, "missing_lines": [120, 121, 126, 127, 128, 133, 134, 135, 140, 141, 142, 145, 150, 151, 154, 155, 156, 161, 162, 167, 168, 169, 174, 175, 180, 181, 188, 189], "excluded_lines": []}, "ProfileService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [196, 197, 202, 203, 208, 209, 210, 217, 218, 223, 224], "excluded_lines": []}, "SyncService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [231, 232, 237, 238, 239, 240, 241, 242, 243, 248, 249, 254, 255], "excluded_lines": []}, "EntryService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 81, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 81, "excluded_lines": 0}, "missing_lines": [262, 263, 271, 272, 291, 292, 295, 296, 299, 300, 301, 302, 303, 304, 307, 308, 311, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 348, 355, 356, 368, 369, 370, 379, 380, 389, 390, 396, 397, 408, 409, 417, 418, 427, 428, 434, 435, 445, 446, 453, 454, 459, 460, 463, 464, 473, 474, 480, 481, 496, 497, 508, 511, 512, 513, 516, 517, 518, 521, 522, 525, 528, 529], "excluded_lines": []}, "ConfigService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 32, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 32, "excluded_lines": 0}, "missing_lines": [536, 537, 540, 541, 544, 545, 581, 582, 583, 584, 585, 586, 587, 592, 593, 595, 598, 599, 602, 603, 606, 607, 608, 609, 610, 611, 614, 615, 618, 619, 620, 621], "excluded_lines": []}, "UtilityService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 32, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 32, "excluded_lines": 0}, "missing_lines": [628, 629, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 665, 666, 670, 671, 673, 674, 677, 678, 681, 682], "excluded_lines": []}, "NostrService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [689, 690, 693, 694, 697, 698, 701, 702, 703, 708, 709, 710], "excluded_lines": []}, "": {"executed_lines": [1, 3, 10, 11, 12, 13, 14, 16, 18, 19, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 41, 42, 44, 45, 48, 49, 51, 54, 55, 57, 60, 61, 63, 64, 67, 68, 70, 71, 74, 75, 77, 80, 81, 83, 84, 85, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 108, 109, 112, 113, 116, 117, 119, 123, 130, 137, 147, 158, 164, 171, 177, 185, 192, 193, 195, 199, 205, 214, 220, 227, 228, 230, 234, 245, 251, 258, 259, 261, 265, 278, 294, 298, 306, 313, 358, 382, 399, 420, 437, 456, 466, 483, 510, 515, 520, 527, 532, 533, 535, 539, 543, 597, 601, 605, 613, 617, 624, 625, 627, 631, 676, 680, 685, 686, 688, 692, 696, 700, 707], "summary": {"covered_lines": 116, "num_statements": 116, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/backup.py": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 23, 24, 27, 30, 31, 39, 41, 61, 95, 114, 148, 170, 193], "summary": {"covered_lines": 19, "num_statements": 116, "percent_covered": 16.379310344827587, "percent_covered_display": "16", "missing_lines": 97, "excluded_lines": 2}, "missing_lines": [51, 52, 53, 54, 55, 56, 57, 62, 63, 64, 65, 66, 72, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 89, 90, 91, 92, 93, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 115, 116, 122, 123, 124, 125, 127, 128, 129, 130, 131, 132, 137, 138, 141, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 164, 171, 172, 178, 179, 180, 181, 183, 184, 185, 188, 189, 190, 191, 194, 195, 197, 198, 199, 200, 202, 203, 206, 207, 208, 209, 210, 215, 216, 219], "excluded_lines": [108, 109], "functions": {"BackupManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [51, 52, 53, 54, 55, 56, 57], "excluded_lines": []}, "BackupManager.create_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [62, 63, 64, 65, 66, 72, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 89, 90, 91, 92, 93], "excluded_lines": []}, "BackupManager._create_additional_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 2}, "missing_lines": [97, 98, 99, 101, 102, 103, 104, 105, 106, 107], "excluded_lines": [108, 109]}, "BackupManager.restore_latest_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [115, 116, 122, 123, 124, 125, 127, 128, 129, 130, 131, 132, 137, 138, 141], "excluded_lines": []}, "BackupManager.restore_from_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 164], "excluded_lines": []}, "BackupManager.list_backups": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [171, 172, 178, 179, 180, 181, 183, 184, 185, 188, 189, 190, 191], "excluded_lines": []}, "BackupManager.restore_backup_by_timestamp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [194, 195, 197, 198, 199, 200, 202, 203, 206, 207, 208, 209, 210, 215, 216, 219], "excluded_lines": []}, "": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 23, 24, 27, 30, 31, 39, 41, 61, 95, 114, 148, 170, 193], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"BackupManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 97, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 97, "excluded_lines": 2}, "missing_lines": [51, 52, 53, 54, 55, 56, 57, 62, 63, 64, 65, 66, 72, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 89, 90, 91, 92, 93, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 115, 116, 122, 123, 124, 125, 127, 128, 129, 130, 131, 132, 137, 138, 141, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 164, 171, 172, 178, 179, 180, 181, 183, 184, 185, 188, 189, 190, 191, 194, 195, 197, 198, 199, 200, 202, 203, 206, 207, 208, 209, 210, 215, 216, 219], "excluded_lines": [108, 109]}, "": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 23, 24, 27, 30, 31, 39, 41, 61, 95, 114, 148, 170, 193], "summary": {"covered_lines": 19, "num_statements": 19, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/config_manager.py": {"executed_lines": [1, 3, 5, 6, 7, 9, 11, 13, 14, 16, 18, 21, 24, 25, 27, 29, 34, 120, 129, 137, 144, 152, 159, 165, 173, 178, 186, 191, 199, 204, 212, 217, 223, 229, 235, 241, 246, 251, 259, 264, 272, 278, 294, 299, 304, 309, 314, 320, 326, 332, 338, 344, 349, 357, 362, 370, 375, 380], "summary": {"covered_lines": 55, "num_statements": 241, "percent_covered": 22.821576763485478, "percent_covered_display": "23", "missing_lines": 186, "excluded_lines": 2}, "missing_lines": [30, 31, 32, 43, 44, 45, 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 114, 115, 116, 117, 118, 122, 123, 124, 125, 126, 127, 131, 132, 133, 134, 135, 139, 140, 141, 142, 146, 147, 148, 149, 150, 154, 155, 156, 157, 161, 162, 163, 167, 168, 169, 170, 171, 175, 176, 180, 181, 182, 183, 184, 188, 189, 193, 194, 195, 196, 197, 201, 202, 206, 207, 208, 209, 210, 214, 215, 219, 220, 221, 225, 226, 227, 231, 232, 233, 237, 238, 239, 243, 244, 248, 249, 253, 254, 255, 256, 257, 261, 262, 266, 267, 268, 269, 270, 274, 275, 280, 282, 283, 295, 296, 297, 300, 301, 302, 305, 306, 307, 310, 311, 312, 316, 317, 318, 322, 323, 324, 328, 329, 330, 334, 335, 336, 340, 341, 342, 346, 347, 351, 352, 353, 354, 355, 359, 360, 364, 365, 366, 367, 368, 372, 373, 376, 377, 378, 381, 382], "excluded_lines": [18, 19], "functions": {"ConfigManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [30, 31, 32], "excluded_lines": []}, "ConfigManager.load_config": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 47, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 47, "excluded_lines": 0}, "missing_lines": [43, 44, 45, 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 114, 115, 116, 117, 118], "excluded_lines": []}, "ConfigManager.save_config": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [122, 123, 124, 125, 126, 127], "excluded_lines": []}, "ConfigManager.set_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [131, 132, 133, 134, 135], "excluded_lines": []}, "ConfigManager.set_pin": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [139, 140, 141, 142], "excluded_lines": []}, "ConfigManager.verify_pin": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [146, 147, 148, 149, 150], "excluded_lines": []}, "ConfigManager.change_pin": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [154, 155, 156, 157], "excluded_lines": []}, "ConfigManager.set_password_hash": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [161, 162, 163], "excluded_lines": []}, "ConfigManager.set_inactivity_timeout": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [167, 168, 169, 170, 171], "excluded_lines": []}, "ConfigManager.get_inactivity_timeout": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [175, 176], "excluded_lines": []}, "ConfigManager.set_kdf_iterations": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [180, 181, 182, 183, 184], "excluded_lines": []}, "ConfigManager.get_kdf_iterations": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [188, 189], "excluded_lines": []}, "ConfigManager.set_kdf_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [193, 194, 195, 196, 197], "excluded_lines": []}, "ConfigManager.get_kdf_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [201, 202], "excluded_lines": []}, "ConfigManager.set_argon2_time_cost": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [206, 207, 208, 209, 210], "excluded_lines": []}, "ConfigManager.get_argon2_time_cost": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [214, 215], "excluded_lines": []}, "ConfigManager.set_additional_backup_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [219, 220, 221], "excluded_lines": []}, "ConfigManager.get_additional_backup_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [225, 226, 227], "excluded_lines": []}, "ConfigManager.set_secret_mode_enabled": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [231, 232, 233], "excluded_lines": []}, "ConfigManager.set_offline_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [237, 238, 239], "excluded_lines": []}, "ConfigManager.get_secret_mode_enabled": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [243, 244], "excluded_lines": []}, "ConfigManager.get_offline_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [248, 249], "excluded_lines": []}, "ConfigManager.set_clipboard_clear_delay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [253, 254, 255, 256, 257], "excluded_lines": []}, "ConfigManager.get_clipboard_clear_delay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [261, 262], "excluded_lines": []}, "ConfigManager.set_backup_interval": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [266, 267, 268, 269, 270], "excluded_lines": []}, "ConfigManager.get_backup_interval": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [274, 275], "excluded_lines": []}, "ConfigManager.get_password_policy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [280, 282, 283], "excluded_lines": []}, "ConfigManager.set_min_uppercase": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [295, 296, 297], "excluded_lines": []}, "ConfigManager.set_min_lowercase": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [300, 301, 302], "excluded_lines": []}, "ConfigManager.set_min_digits": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [305, 306, 307], "excluded_lines": []}, "ConfigManager.set_min_special": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [310, 311, 312], "excluded_lines": []}, "ConfigManager.set_include_special_chars": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [316, 317, 318], "excluded_lines": []}, "ConfigManager.set_allowed_special_chars": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [322, 323, 324], "excluded_lines": []}, "ConfigManager.set_special_mode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [328, 329, 330], "excluded_lines": []}, "ConfigManager.set_exclude_ambiguous": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [334, 335, 336], "excluded_lines": []}, "ConfigManager.set_quick_unlock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [340, 341, 342], "excluded_lines": []}, "ConfigManager.get_quick_unlock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [346, 347], "excluded_lines": []}, "ConfigManager.set_nostr_max_retries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [351, 352, 353, 354, 355], "excluded_lines": []}, "ConfigManager.get_nostr_max_retries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [359, 360], "excluded_lines": []}, "ConfigManager.set_nostr_retry_delay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [364, 365, 366, 367, 368], "excluded_lines": []}, "ConfigManager.get_nostr_retry_delay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [372, 373], "excluded_lines": []}, "ConfigManager.set_verbose_timing": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [376, 377, 378], "excluded_lines": []}, "ConfigManager.get_verbose_timing": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [381, 382], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 9, 11, 13, 14, 16, 18, 21, 24, 25, 27, 29, 34, 120, 129, 137, 144, 152, 159, 165, 173, 178, 186, 191, 199, 204, 212, 217, 223, 229, 235, 241, 246, 251, 259, 264, 272, 278, 294, 299, 304, 309, 314, 320, 326, 332, 338, 344, 349, 357, 362, 370, 375, 380], "summary": {"covered_lines": 55, "num_statements": 55, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [18, 19]}}, "classes": {"ConfigManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 186, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 186, "excluded_lines": 0}, "missing_lines": [30, 31, 32, 43, 44, 45, 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 114, 115, 116, 117, 118, 122, 123, 124, 125, 126, 127, 131, 132, 133, 134, 135, 139, 140, 141, 142, 146, 147, 148, 149, 150, 154, 155, 156, 157, 161, 162, 163, 167, 168, 169, 170, 171, 175, 176, 180, 181, 182, 183, 184, 188, 189, 193, 194, 195, 196, 197, 201, 202, 206, 207, 208, 209, 210, 214, 215, 219, 220, 221, 225, 226, 227, 231, 232, 233, 237, 238, 239, 243, 244, 248, 249, 253, 254, 255, 256, 257, 261, 262, 266, 267, 268, 269, 270, 274, 275, 280, 282, 283, 295, 296, 297, 300, 301, 302, 305, 306, 307, 310, 311, 312, 316, 317, 318, 322, 323, 324, 328, 329, 330, 334, 335, 336, 340, 341, 342, 346, 347, 351, 352, 353, 354, 355, 359, 360, 364, 365, 366, 367, 368, 372, 373, 376, 377, 378, 381, 382], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 9, 11, 13, 14, 16, 18, 21, 24, 25, 27, 29, 34, 120, 129, 137, 144, 152, 159, 165, 173, 178, 186, 191, 199, 204, 212, 217, 223, 229, 235, 241, 246, 251, 259, 264, 272, 278, 294, 299, 304, 309, 314, 320, 326, 332, 338, 344, 349, 357, 362, 370, 375, 380], "summary": {"covered_lines": 55, "num_statements": 55, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [18, 19]}}}, "src/seedpass/core/encryption.py": {"executed_lines": [3, 4, 6, 7, 9, 10, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 35, 38, 45, 46, 48, 56, 57, 62, 99, 117, 206, 247, 271, 279, 297, 303, 330, 347, 355, 363, 379, 441, 450, 560, 603, 619], "summary": {"covered_lines": 46, "num_statements": 343, "percent_covered": 13.411078717201166, "percent_covered_display": "13", "missing_lines": 297, "excluded_lines": 23}, "missing_lines": [40, 41, 42, 49, 52, 53, 71, 72, 74, 75, 76, 79, 80, 82, 83, 85, 86, 87, 91, 94, 95, 97, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 131, 133, 135, 136, 137, 138, 139, 140, 141, 144, 145, 146, 147, 152, 153, 154, 155, 156, 157, 158, 161, 162, 163, 166, 167, 168, 171, 172, 173, 176, 181, 182, 183, 184, 185, 188, 192, 193, 198, 199, 200, 211, 212, 213, 214, 215, 218, 219, 220, 221, 222, 223, 225, 228, 234, 237, 240, 241, 266, 267, 268, 269, 275, 276, 277, 281, 282, 283, 285, 286, 289, 291, 292, 293, 295, 298, 299, 300, 301, 311, 312, 313, 315, 316, 317, 318, 319, 320, 325, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 348, 349, 350, 351, 352, 353, 356, 357, 358, 359, 360, 361, 370, 371, 372, 373, 375, 376, 377, 386, 387, 388, 389, 390, 391, 392, 395, 397, 398, 399, 401, 402, 405, 407, 408, 411, 412, 414, 417, 418, 419, 420, 421, 423, 424, 425, 426, 427, 428, 429, 436, 437, 438, 439, 442, 443, 444, 445, 446, 447, 448, 470, 471, 473, 474, 475, 477, 478, 479, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 496, 497, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 512, 515, 516, 517, 518, 521, 527, 528, 529, 530, 531, 535, 541, 542, 543, 562, 563, 564, 565, 566, 568, 569, 570, 571, 572, 575, 576, 579, 580, 581, 582, 583, 584, 589, 590, 591, 592, 593, 594, 595, 596, 597, 601, 609, 610, 611, 612, 613, 614, 615, 616, 617, 620, 621, 622, 623, 625, 626, 627, 628, 630, 631, 632, 633, 634, 635, 636], "excluded_lines": [11, 12, 13, 15, 201, 202, 229, 230, 238, 239, 321, 322, 430, 431, 432, 433, 544, 545, 546, 550, 556, 557, 558], "functions": {"_derive_legacy_key_from_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [40, 41, 42], "excluded_lines": []}, "LegacyFormatRequiresMigrationError.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [49, 52, 53], "excluded_lines": []}, "EncryptionManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [71, 72, 74, 75, 76, 79, 80, 82, 83, 85, 86, 87, 91, 94, 95, 97], "excluded_lines": []}, "EncryptionManager.encrypt_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115], "excluded_lines": []}, "EncryptionManager.decrypt_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 2}, "missing_lines": [131, 133, 135, 136, 137, 138, 139, 140, 141, 144, 145, 146, 147, 152, 153, 154, 155, 156, 157, 158, 161, 162, 163, 166, 167, 168, 171, 172, 173, 176, 181, 182, 183, 184, 185, 188, 192, 193, 198, 199, 200], "excluded_lines": [201, 202]}, "EncryptionManager.decrypt_legacy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 4}, "missing_lines": [211, 212, 213, 214, 215, 218, 219, 220, 221, 222, 223, 225, 228, 234, 237, 240, 241], "excluded_lines": [229, 230, 238, 239]}, "EncryptionManager.resolve_relative_path": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [266, 267, 268, 269], "excluded_lines": []}, "EncryptionManager.encrypt_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [275, 276, 277], "excluded_lines": []}, "EncryptionManager.decrypt_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [281, 282, 283, 285, 286, 289, 291, 292, 293, 295], "excluded_lines": []}, "EncryptionManager._serialize": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [298, 299, 300, 301], "excluded_lines": []}, "EncryptionManager._deserialize": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 2}, "missing_lines": [311, 312, 313, 315, 316, 317, 318, 319, 320, 325], "excluded_lines": [321, 322]}, "EncryptionManager.encrypt_and_save_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345], "excluded_lines": []}, "EncryptionManager.decrypt_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [348, 349, 350, 351, 352, 353], "excluded_lines": []}, "EncryptionManager.get_file_kdf": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [356, 357, 358, 359, 360, 361], "excluded_lines": []}, "EncryptionManager.save_json_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [370, 371, 372, 373, 375, 376, 377], "excluded_lines": []}, "EncryptionManager.load_json_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 35, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 35, "excluded_lines": 4}, "missing_lines": [386, 387, 388, 389, 390, 391, 392, 395, 397, 398, 399, 401, 402, 405, 407, 408, 411, 412, 414, 417, 418, 419, 420, 421, 423, 424, 425, 426, 427, 428, 429, 436, 437, 438, 439], "excluded_lines": [430, 431, 432, 433]}, "EncryptionManager.get_encrypted_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [442, 443, 444, 445, 446, 447, 448], "excluded_lines": []}, "EncryptionManager.decrypt_and_save_index_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 32, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 32, "excluded_lines": 7}, "missing_lines": [470, 471, 473, 474, 475, 477, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 512, 515, 516, 517, 518, 521, 527, 528, 529, 530, 531, 535, 541, 542, 543], "excluded_lines": [544, 545, 546, 550, 556, 557, 558]}, "EncryptionManager.decrypt_and_save_index_from_nostr._process": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [478, 479, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 496, 497], "excluded_lines": []}, "EncryptionManager.update_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 28, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 28, "excluded_lines": 0}, "missing_lines": [562, 563, 564, 565, 566, 568, 569, 570, 571, 572, 575, 576, 579, 580, 581, 582, 583, 584, 589, 590, 591, 592, 593, 594, 595, 596, 597, 601], "excluded_lines": []}, "EncryptionManager.validate_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [609, 610, 611, 612, 613, 614, 615, 616, 617], "excluded_lines": []}, "EncryptionManager.derive_seed_from_mnemonic": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [620, 621, 622, 623, 625, 626, 627, 628, 630, 631, 632, 633, 634, 635, 636], "excluded_lines": []}, "": {"executed_lines": [3, 4, 6, 7, 9, 10, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 35, 38, 45, 46, 48, 56, 57, 62, 99, 117, 206, 247, 271, 279, 297, 303, 330, 347, 355, 363, 379, 441, 450, 560, 603, 619], "summary": {"covered_lines": 46, "num_statements": 46, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 4}, "missing_lines": [], "excluded_lines": [11, 12, 13, 15]}}, "classes": {"LegacyFormatRequiresMigrationError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [49, 52, 53], "excluded_lines": []}, "EncryptionManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 291, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 291, "excluded_lines": 19}, "missing_lines": [71, 72, 74, 75, 76, 79, 80, 82, 83, 85, 86, 87, 91, 94, 95, 97, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 131, 133, 135, 136, 137, 138, 139, 140, 141, 144, 145, 146, 147, 152, 153, 154, 155, 156, 157, 158, 161, 162, 163, 166, 167, 168, 171, 172, 173, 176, 181, 182, 183, 184, 185, 188, 192, 193, 198, 199, 200, 211, 212, 213, 214, 215, 218, 219, 220, 221, 222, 223, 225, 228, 234, 237, 240, 241, 266, 267, 268, 269, 275, 276, 277, 281, 282, 283, 285, 286, 289, 291, 292, 293, 295, 298, 299, 300, 301, 311, 312, 313, 315, 316, 317, 318, 319, 320, 325, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 348, 349, 350, 351, 352, 353, 356, 357, 358, 359, 360, 361, 370, 371, 372, 373, 375, 376, 377, 386, 387, 388, 389, 390, 391, 392, 395, 397, 398, 399, 401, 402, 405, 407, 408, 411, 412, 414, 417, 418, 419, 420, 421, 423, 424, 425, 426, 427, 428, 429, 436, 437, 438, 439, 442, 443, 444, 445, 446, 447, 448, 470, 471, 473, 474, 475, 477, 478, 479, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 496, 497, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 512, 515, 516, 517, 518, 521, 527, 528, 529, 530, 531, 535, 541, 542, 543, 562, 563, 564, 565, 566, 568, 569, 570, 571, 572, 575, 576, 579, 580, 581, 582, 583, 584, 589, 590, 591, 592, 593, 594, 595, 596, 597, 601, 609, 610, 611, 612, 613, 614, 615, 616, 617, 620, 621, 622, 623, 625, 626, 627, 628, 630, 631, 632, 633, 634, 635, 636], "excluded_lines": [201, 202, 229, 230, 238, 239, 321, 322, 430, 431, 432, 433, 544, 545, 546, 550, 556, 557, 558]}, "": {"executed_lines": [3, 4, 6, 7, 9, 10, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 35, 38, 45, 46, 48, 56, 57, 62, 99, 117, 206, 247, 271, 279, 297, 303, 330, 347, 355, 363, 379, 441, 450, 560, 603, 619], "summary": {"covered_lines": 46, "num_statements": 49, "percent_covered": 93.87755102040816, "percent_covered_display": "94", "missing_lines": 3, "excluded_lines": 4}, "missing_lines": [40, 41, 42], "excluded_lines": [11, 12, 13, 15]}}}, "src/seedpass/core/entry_management.py": {"executed_lines": [3, 18, 19, 21, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 48, 49, 50, 53, 56, 57, 76, 80, 123, 132, 152, 242, 256, 327, 369, 383, 429, 450, 494, 529, 554, 597, 619, 674, 697, 717, 738, 751, 784, 799, 837, 1101, 1105, 1109, 1252, 1307, 1344, 1365, 1407, 1440], "summary": {"covered_lines": 57, "num_statements": 667, "percent_covered": 8.545727136431784, "percent_covered_display": "9", "missing_lines": 610, "excluded_lines": 3}, "missing_lines": [64, 65, 66, 69, 70, 72, 74, 78, 81, 82, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 95, 96, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 119, 120, 121, 124, 125, 126, 127, 128, 129, 130, 138, 139, 140, 141, 142, 144, 145, 146, 147, 148, 149, 150, 183, 184, 185, 187, 188, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 222, 224, 228, 229, 230, 232, 233, 235, 237, 238, 239, 240, 244, 245, 246, 254, 271, 272, 273, 275, 276, 277, 278, 279, 280, 281, 282, 283, 297, 298, 299, 300, 301, 315, 317, 318, 319, 321, 322, 323, 324, 325, 343, 344, 346, 348, 349, 350, 352, 353, 354, 364, 365, 366, 367, 372, 373, 374, 375, 376, 378, 380, 381, 396, 397, 399, 400, 401, 403, 404, 406, 407, 408, 410, 411, 412, 424, 425, 426, 427, 432, 433, 434, 435, 436, 438, 439, 440, 442, 443, 445, 446, 447, 448, 461, 462, 464, 465, 466, 468, 469, 470, 471, 472, 473, 474, 475, 477, 478, 479, 489, 490, 491, 492, 507, 509, 510, 511, 524, 525, 526, 527, 532, 533, 534, 535, 538, 540, 541, 542, 544, 545, 547, 548, 549, 550, 551, 552, 566, 567, 569, 570, 571, 573, 574, 575, 576, 577, 579, 580, 581, 592, 593, 594, 595, 600, 601, 602, 603, 606, 608, 609, 610, 612, 613, 615, 616, 617, 634, 635, 637, 638, 639, 641, 642, 644, 646, 647, 648, 649, 651, 652, 654, 655, 656, 669, 670, 671, 672, 677, 678, 679, 680, 684, 686, 687, 688, 690, 691, 693, 694, 695, 703, 704, 705, 706, 709, 710, 711, 712, 713, 714, 715, 724, 725, 726, 727, 730, 731, 732, 733, 734, 735, 736, 740, 741, 742, 743, 746, 748, 749, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 771, 772, 773, 782, 790, 791, 792, 793, 794, 797, 806, 807, 808, 810, 811, 812, 817, 818, 821, 822, 824, 825, 826, 828, 829, 832, 835, 876, 877, 878, 880, 881, 884, 890, 892, 894, 916, 990, 991, 994, 995, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1019, 1020, 1021, 1022, 1026, 1027, 1028, 1029, 1030, 1031, 1033, 1034, 1036, 1037, 1038, 1039, 1040, 1044, 1045, 1046, 1048, 1049, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1078, 1080, 1081, 1085, 1086, 1087, 1089, 1090, 1094, 1095, 1096, 1099, 1103, 1107, 1130, 1131, 1132, 1134, 1135, 1136, 1137, 1138, 1140, 1141, 1142, 1143, 1144, 1147, 1148, 1150, 1151, 1153, 1155, 1156, 1158, 1159, 1160, 1164, 1165, 1168, 1169, 1171, 1172, 1173, 1174, 1175, 1176, 1186, 1196, 1197, 1198, 1199, 1202, 1203, 1204, 1205, 1206, 1209, 1215, 1216, 1222, 1227, 1228, 1235, 1236, 1242, 1244, 1246, 1247, 1248, 1249, 1250, 1261, 1262, 1264, 1265, 1267, 1268, 1272, 1273, 1277, 1278, 1280, 1281, 1284, 1285, 1286, 1288, 1289, 1290, 1291, 1293, 1294, 1305, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1328, 1331, 1338, 1339, 1340, 1348, 1349, 1350, 1351, 1354, 1356, 1358, 1359, 1361, 1362, 1363, 1371, 1372, 1373, 1374, 1375, 1380, 1382, 1385, 1387, 1388, 1394, 1395, 1397, 1398, 1401, 1415, 1416, 1421, 1422, 1423, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1435, 1436, 1437, 1438, 1447, 1448, 1449, 1451, 1452, 1454, 1455, 1456, 1457, 1458, 1459, 1462, 1463, 1464, 1466, 1467, 1469, 1470, 1471, 1472, 1473, 1474], "excluded_lines": [22, 23, 25], "functions": {"EntryManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [64, 65, 66, 69, 70, 72, 74], "excluded_lines": []}, "EntryManager.clear_cache": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [78], "excluded_lines": []}, "EntryManager._load_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 0}, "missing_lines": [81, 82, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 95, 96, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 119, 120, 121], "excluded_lines": []}, "EntryManager._save_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [124, 125, 126, 127, 128, 129, 130], "excluded_lines": []}, "EntryManager.get_next_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [138, 139, 140, 141, 142, 144, 145, 146, 147, 148, 149, 150], "excluded_lines": []}, "EntryManager.add_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 36, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 36, "excluded_lines": 0}, "missing_lines": [183, 184, 185, 187, 188, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 222, 224, 228, 229, 230, 232, 233, 235, 237, 238, 239, 240], "excluded_lines": []}, "EntryManager.get_next_totp_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [244, 245, 246, 254], "excluded_lines": []}, "EntryManager.add_totp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 0}, "missing_lines": [271, 272, 273, 275, 276, 277, 278, 279, 280, 281, 282, 283, 297, 298, 299, 300, 301, 315, 317, 318, 319, 321, 322, 323, 324, 325], "excluded_lines": []}, "EntryManager.add_ssh_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [343, 344, 346, 348, 349, 350, 352, 353, 354, 364, 365, 366, 367], "excluded_lines": []}, "EntryManager.get_ssh_key_pair": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [372, 373, 374, 375, 376, 378, 380, 381], "excluded_lines": []}, "EntryManager.add_pgp_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [396, 397, 399, 400, 401, 403, 404, 406, 407, 408, 410, 411, 412, 424, 425, 426, 427], "excluded_lines": []}, "EntryManager.get_pgp_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [432, 433, 434, 435, 436, 438, 439, 440, 442, 443, 445, 446, 447, 448], "excluded_lines": []}, "EntryManager.add_nostr_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [461, 462, 464, 465, 466, 468, 469, 470, 471, 472, 473, 474, 475, 477, 478, 479, 489, 490, 491, 492], "excluded_lines": []}, "EntryManager.add_key_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [507, 509, 510, 511, 524, 525, 526, 527], "excluded_lines": []}, "EntryManager.get_nostr_key_pair": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [532, 533, 534, 535, 538, 540, 541, 542, 544, 545, 547, 548, 549, 550, 551, 552], "excluded_lines": []}, "EntryManager.add_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [566, 567, 569, 570, 571, 573, 574, 575, 576, 577, 579, 580, 581, 592, 593, 594, 595], "excluded_lines": []}, "EntryManager.get_seed_phrase": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [600, 601, 602, 603, 606, 608, 609, 610, 612, 613, 615, 616, 617], "excluded_lines": []}, "EntryManager.add_managed_account": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [634, 635, 637, 638, 639, 641, 642, 644, 646, 647, 648, 649, 651, 652, 654, 655, 656, 669, 670, 671, 672], "excluded_lines": []}, "EntryManager.get_managed_account_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [677, 678, 679, 680, 684, 686, 687, 688, 690, 691, 693, 694, 695], "excluded_lines": []}, "EntryManager.get_totp_secret": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [703, 704, 705, 706, 709, 710, 711, 712, 713, 714, 715], "excluded_lines": []}, "EntryManager.get_totp_code": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [724, 725, 726, 727, 730, 731, 732, 733, 734, 735, 736], "excluded_lines": []}, "EntryManager.get_totp_time_remaining": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [740, 741, 742, 743, 746, 748, 749], "excluded_lines": []}, "EntryManager.export_totp_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 771, 772, 773, 782], "excluded_lines": []}, "EntryManager.get_encrypted_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [790, 791, 792, 793, 794, 797], "excluded_lines": []}, "EntryManager.retrieve_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [806, 807, 808, 810, 811, 812, 817, 818, 821, 822, 824, 825, 826, 828, 829, 832, 835], "excluded_lines": []}, "EntryManager.modify_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 90, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 90, "excluded_lines": 0}, "missing_lines": [876, 877, 878, 880, 881, 884, 890, 892, 894, 916, 990, 991, 994, 995, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1019, 1020, 1021, 1022, 1026, 1027, 1028, 1029, 1030, 1031, 1033, 1034, 1036, 1037, 1038, 1039, 1040, 1044, 1045, 1046, 1048, 1049, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1078, 1080, 1081, 1085, 1086, 1087, 1089, 1090, 1094, 1095, 1096, 1099], "excluded_lines": []}, "EntryManager.archive_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1103], "excluded_lines": []}, "EntryManager.restore_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1107], "excluded_lines": []}, "EntryManager.list_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 50, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 50, "excluded_lines": 0}, "missing_lines": [1130, 1131, 1132, 1134, 1135, 1136, 1137, 1138, 1140, 1153, 1155, 1156, 1158, 1159, 1160, 1164, 1165, 1168, 1169, 1171, 1172, 1173, 1174, 1175, 1176, 1186, 1196, 1197, 1198, 1199, 1202, 1203, 1204, 1205, 1206, 1209, 1215, 1216, 1222, 1227, 1228, 1235, 1236, 1242, 1244, 1246, 1247, 1248, 1249, 1250], "excluded_lines": []}, "EntryManager.list_entries.sort_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [1141, 1142, 1143, 1144, 1147, 1148, 1150, 1151], "excluded_lines": []}, "EntryManager.search_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [1261, 1262, 1264, 1265, 1267, 1268, 1272, 1273, 1277, 1278, 1280, 1281, 1284, 1285, 1286, 1288, 1289, 1290, 1291, 1293, 1294, 1305], "excluded_lines": []}, "EntryManager.delete_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1328, 1331, 1338, 1339, 1340], "excluded_lines": []}, "EntryManager.update_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [1348, 1349, 1350, 1351, 1354, 1356, 1358, 1359, 1361, 1362, 1363], "excluded_lines": []}, "EntryManager.restore_from_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [1371, 1372, 1373, 1374, 1375, 1380, 1382, 1385, 1387, 1388, 1394, 1395, 1397, 1398, 1401], "excluded_lines": []}, "EntryManager.list_all_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [1415, 1416, 1421, 1422, 1423, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1435, 1436, 1437, 1438], "excluded_lines": []}, "EntryManager.get_entry_summaries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 0}, "missing_lines": [1447, 1448, 1449, 1451, 1452, 1454, 1455, 1456, 1457, 1458, 1459, 1462, 1463, 1464, 1466, 1467, 1469, 1470, 1471, 1472, 1473, 1474], "excluded_lines": []}, "": {"executed_lines": [3, 18, 19, 21, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 48, 49, 50, 53, 56, 57, 76, 80, 123, 132, 152, 242, 256, 327, 369, 383, 429, 450, 494, 529, 554, 597, 619, 674, 697, 717, 738, 751, 784, 799, 837, 1101, 1105, 1109, 1252, 1307, 1344, 1365, 1407, 1440], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [22, 23, 25]}}, "classes": {"EntryManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 610, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 610, "excluded_lines": 0}, "missing_lines": [64, 65, 66, 69, 70, 72, 74, 78, 81, 82, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 95, 96, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 119, 120, 121, 124, 125, 126, 127, 128, 129, 130, 138, 139, 140, 141, 142, 144, 145, 146, 147, 148, 149, 150, 183, 184, 185, 187, 188, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 222, 224, 228, 229, 230, 232, 233, 235, 237, 238, 239, 240, 244, 245, 246, 254, 271, 272, 273, 275, 276, 277, 278, 279, 280, 281, 282, 283, 297, 298, 299, 300, 301, 315, 317, 318, 319, 321, 322, 323, 324, 325, 343, 344, 346, 348, 349, 350, 352, 353, 354, 364, 365, 366, 367, 372, 373, 374, 375, 376, 378, 380, 381, 396, 397, 399, 400, 401, 403, 404, 406, 407, 408, 410, 411, 412, 424, 425, 426, 427, 432, 433, 434, 435, 436, 438, 439, 440, 442, 443, 445, 446, 447, 448, 461, 462, 464, 465, 466, 468, 469, 470, 471, 472, 473, 474, 475, 477, 478, 479, 489, 490, 491, 492, 507, 509, 510, 511, 524, 525, 526, 527, 532, 533, 534, 535, 538, 540, 541, 542, 544, 545, 547, 548, 549, 550, 551, 552, 566, 567, 569, 570, 571, 573, 574, 575, 576, 577, 579, 580, 581, 592, 593, 594, 595, 600, 601, 602, 603, 606, 608, 609, 610, 612, 613, 615, 616, 617, 634, 635, 637, 638, 639, 641, 642, 644, 646, 647, 648, 649, 651, 652, 654, 655, 656, 669, 670, 671, 672, 677, 678, 679, 680, 684, 686, 687, 688, 690, 691, 693, 694, 695, 703, 704, 705, 706, 709, 710, 711, 712, 713, 714, 715, 724, 725, 726, 727, 730, 731, 732, 733, 734, 735, 736, 740, 741, 742, 743, 746, 748, 749, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 771, 772, 773, 782, 790, 791, 792, 793, 794, 797, 806, 807, 808, 810, 811, 812, 817, 818, 821, 822, 824, 825, 826, 828, 829, 832, 835, 876, 877, 878, 880, 881, 884, 890, 892, 894, 916, 990, 991, 994, 995, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1019, 1020, 1021, 1022, 1026, 1027, 1028, 1029, 1030, 1031, 1033, 1034, 1036, 1037, 1038, 1039, 1040, 1044, 1045, 1046, 1048, 1049, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1078, 1080, 1081, 1085, 1086, 1087, 1089, 1090, 1094, 1095, 1096, 1099, 1103, 1107, 1130, 1131, 1132, 1134, 1135, 1136, 1137, 1138, 1140, 1141, 1142, 1143, 1144, 1147, 1148, 1150, 1151, 1153, 1155, 1156, 1158, 1159, 1160, 1164, 1165, 1168, 1169, 1171, 1172, 1173, 1174, 1175, 1176, 1186, 1196, 1197, 1198, 1199, 1202, 1203, 1204, 1205, 1206, 1209, 1215, 1216, 1222, 1227, 1228, 1235, 1236, 1242, 1244, 1246, 1247, 1248, 1249, 1250, 1261, 1262, 1264, 1265, 1267, 1268, 1272, 1273, 1277, 1278, 1280, 1281, 1284, 1285, 1286, 1288, 1289, 1290, 1291, 1293, 1294, 1305, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1328, 1331, 1338, 1339, 1340, 1348, 1349, 1350, 1351, 1354, 1356, 1358, 1359, 1361, 1362, 1363, 1371, 1372, 1373, 1374, 1375, 1380, 1382, 1385, 1387, 1388, 1394, 1395, 1397, 1398, 1401, 1415, 1416, 1421, 1422, 1423, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1435, 1436, 1437, 1438, 1447, 1448, 1449, 1451, 1452, 1454, 1455, 1456, 1457, 1458, 1459, 1462, 1463, 1464, 1466, 1467, 1469, 1470, 1471, 1472, 1473, 1474], "excluded_lines": []}, "": {"executed_lines": [3, 18, 19, 21, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 48, 49, 50, 53, 56, 57, 76, 80, 123, 132, 152, 242, 256, 327, 369, 383, 429, 450, 494, 529, 554, 597, 619, 674, 697, 717, 738, 751, 784, 799, 837, 1101, 1105, 1109, 1252, 1307, 1344, 1365, 1407, 1440], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [22, 23, 25]}}}, "src/seedpass/core/entry_service.py": {"executed_lines": [1, 3, 4, 5, 7, 9, 14, 15, 17, 21, 22, 24, 27], "summary": {"covered_lines": 11, "num_statements": 114, "percent_covered": 9.649122807017545, "percent_covered_display": "10", "missing_lines": 103, "excluded_lines": 8}, "missing_lines": [25, 28, 29, 30, 31, 39, 40, 41, 44, 45, 46, 47, 52, 53, 54, 55, 61, 62, 64, 65, 66, 68, 69, 71, 77, 78, 81, 88, 90, 91, 92, 100, 102, 103, 104, 105, 106, 107, 108, 114, 115, 116, 117, 119, 120, 122, 123, 124, 127, 128, 129, 131, 139, 140, 142, 143, 144, 150, 151, 152, 153, 154, 155, 156, 157, 158, 162, 164, 167, 168, 169, 171, 174, 175, 177, 178, 179, 181, 184, 185, 186, 188, 191, 192, 193, 194, 196, 199, 200, 201, 202, 204, 205, 206, 207, 208, 210, 213, 214, 215, 216, 218, 237], "excluded_lines": [17, 18, 95, 96, 239, 240, 241, 242], "functions": {"EntryService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [25], "excluded_lines": []}, "EntryService.handle_add_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 77, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 77, "excluded_lines": 4}, "missing_lines": [28, 29, 30, 31, 39, 64, 102, 103, 104, 105, 106, 107, 108, 114, 115, 116, 117, 119, 120, 122, 123, 124, 127, 128, 129, 131, 139, 140, 142, 143, 144, 150, 151, 152, 153, 154, 155, 156, 157, 158, 162, 164, 167, 168, 169, 171, 174, 175, 177, 178, 179, 181, 184, 185, 186, 188, 191, 192, 193, 194, 196, 199, 200, 201, 202, 204, 205, 206, 207, 208, 210, 213, 214, 215, 216, 218, 237], "excluded_lines": [239, 240, 241, 242]}, "EntryService.handle_add_password.prompt_length": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [40, 41, 44, 45, 46, 47, 52, 53, 54, 55, 61, 62], "excluded_lines": []}, "EntryService.handle_add_password.finalize_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 2}, "missing_lines": [65, 66, 68, 69, 71, 77, 78, 81, 88, 90, 91, 92, 100], "excluded_lines": [95, 96]}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 14, 15, 17, 21, 22, 24, 27], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [17, 18]}}, "classes": {"EntryService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 103, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 103, "excluded_lines": 6}, "missing_lines": [25, 28, 29, 30, 31, 39, 40, 41, 44, 45, 46, 47, 52, 53, 54, 55, 61, 62, 64, 65, 66, 68, 69, 71, 77, 78, 81, 88, 90, 91, 92, 100, 102, 103, 104, 105, 106, 107, 108, 114, 115, 116, 117, 119, 120, 122, 123, 124, 127, 128, 129, 131, 139, 140, 142, 143, 144, 150, 151, 152, 153, 154, 155, 156, 157, 158, 162, 164, 167, 168, 169, 171, 174, 175, 177, 178, 179, 181, 184, 185, 186, 188, 191, 192, 193, 194, 196, 199, 200, 201, 202, 204, 205, 206, 207, 208, 210, 213, 214, 215, 216, 218, 237], "excluded_lines": [95, 96, 239, 240, 241, 242]}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 14, 15, 17, 21, 22, 24, 27], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [17, 18]}}}, "src/seedpass/core/entry_types.py": {"executed_lines": [2, 4, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 21], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [2, 4, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 21], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"EntryType": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [2, 4, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 21], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/errors.py": {"executed_lines": [1, 11, 12, 15, 16, 18, 22, 23, 30], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [19], "excluded_lines": [], "functions": {"SeedPassError.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [19], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 15, 16, 18, 22, 23, 30], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"SeedPassError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [19], "excluded_lines": []}, "DecryptionError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 11, 12, 15, 16, 18, 22, 23, 30], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/manager.py": {"executed_lines": [3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 52, 53, 60, 66, 67, 68, 69, 75, 76, 77, 78, 79, 81, 94, 95, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 112, 113, 114, 115, 118, 121, 122, 124, 141, 158, 164, 189, 190, 191, 193, 194, 197, 200, 201, 206, 209, 210, 212, 218, 227, 228, 237, 238, 239, 240, 241, 242, 244, 327, 328, 339, 340, 345, 355, 369, 386, 387, 391, 392, 398, 399, 407, 408, 422, 423, 432, 441, 450, 465, 477, 478, 483, 484, 489, 490, 497, 505, 551, 565, 577, 621, 667, 700, 794, 839, 840, 841, 844, 845, 875, 876, 900, 901, 987, 988, 1032, 1071, 1077, 1169, 1170, 1251, 1271, 1292, 1293, 1365, 1395, 1537, 1651, 1654, 1685, 1693, 1722, 1750, 1813, 1816, 1824, 1835, 1861, 1890, 1891, 1894, 1895, 2036, 2037, 2094, 2095, 2164, 2165, 2232, 2233, 2292, 2293, 2374, 2375, 2437, 2464, 2481, 2488, 2511, 2604, 2682, 2745, 3165, 3166, 3200, 3201, 3638, 3639, 3696, 3848, 3849, 3852, 3889, 3890, 3908, 3909, 3986, 3987, 3990, 3991, 4030, 4031, 4059, 4079, 4100, 4145, 4150, 4161, 4176, 4177, 4219, 4220, 4302, 4303, 4373, 4374, 4470, 4515, 4532, 4573, 4648, 4720], "summary": {"covered_lines": 222, "num_statements": 2703, "percent_covered": 8.213096559378469, "percent_covered_display": "8", "missing_lines": 2481, "excluded_lines": 32}, "missing_lines": [125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 142, 143, 148, 149, 152, 153, 154, 155, 160, 161, 174, 175, 176, 177, 180, 182, 183, 185, 186, 202, 203, 204, 215, 216, 220, 221, 222, 223, 224, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 277, 278, 279, 280, 281, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 304, 305, 306, 309, 310, 311, 314, 316, 318, 321, 323, 333, 334, 335, 343, 348, 349, 350, 351, 352, 353, 357, 363, 364, 365, 366, 367, 371, 372, 373, 374, 375, 376, 377, 378, 389, 394, 395, 396, 400, 401, 402, 403, 405, 410, 411, 412, 413, 414, 417, 418, 419, 420, 425, 426, 427, 428, 429, 430, 434, 435, 436, 437, 438, 439, 443, 444, 445, 446, 447, 448, 452, 453, 454, 455, 456, 458, 462, 463, 467, 468, 469, 470, 471, 472, 473, 474, 475, 479, 480, 481, 485, 486, 487, 491, 492, 493, 494, 495, 499, 500, 501, 502, 503, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 536, 541, 542, 543, 546, 547, 548, 549, 555, 556, 557, 558, 559, 560, 563, 569, 570, 572, 575, 581, 582, 583, 586, 587, 588, 590, 591, 592, 597, 598, 600, 602, 603, 604, 605, 607, 608, 610, 613, 614, 616, 617, 618, 619, 626, 627, 634, 635, 636, 637, 638, 639, 641, 642, 644, 645, 648, 649, 657, 658, 660, 662, 663, 664, 665, 670, 671, 672, 675, 676, 682, 686, 688, 689, 690, 697, 698, 709, 710, 711, 712, 713, 714, 716, 721, 726, 727, 729, 730, 731, 733, 734, 735, 736, 737, 738, 739, 741, 744, 745, 746, 747, 752, 753, 754, 755, 757, 758, 759, 760, 761, 762, 764, 765, 766, 767, 768, 770, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 799, 800, 802, 803, 805, 806, 811, 816, 817, 818, 819, 820, 822, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 842, 847, 848, 850, 851, 852, 853, 855, 859, 860, 861, 863, 864, 865, 866, 867, 869, 870, 871, 872, 873, 878, 879, 880, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 894, 895, 896, 897, 898, 906, 907, 908, 911, 912, 915, 916, 917, 923, 927, 928, 929, 934, 936, 937, 938, 939, 941, 942, 943, 946, 947, 948, 951, 956, 960, 961, 962, 963, 964, 965, 966, 967, 970, 975, 976, 977, 978, 980, 981, 982, 983, 984, 985, 993, 995, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1025, 1026, 1029, 1030, 1052, 1053, 1054, 1055, 1056, 1058, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1075, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1093, 1094, 1095, 1096, 1102, 1106, 1109, 1110, 1113, 1115, 1116, 1117, 1118, 1119, 1120, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1133, 1137, 1138, 1139, 1141, 1146, 1147, 1149, 1150, 1152, 1153, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1165, 1166, 1167, 1177, 1178, 1179, 1180, 1182, 1184, 1185, 1186, 1187, 1188, 1189, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1203, 1204, 1205, 1206, 1212, 1214, 1217, 1218, 1221, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1233, 1234, 1235, 1238, 1239, 1240, 1241, 1243, 1244, 1246, 1248, 1249, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1303, 1304, 1305, 1309, 1313, 1314, 1315, 1318, 1320, 1321, 1323, 1324, 1325, 1326, 1331, 1335, 1336, 1338, 1342, 1347, 1348, 1350, 1351, 1353, 1354, 1358, 1359, 1360, 1361, 1362, 1363, 1369, 1370, 1371, 1372, 1373, 1374, 1376, 1379, 1380, 1381, 1384, 1386, 1387, 1389, 1390, 1391, 1392, 1393, 1400, 1402, 1403, 1406, 1409, 1413, 1414, 1419, 1420, 1421, 1427, 1428, 1431, 1432, 1433, 1435, 1440, 1441, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1469, 1470, 1471, 1472, 1473, 1474, 1485, 1488, 1490, 1491, 1492, 1499, 1500, 1501, 1502, 1503, 1504, 1507, 1508, 1509, 1516, 1523, 1530, 1532, 1533, 1534, 1535, 1539, 1540, 1541, 1542, 1543, 1544, 1545, 1546, 1547, 1548, 1553, 1557, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1594, 1595, 1596, 1597, 1604, 1610, 1611, 1616, 1623, 1629, 1630, 1631, 1632, 1633, 1638, 1639, 1642, 1647, 1648, 1649, 1652, 1656, 1657, 1658, 1659, 1660, 1663, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1674, 1675, 1676, 1677, 1680, 1681, 1683, 1687, 1688, 1689, 1690, 1691, 1695, 1700, 1702, 1703, 1704, 1707, 1708, 1709, 1714, 1715, 1716, 1717, 1719, 1720, 1724, 1725, 1727, 1728, 1729, 1730, 1731, 1732, 1733, 1734, 1735, 1737, 1738, 1739, 1740, 1743, 1744, 1745, 1746, 1748, 1757, 1758, 1760, 1761, 1762, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1807, 1808, 1809, 1811, 1814, 1822, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1837, 1838, 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1848, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1859, 1863, 1864, 1866, 1867, 1868, 1869, 1871, 1872, 1873, 1875, 1876, 1877, 1878, 1879, 1880, 1882, 1885, 1887, 1888, 1892, 1897, 1898, 1899, 1900, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1922, 1923, 1924, 1927, 1932, 1933, 1934, 1939, 1949, 1950, 1951, 1953, 1954, 1955, 1956, 1957, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1983, 1984, 1985, 1986, 1987, 1988, 1991, 1996, 1997, 2007, 2008, 2009, 2015, 2016, 2017, 2018, 2019, 2023, 2024, 2025, 2026, 2027, 2028, 2030, 2031, 2032, 2033, 2034, 2039, 2040, 2041, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2059, 2062, 2065, 2066, 2068, 2071, 2072, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2088, 2089, 2090, 2091, 2092, 2097, 2098, 2099, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2118, 2119, 2120, 2121, 2122, 2125, 2126, 2127, 2129, 2132, 2133, 2135, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2150, 2151, 2152, 2153, 2154, 2158, 2159, 2160, 2161, 2162, 2167, 2168, 2169, 2176, 2177, 2178, 2179, 2180, 2184, 2185, 2186, 2187, 2192, 2200, 2203, 2204, 2206, 2209, 2210, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2226, 2227, 2228, 2229, 2230, 2235, 2236, 2237, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2255, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2272, 2273, 2274, 2275, 2278, 2279, 2280, 2286, 2287, 2288, 2289, 2290, 2295, 2296, 2297, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, 2337, 2345, 2346, 2348, 2349, 2350, 2351, 2352, 2353, 2360, 2361, 2362, 2368, 2369, 2370, 2371, 2372, 2377, 2378, 2379, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2397, 2400, 2401, 2402, 2403, 2409, 2410, 2411, 2412, 2419, 2420, 2421, 2423, 2424, 2425, 2431, 2432, 2433, 2434, 2435, 2439, 2440, 2441, 2442, 2444, 2445, 2453, 2455, 2457, 2458, 2459, 2460, 2461, 2462, 2466, 2467, 2472, 2473, 2474, 2475, 2477, 2478, 2479, 2483, 2484, 2485, 2486, 2492, 2493, 2494, 2496, 2497, 2498, 2500, 2501, 2505, 2506, 2507, 2509, 2513, 2514, 2515, 2522, 2523, 2524, 2525, 2526, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2539, 2541, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563, 2564, 2565, 2567, 2568, 2569, 2570, 2573, 2574, 2575, 2576, 2577, 2578, 2584, 2587, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2601, 2602, 2606, 2607, 2608, 2609, 2616, 2617, 2618, 2619, 2620, 2623, 2624, 2625, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, 2645, 2646, 2647, 2648, 2649, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, 2662, 2663, 2664, 2665, 2666, 2667, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2677, 2679, 2680, 2685, 2687, 2688, 2689, 2690, 2692, 2696, 2697, 2699, 2700, 2701, 2703, 2704, 2705, 2706, 2713, 2714, 2715, 2716, 2721, 2722, 2724, 2728, 2729, 2730, 2731, 2732, 2733, 2735, 2736, 2737, 2738, 2740, 2756, 2758, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2772, 2773, 2780, 2781, 2782, 2783, 2784, 2785, 2786, 2787, 2788, 2789, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 2812, 2813, 2814, 2815, 2819, 2821, 2822, 2823, 2824, 2827, 2828, 2829, 2830, 2833, 2834, 2835, 2836, 2837, 2838, 2839, 2840, 2841, 2842, 2843, 2844, 2845, 2852, 2853, 2857, 2859, 2860, 2861, 2862, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874, 2875, 2876, 2877, 2878, 2879, 2880, 2887, 2888, 2889, 2890, 2892, 2893, 2894, 2895, 2896, 2902, 2906, 2908, 2909, 2910, 2911, 2914, 2915, 2916, 2917, 2920, 2921, 2922, 2923, 2924, 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2938, 2942, 2944, 2945, 2946, 2947, 2948, 2951, 2952, 2953, 2954, 2955, 2956, 2963, 2964, 2965, 2966, 2967, 2968, 2972, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2981, 2982, 2983, 2984, 2985, 2990, 2991, 2992, 2999, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3021, 3028, 3029, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3049, 3056, 3057, 3060, 3061, 3062, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3078, 3079, 3080, 3081, 3082, 3083, 3085, 3091, 3092, 3093, 3094, 3095, 3096, 3101, 3103, 3104, 3105, 3106, 3113, 3119, 3120, 3121, 3122, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3144, 3145, 3146, 3147, 3148, 3149, 3150, 3153, 3160, 3162, 3163, 3168, 3169, 3170, 3177, 3180, 3181, 3182, 3183, 3184, 3186, 3187, 3188, 3189, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198, 3206, 3207, 3208, 3215, 3218, 3219, 3220, 3221, 3224, 3225, 3226, 3228, 3230, 3231, 3232, 3233, 3234, 3235, 3237, 3243, 3244, 3245, 3251, 3255, 3258, 3259, 3260, 3261, 3263, 3267, 3270, 3271, 3272, 3273, 3275, 3279, 3286, 3287, 3288, 3289, 3290, 3291, 3293, 3297, 3299, 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3320, 3323, 3329, 3339, 3340, 3341, 3342, 3344, 3350, 3356, 3360, 3367, 3368, 3369, 3370, 3371, 3372, 3374, 3378, 3380, 3387, 3390, 3396, 3403, 3407, 3408, 3409, 3410, 3412, 3418, 3424, 3430, 3434, 3435, 3439, 3440, 3444, 3451, 3452, 3453, 3454, 3455, 3456, 3458, 3462, 3464, 3471, 3472, 3473, 3474, 3475, 3476, 3479, 3480, 3481, 3482, 3483, 3487, 3490, 3496, 3504, 3505, 3507, 3512, 3513, 3514, 3515, 3516, 3518, 3524, 3525, 3526, 3527, 3534, 3541, 3547, 3553, 3560, 3561, 3562, 3563, 3564, 3565, 3567, 3571, 3573, 3580, 3581, 3582, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3594, 3597, 3603, 3615, 3616, 3618, 3621, 3622, 3623, 3626, 3627, 3632, 3634, 3635, 3636, 3641, 3642, 3643, 3650, 3651, 3652, 3653, 3654, 3656, 3657, 3658, 3659, 3660, 3662, 3663, 3664, 3671, 3672, 3673, 3674, 3675, 3676, 3677, 3679, 3682, 3683, 3684, 3687, 3688, 3689, 3690, 3691, 3692, 3693, 3694, 3698, 3699, 3700, 3702, 3703, 3704, 3705, 3706, 3709, 3715, 3716, 3717, 3718, 3719, 3720, 3721, 3722, 3723, 3724, 3725, 3726, 3732, 3733, 3734, 3735, 3736, 3737, 3738, 3739, 3740, 3741, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3752, 3753, 3754, 3755, 3756, 3757, 3758, 3759, 3762, 3763, 3764, 3765, 3768, 3769, 3770, 3771, 3776, 3777, 3778, 3779, 3780, 3781, 3782, 3783, 3784, 3785, 3788, 3789, 3790, 3791, 3792, 3793, 3794, 3795, 3796, 3797, 3798, 3799, 3800, 3801, 3802, 3803, 3804, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3815, 3816, 3817, 3818, 3819, 3820, 3821, 3822, 3823, 3824, 3825, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3839, 3840, 3846, 3850, 3854, 3855, 3858, 3859, 3860, 3861, 3863, 3866, 3867, 3869, 3872, 3873, 3876, 3877, 3878, 3879, 3880, 3885, 3886, 3887, 3892, 3893, 3896, 3897, 3898, 3899, 3900, 3901, 3902, 3903, 3904, 3905, 3906, 3911, 3913, 3916, 3919, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3940, 3941, 3942, 3943, 3946, 3947, 3948, 3951, 3952, 3953, 3954, 3955, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3977, 3978, 3979, 3981, 3982, 3983, 3984, 3988, 3995, 3996, 3997, 4004, 4005, 4006, 4007, 4008, 4012, 4013, 4015, 4016, 4017, 4019, 4025, 4026, 4027, 4028, 4033, 4034, 4035, 4036, 4037, 4038, 4045, 4046, 4047, 4054, 4055, 4056, 4057, 4065, 4066, 4067, 4068, 4069, 4071, 4072, 4073, 4074, 4075, 4076, 4077, 4085, 4086, 4087, 4088, 4089, 4092, 4098, 4104, 4105, 4106, 4107, 4108, 4109, 4110, 4111, 4112, 4113, 4114, 4115, 4117, 4120, 4121, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4135, 4136, 4141, 4142, 4143, 4148, 4154, 4155, 4156, 4157, 4158, 4159, 4165, 4166, 4167, 4172, 4173, 4174, 4189, 4190, 4191, 4198, 4199, 4202, 4209, 4210, 4211, 4212, 4213, 4214, 4215, 4216, 4217, 4223, 4224, 4230, 4233, 4234, 4235, 4236, 4237, 4238, 4239, 4240, 4241, 4243, 4244, 4252, 4253, 4259, 4260, 4261, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274, 4280, 4282, 4283, 4284, 4285, 4286, 4289, 4290, 4291, 4292, 4293, 4296, 4297, 4299, 4300, 4305, 4306, 4307, 4308, 4315, 4316, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4327, 4328, 4329, 4330, 4331, 4341, 4342, 4343, 4345, 4348, 4350, 4352, 4353, 4354, 4355, 4358, 4359, 4360, 4361, 4363, 4365, 4366, 4367, 4368, 4369, 4370, 4371, 4386, 4387, 4388, 4395, 4396, 4400, 4406, 4407, 4410, 4411, 4412, 4415, 4418, 4419, 4422, 4423, 4424, 4431, 4432, 4433, 4434, 4436, 4439, 4440, 4443, 4444, 4446, 4447, 4448, 4449, 4451, 4454, 4460, 4461, 4462, 4465, 4466, 4467, 4468, 4480, 4481, 4482, 4483, 4485, 4486, 4487, 4488, 4489, 4491, 4492, 4493, 4495, 4496, 4497, 4499, 4500, 4501, 4502, 4503, 4509, 4510, 4511, 4512, 4513, 4526, 4527, 4528, 4529, 4530, 4537, 4538, 4539, 4540, 4543, 4544, 4549, 4550, 4551, 4553, 4554, 4555, 4556, 4558, 4559, 4564, 4565, 4568, 4569, 4570, 4571, 4575, 4576, 4577, 4578, 4581, 4582, 4585, 4587, 4588, 4591, 4593, 4595, 4596, 4597, 4598, 4599, 4602, 4603, 4604, 4606, 4607, 4608, 4610, 4611, 4621, 4624, 4626, 4627, 4628, 4637, 4638, 4639, 4640, 4641, 4644, 4645, 4646, 4650, 4651, 4653, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4674, 4675, 4676, 4679, 4680, 4681, 4682, 4683, 4685, 4686, 4687, 4689, 4692, 4693, 4694, 4695, 4698, 4701, 4702, 4703, 4708, 4709, 4710, 4711, 4712, 4714, 4715, 4716, 4718, 4722, 4723, 4724, 4725, 4727, 4728, 4729, 4730, 4731, 4732, 4738, 4739, 4744, 4745, 4751, 4757, 4758, 4759, 4760], "excluded_lines": [1804, 1805, 1832, 1833, 2221, 2222, 2281, 2282, 2363, 2364, 2426, 2427, 2741, 2742, 2743, 2816, 2817, 2818, 2854, 2855, 2856, 2903, 2904, 2905, 2939, 2940, 2941, 2969, 2970, 2971, 3772, 3773], "functions": {"AuditLogger.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139], "excluded_lines": []}, "AuditLogger.log": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [142, 143, 148, 149, 152, 153, 154, 155], "excluded_lines": []}, "calculate_profile_id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [160, 161], "excluded_lines": []}, "restore_backup_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [174, 175, 176, 177, 180, 182, 183, 185, 186], "excluded_lines": []}, "requires_unlocked": {"executed_lines": [200, 201, 206], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "requires_unlocked.wrapper": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [202, 203, 204], "excluded_lines": []}, "AuthGuard.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [215, 216], "excluded_lines": []}, "AuthGuard.check_timeout": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [220, 221, 222, 223, 224], "excluded_lines": []}, "PasswordManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 55, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 55, "excluded_lines": 0}, "missing_lines": [254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 277, 278, 279, 280, 281, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 304, 305, 306, 309, 310, 311, 314, 316, 318, 321, 323], "excluded_lines": []}, "PasswordManager.get_bip85_entropy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [333, 334, 335], "excluded_lines": []}, "PasswordManager.clear_bip85_cache": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [343], "excluded_lines": []}, "PasswordManager.derive_key_hierarchy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [348, 349, 350, 351, 352, 353], "excluded_lines": []}, "PasswordManager.ensure_key_hierarchy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [357, 363, 364, 365, 366, 367], "excluded_lines": []}, "PasswordManager.ensure_script_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [371, 372, 373, 374, 375, 376, 377, 378], "excluded_lines": []}, "PasswordManager.get_password_prompt": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [389], "excluded_lines": []}, "PasswordManager.parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [400, 401, 402, 403, 405], "excluded_lines": []}, "PasswordManager.header_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [410, 411, 412, 413, 414, 417, 418, 419, 420], "excluded_lines": []}, "PasswordManager.header_fingerprint_args": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [425, 426, 427, 428, 429, 430], "excluded_lines": []}, "PasswordManager.update_activity": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [434, 435, 436, 437, 438, 439], "excluded_lines": []}, "PasswordManager.notify": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [443, 444, 445, 446, 447, 448], "excluded_lines": []}, "PasswordManager.get_current_notification": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [452, 453, 454, 455, 456, 458, 462, 463], "excluded_lines": []}, "PasswordManager.poll_background_errors": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [467, 468, 469, 470, 471, 472, 473, 474, 475], "excluded_lines": []}, "PasswordManager.menu_handler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [479, 480, 481], "excluded_lines": []}, "PasswordManager.profile_service": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [485, 486, 487], "excluded_lines": []}, "PasswordManager.entry_service": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [491, 492, 493, 494, 495], "excluded_lines": []}, "PasswordManager.lock_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [499, 500, 501, 502, 503], "excluded_lines": []}, "PasswordManager.unlock_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 536, 541, 542, 543, 546, 547, 548, 549], "excluded_lines": []}, "PasswordManager.initialize_fingerprint_manager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [555, 556, 557, 558, 559, 560, 563], "excluded_lines": []}, "PasswordManager.setup_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [569, 570, 572, 575], "excluded_lines": []}, "PasswordManager.select_or_add_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [581, 582, 583, 586, 587, 588, 590, 591, 592, 597, 598, 600, 602, 603, 604, 605, 607, 608, 610, 613, 614, 616, 617, 618, 619], "excluded_lines": []}, "PasswordManager.add_new_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [626, 627, 634, 635, 636, 637, 638, 639, 641, 642, 644, 645, 648, 649, 657, 658, 660, 662, 663, 664, 665], "excluded_lines": []}, "PasswordManager.select_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [670, 671, 672, 675, 676, 682, 686, 688, 689, 690, 697, 698], "excluded_lines": []}, "PasswordManager.setup_encryption_manager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 59, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 59, "excluded_lines": 0}, "missing_lines": [709, 710, 711, 712, 713, 714, 716, 721, 726, 727, 729, 730, 731, 733, 734, 735, 736, 737, 738, 739, 741, 744, 745, 746, 747, 752, 753, 754, 755, 757, 758, 759, 760, 761, 762, 764, 765, 766, 767, 768, 770, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792], "excluded_lines": []}, "PasswordManager.load_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 0}, "missing_lines": [799, 800, 802, 803, 805, 806, 811, 816, 817, 818, 819, 820, 822, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837], "excluded_lines": []}, "PasswordManager.handle_switch_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [842], "excluded_lines": []}, "PasswordManager.load_managed_account": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [847, 848, 850, 851, 852, 853, 855, 859, 860, 861, 863, 864, 865, 866, 867, 869, 870, 871, 872, 873], "excluded_lines": []}, "PasswordManager.exit_managed_account": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [878, 879, 880, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 894, 895, 896, 897, 898], "excluded_lines": []}, "PasswordManager.handle_existing_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 44, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 44, "excluded_lines": 0}, "missing_lines": [906, 907, 908, 911, 912, 915, 916, 917, 923, 927, 928, 929, 934, 936, 937, 938, 939, 941, 942, 943, 946, 947, 948, 951, 956, 960, 961, 962, 963, 964, 965, 966, 967, 970, 975, 976, 977, 978, 980, 981, 982, 983, 984, 985], "excluded_lines": []}, "PasswordManager.handle_new_seed_setup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [993, 995, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1025, 1026, 1029, 1030], "excluded_lines": []}, "PasswordManager.setup_existing_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [1052, 1053, 1054, 1055, 1056, 1058, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069], "excluded_lines": []}, "PasswordManager.setup_existing_seed_word_by_word": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1075], "excluded_lines": []}, "PasswordManager._finalize_existing_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 53, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 53, "excluded_lines": 0}, "missing_lines": [1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1093, 1094, 1095, 1096, 1102, 1106, 1109, 1110, 1113, 1115, 1116, 1117, 1118, 1119, 1120, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1133, 1137, 1138, 1139, 1141, 1146, 1147, 1149, 1150, 1152, 1153, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1165, 1166, 1167], "excluded_lines": []}, "PasswordManager.generate_new_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 48, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 48, "excluded_lines": 0}, "missing_lines": [1177, 1178, 1179, 1180, 1182, 1184, 1185, 1186, 1187, 1188, 1189, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1203, 1204, 1205, 1206, 1212, 1214, 1217, 1218, 1221, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1233, 1234, 1235, 1238, 1239, 1240, 1241, 1243, 1244, 1246, 1248, 1249], "excluded_lines": []}, "PasswordManager.validate_bip85_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269], "excluded_lines": []}, "PasswordManager.generate_bip85_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290], "excluded_lines": []}, "PasswordManager.save_and_encrypt_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 31, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 31, "excluded_lines": 0}, "missing_lines": [1303, 1304, 1305, 1309, 1313, 1314, 1315, 1318, 1320, 1321, 1323, 1324, 1325, 1326, 1331, 1335, 1336, 1338, 1342, 1347, 1348, 1350, 1351, 1353, 1354, 1358, 1359, 1360, 1361, 1362, 1363], "excluded_lines": []}, "PasswordManager.initialize_bip85": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [1369, 1370, 1371, 1372, 1373, 1374, 1376, 1386, 1387, 1389, 1390, 1391, 1392, 1393], "excluded_lines": []}, "PasswordManager.initialize_bip85.cached_derive": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [1379, 1380, 1381, 1384], "excluded_lines": []}, "PasswordManager.initialize_managers": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 62, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 62, "excluded_lines": 0}, "missing_lines": [1400, 1402, 1403, 1406, 1409, 1413, 1414, 1419, 1420, 1421, 1427, 1428, 1431, 1432, 1433, 1435, 1440, 1441, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1469, 1470, 1471, 1472, 1473, 1474, 1485, 1488, 1490, 1491, 1492, 1499, 1500, 1501, 1502, 1503, 1504, 1507, 1508, 1509, 1516, 1523, 1530, 1532, 1533, 1534, 1535], "excluded_lines": []}, "PasswordManager.sync_index_from_nostr_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 59, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 59, "excluded_lines": 0}, "missing_lines": [1539, 1540, 1541, 1542, 1543, 1544, 1545, 1546, 1547, 1548, 1553, 1557, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1594, 1595, 1596, 1597, 1604, 1610, 1611, 1616, 1623, 1629, 1630, 1631, 1632, 1633, 1638, 1639, 1642, 1647, 1648, 1649], "excluded_lines": []}, "PasswordManager.sync_index_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1652], "excluded_lines": []}, "PasswordManager.start_background_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [1656, 1657, 1658, 1659, 1660, 1663, 1665, 1674, 1675, 1676, 1677, 1680, 1681, 1683], "excluded_lines": []}, "PasswordManager.start_background_sync._worker": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [1666, 1667, 1668, 1669, 1670, 1671, 1672], "excluded_lines": []}, "PasswordManager.cleanup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [1687, 1688, 1689, 1690, 1691], "excluded_lines": []}, "PasswordManager.start_background_relay_check": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [1695, 1700, 1702, 1719, 1720], "excluded_lines": []}, "PasswordManager.start_background_relay_check._worker": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [1703, 1704, 1707, 1708, 1709, 1714, 1715, 1716, 1717], "excluded_lines": []}, "PasswordManager.start_background_vault_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [1724, 1725, 1727, 1737, 1738, 1739, 1740, 1743, 1744, 1745, 1746, 1748], "excluded_lines": []}, "PasswordManager.start_background_vault_sync._worker": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [1728, 1729, 1730, 1731, 1732, 1733, 1734, 1735], "excluded_lines": []}, "PasswordManager.attempt_initial_sync_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 37, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 37, "excluded_lines": 2}, "missing_lines": [1757, 1758, 1760, 1761, 1762, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1807, 1808, 1809, 1811], "excluded_lines": [1804, 1805]}, "PasswordManager.attempt_initial_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1814], "excluded_lines": []}, "PasswordManager.sync_index_from_nostr_if_missing": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1822], "excluded_lines": []}, "PasswordManager.sync_index_from_nostr_if_missing_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 2}, "missing_lines": [1825, 1826, 1827, 1828, 1829, 1830, 1831], "excluded_lines": [1832, 1833]}, "PasswordManager.check_nostr_backup_exists": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [1837, 1838, 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1848, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1859], "excluded_lines": []}, "PasswordManager.restore_from_nostr_with_guidance": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [1863, 1864, 1866, 1867, 1868, 1869, 1871, 1872, 1873, 1875, 1876, 1877, 1878, 1879, 1880, 1882, 1885, 1887, 1888], "excluded_lines": []}, "PasswordManager.handle_add_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [1892], "excluded_lines": []}, "PasswordManager.handle_add_totp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 76, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 76, "excluded_lines": 0}, "missing_lines": [1897, 1898, 1899, 1900, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1922, 1923, 1924, 1927, 1932, 1933, 1934, 1939, 1949, 1950, 1951, 1953, 1954, 1955, 1956, 1957, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1983, 1984, 1985, 1986, 1987, 1988, 1991, 1996, 1997, 2007, 2008, 2009, 2015, 2016, 2017, 2018, 2019, 2023, 2024, 2025, 2026, 2027, 2028, 2030, 2031, 2032, 2033, 2034], "excluded_lines": []}, "PasswordManager.handle_add_ssh_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 0}, "missing_lines": [2039, 2040, 2041, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2059, 2062, 2065, 2066, 2068, 2071, 2072, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2088, 2089, 2090, 2091, 2092], "excluded_lines": []}, "PasswordManager.handle_add_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 0}, "missing_lines": [2097, 2098, 2099, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2118, 2119, 2120, 2121, 2122, 2125, 2126, 2127, 2129, 2132, 2133, 2135, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2150, 2151, 2152, 2153, 2154, 2158, 2159, 2160, 2161, 2162], "excluded_lines": []}, "PasswordManager.handle_add_pgp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 2}, "missing_lines": [2167, 2168, 2169, 2176, 2177, 2178, 2179, 2180, 2184, 2185, 2186, 2187, 2192, 2200, 2203, 2204, 2206, 2209, 2210, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2226, 2227, 2228, 2229, 2230], "excluded_lines": [2221, 2222]}, "PasswordManager.handle_add_nostr_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 31, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 31, "excluded_lines": 2}, "missing_lines": [2235, 2236, 2237, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2255, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2272, 2273, 2274, 2275, 2278, 2279, 2280, 2286, 2287, 2288, 2289, 2290], "excluded_lines": [2281, 2282]}, "PasswordManager.handle_add_key_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 2}, "missing_lines": [2295, 2296, 2297, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, 2337, 2345, 2346, 2348, 2349, 2350, 2351, 2352, 2353, 2360, 2361, 2362, 2368, 2369, 2370, 2371, 2372], "excluded_lines": [2363, 2364]}, "PasswordManager.handle_add_managed_account": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 30, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 30, "excluded_lines": 2}, "missing_lines": [2377, 2378, 2379, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2397, 2400, 2401, 2402, 2403, 2409, 2410, 2411, 2412, 2419, 2420, 2421, 2423, 2424, 2425, 2431, 2432, 2433, 2434, 2435], "excluded_lines": [2426, 2427]}, "PasswordManager.show_entry_details_by_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [2439, 2440, 2441, 2442, 2444, 2445, 2453, 2455, 2457, 2458, 2459, 2460, 2461, 2462], "excluded_lines": []}, "PasswordManager._prompt_toggle_archive": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [2466, 2467, 2472, 2473, 2474, 2475, 2477, 2478, 2479], "excluded_lines": []}, "PasswordManager._entry_type_str": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [2483, 2484, 2485, 2486], "excluded_lines": []}, "PasswordManager._generate_password_for_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [2492, 2493, 2494, 2496, 2497, 2498, 2500, 2501, 2505, 2506, 2507, 2509], "excluded_lines": []}, "PasswordManager._entry_actions_menu": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 61, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 61, "excluded_lines": 0}, "missing_lines": [2513, 2514, 2515, 2522, 2523, 2524, 2525, 2526, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2539, 2541, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563, 2564, 2565, 2567, 2568, 2569, 2570, 2573, 2574, 2575, 2576, 2577, 2578, 2584, 2587, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2601, 2602], "excluded_lines": []}, "PasswordManager._entry_edit_menu": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 62, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 62, "excluded_lines": 0}, "missing_lines": [2606, 2607, 2608, 2609, 2616, 2617, 2618, 2619, 2620, 2623, 2624, 2625, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, 2645, 2646, 2647, 2648, 2649, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, 2662, 2663, 2664, 2665, 2666, 2667, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2677, 2679, 2680], "excluded_lines": []}, "PasswordManager._entry_qr_menu": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 3}, "missing_lines": [2685, 2687, 2688, 2689, 2690, 2692, 2696, 2697, 2699, 2700, 2701, 2703, 2704, 2705, 2706, 2713, 2714, 2715, 2716, 2721, 2722, 2724, 2728, 2729, 2730, 2731, 2732, 2733, 2735, 2736, 2737, 2738, 2740], "excluded_lines": [2741, 2742, 2743]}, "PasswordManager.display_sensitive_entry_info": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 257, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 257, "excluded_lines": 15}, "missing_lines": [2756, 2758, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2772, 2773, 2780, 2781, 2782, 2783, 2784, 2785, 2786, 2787, 2788, 2789, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 2812, 2813, 2814, 2815, 2819, 2821, 2822, 2823, 2824, 2827, 2828, 2829, 2830, 2833, 2834, 2835, 2836, 2837, 2838, 2839, 2840, 2841, 2842, 2843, 2844, 2845, 2852, 2853, 2857, 2859, 2860, 2861, 2862, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874, 2875, 2876, 2877, 2878, 2879, 2880, 2887, 2888, 2889, 2890, 2892, 2893, 2894, 2895, 2896, 2902, 2906, 2908, 2909, 2910, 2911, 2914, 2915, 2916, 2917, 2920, 2921, 2922, 2923, 2924, 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2938, 2942, 2944, 2945, 2946, 2947, 2948, 2951, 2952, 2953, 2954, 2955, 2956, 2963, 2964, 2965, 2966, 2967, 2968, 2972, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2981, 2982, 2983, 2984, 2985, 2990, 2991, 2992, 2999, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3021, 3028, 3029, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3049, 3056, 3057, 3060, 3061, 3062, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3078, 3079, 3080, 3081, 3082, 3083, 3085, 3091, 3092, 3093, 3094, 3095, 3096, 3101, 3103, 3104, 3105, 3106, 3113, 3119, 3120, 3121, 3122, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3144, 3145, 3146, 3147, 3148, 3149, 3150, 3153, 3160, 3162, 3163], "excluded_lines": [2816, 2817, 2818, 2854, 2855, 2856, 2903, 2904, 2905, 2939, 2940, 2941, 2969, 2970, 2971]}, "PasswordManager.handle_retrieve_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [3168, 3169, 3170, 3177, 3180, 3181, 3182, 3183, 3184, 3186, 3187, 3188, 3189, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198], "excluded_lines": []}, "PasswordManager.handle_modify_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 168, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 168, "excluded_lines": 0}, "missing_lines": [3206, 3207, 3208, 3215, 3218, 3219, 3220, 3221, 3224, 3225, 3226, 3228, 3230, 3231, 3232, 3233, 3234, 3235, 3237, 3243, 3244, 3245, 3251, 3255, 3258, 3259, 3260, 3261, 3263, 3267, 3270, 3271, 3272, 3273, 3275, 3279, 3286, 3287, 3288, 3289, 3290, 3291, 3293, 3297, 3299, 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3320, 3323, 3329, 3339, 3340, 3341, 3342, 3344, 3350, 3356, 3360, 3367, 3368, 3369, 3370, 3371, 3372, 3374, 3378, 3380, 3387, 3390, 3396, 3403, 3407, 3408, 3409, 3410, 3412, 3418, 3424, 3430, 3434, 3435, 3439, 3440, 3444, 3451, 3452, 3453, 3454, 3455, 3456, 3458, 3462, 3464, 3471, 3472, 3473, 3474, 3475, 3476, 3479, 3480, 3481, 3482, 3483, 3487, 3490, 3496, 3504, 3505, 3507, 3512, 3513, 3514, 3515, 3516, 3518, 3524, 3525, 3526, 3527, 3534, 3541, 3547, 3553, 3560, 3561, 3562, 3563, 3564, 3565, 3567, 3571, 3573, 3580, 3581, 3582, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3594, 3597, 3603, 3615, 3616, 3618, 3621, 3622, 3623, 3626, 3627, 3632, 3634, 3635, 3636], "excluded_lines": []}, "PasswordManager.handle_search_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 35, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 35, "excluded_lines": 0}, "missing_lines": [3641, 3642, 3643, 3650, 3651, 3652, 3653, 3654, 3656, 3657, 3658, 3659, 3660, 3662, 3663, 3664, 3671, 3672, 3673, 3674, 3675, 3676, 3677, 3679, 3682, 3683, 3684, 3687, 3688, 3689, 3690, 3691, 3692, 3693, 3694], "excluded_lines": []}, "PasswordManager.display_entry_details": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 116, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 116, "excluded_lines": 2}, "missing_lines": [3698, 3699, 3700, 3702, 3703, 3704, 3705, 3706, 3709, 3715, 3716, 3717, 3718, 3719, 3720, 3721, 3722, 3723, 3724, 3725, 3726, 3732, 3733, 3734, 3735, 3736, 3737, 3738, 3739, 3740, 3741, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3752, 3753, 3754, 3755, 3756, 3757, 3758, 3759, 3762, 3763, 3764, 3765, 3768, 3769, 3770, 3771, 3776, 3777, 3778, 3779, 3780, 3781, 3782, 3783, 3784, 3785, 3788, 3789, 3790, 3791, 3792, 3793, 3794, 3795, 3796, 3797, 3798, 3799, 3800, 3801, 3802, 3803, 3804, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3815, 3816, 3817, 3818, 3819, 3820, 3821, 3822, 3823, 3824, 3825, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3839, 3840, 3846], "excluded_lines": [3772, 3773]}, "PasswordManager.handle_list_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [3850], "excluded_lines": []}, "PasswordManager.delete_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [3854, 3855, 3858, 3859, 3860, 3861, 3863, 3866, 3867, 3869, 3872, 3873, 3876, 3877, 3878, 3879, 3880, 3885, 3886, 3887], "excluded_lines": []}, "PasswordManager.handle_archive_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [3892, 3893, 3896, 3897, 3898, 3899, 3900, 3901, 3902, 3903, 3904, 3905, 3906], "excluded_lines": []}, "PasswordManager.handle_view_archived_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 49, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 49, "excluded_lines": 0}, "missing_lines": [3911, 3913, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3940, 3941, 3942, 3943, 3946, 3947, 3948, 3951, 3952, 3953, 3954, 3955, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3977, 3978, 3979, 3981, 3982, 3983, 3984], "excluded_lines": []}, "PasswordManager.handle_view_archived_entries._load_archived_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [3916, 3919], "excluded_lines": []}, "PasswordManager.handle_display_totp_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [3988], "excluded_lines": []}, "PasswordManager.handle_verify_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [3995, 3996, 3997, 4004, 4005, 4006, 4007, 4008, 4012, 4013, 4015, 4016, 4017, 4019, 4025, 4026, 4027, 4028], "excluded_lines": []}, "PasswordManager.handle_update_script_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [4033, 4034, 4035, 4036, 4037, 4038, 4045, 4046, 4047, 4054, 4055, 4056, 4057], "excluded_lines": []}, "PasswordManager.get_encrypted_data": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [4065, 4066, 4067, 4068, 4069, 4071, 4072, 4073, 4074, 4075, 4076, 4077], "excluded_lines": []}, "PasswordManager.decrypt_and_save_index_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [4085, 4086, 4087, 4088, 4089, 4092, 4098], "excluded_lines": []}, "PasswordManager.sync_vault_async": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 29, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 29, "excluded_lines": 0}, "missing_lines": [4104, 4105, 4106, 4107, 4108, 4109, 4110, 4111, 4112, 4113, 4114, 4115, 4117, 4120, 4121, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4135, 4136, 4141, 4142, 4143], "excluded_lines": []}, "PasswordManager.sync_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [4148], "excluded_lines": []}, "PasswordManager.backup_database": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [4154, 4155, 4156, 4157, 4158, 4159], "excluded_lines": []}, "PasswordManager.restore_database": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [4165, 4166, 4167, 4172, 4173, 4174], "excluded_lines": []}, "PasswordManager.handle_export_database": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [4189, 4190, 4191, 4198, 4199, 4202, 4209, 4210, 4211, 4212, 4213, 4214, 4215, 4216, 4217], "excluded_lines": []}, "PasswordManager.handle_import_database": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 42, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 42, "excluded_lines": 0}, "missing_lines": [4223, 4224, 4230, 4233, 4234, 4235, 4236, 4237, 4238, 4239, 4240, 4241, 4243, 4244, 4252, 4253, 4259, 4260, 4261, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274, 4280, 4282, 4283, 4284, 4285, 4286, 4289, 4290, 4291, 4292, 4293, 4296, 4297, 4299, 4300], "excluded_lines": []}, "PasswordManager.handle_export_totp_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 0}, "missing_lines": [4305, 4306, 4307, 4308, 4315, 4316, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4327, 4328, 4329, 4330, 4331, 4341, 4342, 4343, 4345, 4348, 4350, 4352, 4353, 4354, 4355, 4358, 4359, 4360, 4361, 4363, 4365, 4366, 4367, 4368, 4369, 4370, 4371], "excluded_lines": []}, "PasswordManager.handle_backup_reveal_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 39, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 39, "excluded_lines": 0}, "missing_lines": [4386, 4387, 4388, 4395, 4396, 4400, 4406, 4407, 4410, 4411, 4412, 4415, 4418, 4419, 4422, 4423, 4424, 4431, 4432, 4433, 4434, 4436, 4439, 4440, 4443, 4444, 4446, 4447, 4448, 4449, 4451, 4454, 4460, 4461, 4462, 4465, 4466, 4467, 4468], "excluded_lines": []}, "PasswordManager.verify_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 25, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 25, "excluded_lines": 0}, "missing_lines": [4480, 4481, 4482, 4483, 4485, 4486, 4487, 4488, 4489, 4491, 4492, 4493, 4495, 4496, 4497, 4499, 4500, 4501, 4502, 4503, 4509, 4510, 4511, 4512, 4513], "excluded_lines": []}, "PasswordManager.is_valid_filename": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [4526, 4527, 4528, 4529, 4530], "excluded_lines": []}, "PasswordManager.store_hashed_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [4537, 4538, 4539, 4540, 4543, 4544, 4549, 4550, 4551, 4553, 4554, 4555, 4556, 4558, 4559, 4564, 4565, 4568, 4569, 4570, 4571], "excluded_lines": []}, "PasswordManager.change_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 37, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 37, "excluded_lines": 0}, "missing_lines": [4575, 4576, 4577, 4578, 4581, 4582, 4585, 4587, 4588, 4591, 4593, 4595, 4596, 4597, 4598, 4599, 4602, 4603, 4604, 4606, 4607, 4608, 4610, 4611, 4621, 4624, 4626, 4627, 4628, 4637, 4638, 4639, 4640, 4641, 4644, 4645, 4646], "excluded_lines": []}, "PasswordManager.get_profile_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 47, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 47, "excluded_lines": 0}, "missing_lines": [4650, 4651, 4653, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4674, 4675, 4676, 4679, 4680, 4681, 4682, 4683, 4685, 4686, 4687, 4689, 4692, 4693, 4694, 4695, 4698, 4701, 4702, 4703, 4708, 4709, 4710, 4711, 4712, 4714, 4715, 4716, 4718], "excluded_lines": []}, "PasswordManager.display_stats": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [4722, 4723, 4724, 4725, 4727, 4728, 4729, 4730, 4731, 4732, 4738, 4739, 4744, 4745, 4751, 4757, 4758, 4759, 4760], "excluded_lines": []}, "": {"executed_lines": [3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 52, 53, 60, 66, 67, 68, 69, 75, 76, 77, 78, 79, 81, 94, 95, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 112, 113, 114, 115, 118, 121, 122, 124, 141, 158, 164, 189, 190, 191, 193, 194, 197, 209, 210, 212, 218, 227, 228, 237, 238, 239, 240, 241, 242, 244, 327, 328, 339, 340, 345, 355, 369, 386, 387, 391, 392, 398, 399, 407, 408, 422, 423, 432, 441, 450, 465, 477, 478, 483, 484, 489, 490, 497, 505, 551, 565, 577, 621, 667, 700, 794, 839, 840, 841, 844, 845, 875, 876, 900, 901, 987, 988, 1032, 1071, 1077, 1169, 1170, 1251, 1271, 1292, 1293, 1365, 1395, 1537, 1651, 1654, 1685, 1693, 1722, 1750, 1813, 1816, 1824, 1835, 1861, 1890, 1891, 1894, 1895, 2036, 2037, 2094, 2095, 2164, 2165, 2232, 2233, 2292, 2293, 2374, 2375, 2437, 2464, 2481, 2488, 2511, 2604, 2682, 2745, 3165, 3166, 3200, 3201, 3638, 3639, 3696, 3848, 3849, 3852, 3889, 3890, 3908, 3909, 3986, 3987, 3990, 3991, 4030, 4031, 4059, 4079, 4100, 4145, 4150, 4161, 4176, 4177, 4219, 4220, 4302, 4303, 4373, 4374, 4470, 4515, 4532, 4573, 4648, 4720], "summary": {"covered_lines": 219, "num_statements": 219, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"AuditLogger": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 142, 143, 148, 149, 152, 153, 154, 155], "excluded_lines": []}, "Notification": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "AuthGuard": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [215, 216, 220, 221, 222, 223, 224], "excluded_lines": []}, "PasswordManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2437, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2437, "excluded_lines": 32}, "missing_lines": [254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 277, 278, 279, 280, 281, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 304, 305, 306, 309, 310, 311, 314, 316, 318, 321, 323, 333, 334, 335, 343, 348, 349, 350, 351, 352, 353, 357, 363, 364, 365, 366, 367, 371, 372, 373, 374, 375, 376, 377, 378, 389, 394, 395, 396, 400, 401, 402, 403, 405, 410, 411, 412, 413, 414, 417, 418, 419, 420, 425, 426, 427, 428, 429, 430, 434, 435, 436, 437, 438, 439, 443, 444, 445, 446, 447, 448, 452, 453, 454, 455, 456, 458, 462, 463, 467, 468, 469, 470, 471, 472, 473, 474, 475, 479, 480, 481, 485, 486, 487, 491, 492, 493, 494, 495, 499, 500, 501, 502, 503, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 536, 541, 542, 543, 546, 547, 548, 549, 555, 556, 557, 558, 559, 560, 563, 569, 570, 572, 575, 581, 582, 583, 586, 587, 588, 590, 591, 592, 597, 598, 600, 602, 603, 604, 605, 607, 608, 610, 613, 614, 616, 617, 618, 619, 626, 627, 634, 635, 636, 637, 638, 639, 641, 642, 644, 645, 648, 649, 657, 658, 660, 662, 663, 664, 665, 670, 671, 672, 675, 676, 682, 686, 688, 689, 690, 697, 698, 709, 710, 711, 712, 713, 714, 716, 721, 726, 727, 729, 730, 731, 733, 734, 735, 736, 737, 738, 739, 741, 744, 745, 746, 747, 752, 753, 754, 755, 757, 758, 759, 760, 761, 762, 764, 765, 766, 767, 768, 770, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 799, 800, 802, 803, 805, 806, 811, 816, 817, 818, 819, 820, 822, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 842, 847, 848, 850, 851, 852, 853, 855, 859, 860, 861, 863, 864, 865, 866, 867, 869, 870, 871, 872, 873, 878, 879, 880, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 894, 895, 896, 897, 898, 906, 907, 908, 911, 912, 915, 916, 917, 923, 927, 928, 929, 934, 936, 937, 938, 939, 941, 942, 943, 946, 947, 948, 951, 956, 960, 961, 962, 963, 964, 965, 966, 967, 970, 975, 976, 977, 978, 980, 981, 982, 983, 984, 985, 993, 995, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1025, 1026, 1029, 1030, 1052, 1053, 1054, 1055, 1056, 1058, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1075, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1093, 1094, 1095, 1096, 1102, 1106, 1109, 1110, 1113, 1115, 1116, 1117, 1118, 1119, 1120, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1133, 1137, 1138, 1139, 1141, 1146, 1147, 1149, 1150, 1152, 1153, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1165, 1166, 1167, 1177, 1178, 1179, 1180, 1182, 1184, 1185, 1186, 1187, 1188, 1189, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1203, 1204, 1205, 1206, 1212, 1214, 1217, 1218, 1221, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1233, 1234, 1235, 1238, 1239, 1240, 1241, 1243, 1244, 1246, 1248, 1249, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1303, 1304, 1305, 1309, 1313, 1314, 1315, 1318, 1320, 1321, 1323, 1324, 1325, 1326, 1331, 1335, 1336, 1338, 1342, 1347, 1348, 1350, 1351, 1353, 1354, 1358, 1359, 1360, 1361, 1362, 1363, 1369, 1370, 1371, 1372, 1373, 1374, 1376, 1379, 1380, 1381, 1384, 1386, 1387, 1389, 1390, 1391, 1392, 1393, 1400, 1402, 1403, 1406, 1409, 1413, 1414, 1419, 1420, 1421, 1427, 1428, 1431, 1432, 1433, 1435, 1440, 1441, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1469, 1470, 1471, 1472, 1473, 1474, 1485, 1488, 1490, 1491, 1492, 1499, 1500, 1501, 1502, 1503, 1504, 1507, 1508, 1509, 1516, 1523, 1530, 1532, 1533, 1534, 1535, 1539, 1540, 1541, 1542, 1543, 1544, 1545, 1546, 1547, 1548, 1553, 1557, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1594, 1595, 1596, 1597, 1604, 1610, 1611, 1616, 1623, 1629, 1630, 1631, 1632, 1633, 1638, 1639, 1642, 1647, 1648, 1649, 1652, 1656, 1657, 1658, 1659, 1660, 1663, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1674, 1675, 1676, 1677, 1680, 1681, 1683, 1687, 1688, 1689, 1690, 1691, 1695, 1700, 1702, 1703, 1704, 1707, 1708, 1709, 1714, 1715, 1716, 1717, 1719, 1720, 1724, 1725, 1727, 1728, 1729, 1730, 1731, 1732, 1733, 1734, 1735, 1737, 1738, 1739, 1740, 1743, 1744, 1745, 1746, 1748, 1757, 1758, 1760, 1761, 1762, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1807, 1808, 1809, 1811, 1814, 1822, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1837, 1838, 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1848, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1859, 1863, 1864, 1866, 1867, 1868, 1869, 1871, 1872, 1873, 1875, 1876, 1877, 1878, 1879, 1880, 1882, 1885, 1887, 1888, 1892, 1897, 1898, 1899, 1900, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1922, 1923, 1924, 1927, 1932, 1933, 1934, 1939, 1949, 1950, 1951, 1953, 1954, 1955, 1956, 1957, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1983, 1984, 1985, 1986, 1987, 1988, 1991, 1996, 1997, 2007, 2008, 2009, 2015, 2016, 2017, 2018, 2019, 2023, 2024, 2025, 2026, 2027, 2028, 2030, 2031, 2032, 2033, 2034, 2039, 2040, 2041, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2059, 2062, 2065, 2066, 2068, 2071, 2072, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2088, 2089, 2090, 2091, 2092, 2097, 2098, 2099, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2118, 2119, 2120, 2121, 2122, 2125, 2126, 2127, 2129, 2132, 2133, 2135, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2150, 2151, 2152, 2153, 2154, 2158, 2159, 2160, 2161, 2162, 2167, 2168, 2169, 2176, 2177, 2178, 2179, 2180, 2184, 2185, 2186, 2187, 2192, 2200, 2203, 2204, 2206, 2209, 2210, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2226, 2227, 2228, 2229, 2230, 2235, 2236, 2237, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2255, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2272, 2273, 2274, 2275, 2278, 2279, 2280, 2286, 2287, 2288, 2289, 2290, 2295, 2296, 2297, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, 2337, 2345, 2346, 2348, 2349, 2350, 2351, 2352, 2353, 2360, 2361, 2362, 2368, 2369, 2370, 2371, 2372, 2377, 2378, 2379, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2397, 2400, 2401, 2402, 2403, 2409, 2410, 2411, 2412, 2419, 2420, 2421, 2423, 2424, 2425, 2431, 2432, 2433, 2434, 2435, 2439, 2440, 2441, 2442, 2444, 2445, 2453, 2455, 2457, 2458, 2459, 2460, 2461, 2462, 2466, 2467, 2472, 2473, 2474, 2475, 2477, 2478, 2479, 2483, 2484, 2485, 2486, 2492, 2493, 2494, 2496, 2497, 2498, 2500, 2501, 2505, 2506, 2507, 2509, 2513, 2514, 2515, 2522, 2523, 2524, 2525, 2526, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2539, 2541, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563, 2564, 2565, 2567, 2568, 2569, 2570, 2573, 2574, 2575, 2576, 2577, 2578, 2584, 2587, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2601, 2602, 2606, 2607, 2608, 2609, 2616, 2617, 2618, 2619, 2620, 2623, 2624, 2625, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, 2645, 2646, 2647, 2648, 2649, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, 2662, 2663, 2664, 2665, 2666, 2667, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2677, 2679, 2680, 2685, 2687, 2688, 2689, 2690, 2692, 2696, 2697, 2699, 2700, 2701, 2703, 2704, 2705, 2706, 2713, 2714, 2715, 2716, 2721, 2722, 2724, 2728, 2729, 2730, 2731, 2732, 2733, 2735, 2736, 2737, 2738, 2740, 2756, 2758, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2772, 2773, 2780, 2781, 2782, 2783, 2784, 2785, 2786, 2787, 2788, 2789, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 2812, 2813, 2814, 2815, 2819, 2821, 2822, 2823, 2824, 2827, 2828, 2829, 2830, 2833, 2834, 2835, 2836, 2837, 2838, 2839, 2840, 2841, 2842, 2843, 2844, 2845, 2852, 2853, 2857, 2859, 2860, 2861, 2862, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874, 2875, 2876, 2877, 2878, 2879, 2880, 2887, 2888, 2889, 2890, 2892, 2893, 2894, 2895, 2896, 2902, 2906, 2908, 2909, 2910, 2911, 2914, 2915, 2916, 2917, 2920, 2921, 2922, 2923, 2924, 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2938, 2942, 2944, 2945, 2946, 2947, 2948, 2951, 2952, 2953, 2954, 2955, 2956, 2963, 2964, 2965, 2966, 2967, 2968, 2972, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2981, 2982, 2983, 2984, 2985, 2990, 2991, 2992, 2999, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3021, 3028, 3029, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3049, 3056, 3057, 3060, 3061, 3062, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3078, 3079, 3080, 3081, 3082, 3083, 3085, 3091, 3092, 3093, 3094, 3095, 3096, 3101, 3103, 3104, 3105, 3106, 3113, 3119, 3120, 3121, 3122, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3144, 3145, 3146, 3147, 3148, 3149, 3150, 3153, 3160, 3162, 3163, 3168, 3169, 3170, 3177, 3180, 3181, 3182, 3183, 3184, 3186, 3187, 3188, 3189, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198, 3206, 3207, 3208, 3215, 3218, 3219, 3220, 3221, 3224, 3225, 3226, 3228, 3230, 3231, 3232, 3233, 3234, 3235, 3237, 3243, 3244, 3245, 3251, 3255, 3258, 3259, 3260, 3261, 3263, 3267, 3270, 3271, 3272, 3273, 3275, 3279, 3286, 3287, 3288, 3289, 3290, 3291, 3293, 3297, 3299, 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3320, 3323, 3329, 3339, 3340, 3341, 3342, 3344, 3350, 3356, 3360, 3367, 3368, 3369, 3370, 3371, 3372, 3374, 3378, 3380, 3387, 3390, 3396, 3403, 3407, 3408, 3409, 3410, 3412, 3418, 3424, 3430, 3434, 3435, 3439, 3440, 3444, 3451, 3452, 3453, 3454, 3455, 3456, 3458, 3462, 3464, 3471, 3472, 3473, 3474, 3475, 3476, 3479, 3480, 3481, 3482, 3483, 3487, 3490, 3496, 3504, 3505, 3507, 3512, 3513, 3514, 3515, 3516, 3518, 3524, 3525, 3526, 3527, 3534, 3541, 3547, 3553, 3560, 3561, 3562, 3563, 3564, 3565, 3567, 3571, 3573, 3580, 3581, 3582, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3594, 3597, 3603, 3615, 3616, 3618, 3621, 3622, 3623, 3626, 3627, 3632, 3634, 3635, 3636, 3641, 3642, 3643, 3650, 3651, 3652, 3653, 3654, 3656, 3657, 3658, 3659, 3660, 3662, 3663, 3664, 3671, 3672, 3673, 3674, 3675, 3676, 3677, 3679, 3682, 3683, 3684, 3687, 3688, 3689, 3690, 3691, 3692, 3693, 3694, 3698, 3699, 3700, 3702, 3703, 3704, 3705, 3706, 3709, 3715, 3716, 3717, 3718, 3719, 3720, 3721, 3722, 3723, 3724, 3725, 3726, 3732, 3733, 3734, 3735, 3736, 3737, 3738, 3739, 3740, 3741, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3752, 3753, 3754, 3755, 3756, 3757, 3758, 3759, 3762, 3763, 3764, 3765, 3768, 3769, 3770, 3771, 3776, 3777, 3778, 3779, 3780, 3781, 3782, 3783, 3784, 3785, 3788, 3789, 3790, 3791, 3792, 3793, 3794, 3795, 3796, 3797, 3798, 3799, 3800, 3801, 3802, 3803, 3804, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3815, 3816, 3817, 3818, 3819, 3820, 3821, 3822, 3823, 3824, 3825, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3839, 3840, 3846, 3850, 3854, 3855, 3858, 3859, 3860, 3861, 3863, 3866, 3867, 3869, 3872, 3873, 3876, 3877, 3878, 3879, 3880, 3885, 3886, 3887, 3892, 3893, 3896, 3897, 3898, 3899, 3900, 3901, 3902, 3903, 3904, 3905, 3906, 3911, 3913, 3916, 3919, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3940, 3941, 3942, 3943, 3946, 3947, 3948, 3951, 3952, 3953, 3954, 3955, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3977, 3978, 3979, 3981, 3982, 3983, 3984, 3988, 3995, 3996, 3997, 4004, 4005, 4006, 4007, 4008, 4012, 4013, 4015, 4016, 4017, 4019, 4025, 4026, 4027, 4028, 4033, 4034, 4035, 4036, 4037, 4038, 4045, 4046, 4047, 4054, 4055, 4056, 4057, 4065, 4066, 4067, 4068, 4069, 4071, 4072, 4073, 4074, 4075, 4076, 4077, 4085, 4086, 4087, 4088, 4089, 4092, 4098, 4104, 4105, 4106, 4107, 4108, 4109, 4110, 4111, 4112, 4113, 4114, 4115, 4117, 4120, 4121, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4135, 4136, 4141, 4142, 4143, 4148, 4154, 4155, 4156, 4157, 4158, 4159, 4165, 4166, 4167, 4172, 4173, 4174, 4189, 4190, 4191, 4198, 4199, 4202, 4209, 4210, 4211, 4212, 4213, 4214, 4215, 4216, 4217, 4223, 4224, 4230, 4233, 4234, 4235, 4236, 4237, 4238, 4239, 4240, 4241, 4243, 4244, 4252, 4253, 4259, 4260, 4261, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274, 4280, 4282, 4283, 4284, 4285, 4286, 4289, 4290, 4291, 4292, 4293, 4296, 4297, 4299, 4300, 4305, 4306, 4307, 4308, 4315, 4316, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4327, 4328, 4329, 4330, 4331, 4341, 4342, 4343, 4345, 4348, 4350, 4352, 4353, 4354, 4355, 4358, 4359, 4360, 4361, 4363, 4365, 4366, 4367, 4368, 4369, 4370, 4371, 4386, 4387, 4388, 4395, 4396, 4400, 4406, 4407, 4410, 4411, 4412, 4415, 4418, 4419, 4422, 4423, 4424, 4431, 4432, 4433, 4434, 4436, 4439, 4440, 4443, 4444, 4446, 4447, 4448, 4449, 4451, 4454, 4460, 4461, 4462, 4465, 4466, 4467, 4468, 4480, 4481, 4482, 4483, 4485, 4486, 4487, 4488, 4489, 4491, 4492, 4493, 4495, 4496, 4497, 4499, 4500, 4501, 4502, 4503, 4509, 4510, 4511, 4512, 4513, 4526, 4527, 4528, 4529, 4530, 4537, 4538, 4539, 4540, 4543, 4544, 4549, 4550, 4551, 4553, 4554, 4555, 4556, 4558, 4559, 4564, 4565, 4568, 4569, 4570, 4571, 4575, 4576, 4577, 4578, 4581, 4582, 4585, 4587, 4588, 4591, 4593, 4595, 4596, 4597, 4598, 4599, 4602, 4603, 4604, 4606, 4607, 4608, 4610, 4611, 4621, 4624, 4626, 4627, 4628, 4637, 4638, 4639, 4640, 4641, 4644, 4645, 4646, 4650, 4651, 4653, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4674, 4675, 4676, 4679, 4680, 4681, 4682, 4683, 4685, 4686, 4687, 4689, 4692, 4693, 4694, 4695, 4698, 4701, 4702, 4703, 4708, 4709, 4710, 4711, 4712, 4714, 4715, 4716, 4718, 4722, 4723, 4724, 4725, 4727, 4728, 4729, 4730, 4731, 4732, 4738, 4739, 4744, 4745, 4751, 4757, 4758, 4759, 4760], "excluded_lines": [1804, 1805, 1832, 1833, 2221, 2222, 2281, 2282, 2363, 2364, 2426, 2427, 2741, 2742, 2743, 2816, 2817, 2818, 2854, 2855, 2856, 2903, 2904, 2905, 2939, 2940, 2941, 2969, 2970, 2971, 3772, 3773]}, "": {"executed_lines": [3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 52, 53, 60, 66, 67, 68, 69, 75, 76, 77, 78, 79, 81, 94, 95, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 112, 113, 114, 115, 118, 121, 122, 124, 141, 158, 164, 189, 190, 191, 193, 194, 197, 200, 201, 206, 209, 210, 212, 218, 227, 228, 237, 238, 239, 240, 241, 242, 244, 327, 328, 339, 340, 345, 355, 369, 386, 387, 391, 392, 398, 399, 407, 408, 422, 423, 432, 441, 450, 465, 477, 478, 483, 484, 489, 490, 497, 505, 551, 565, 577, 621, 667, 700, 794, 839, 840, 841, 844, 845, 875, 876, 900, 901, 987, 988, 1032, 1071, 1077, 1169, 1170, 1251, 1271, 1292, 1293, 1365, 1395, 1537, 1651, 1654, 1685, 1693, 1722, 1750, 1813, 1816, 1824, 1835, 1861, 1890, 1891, 1894, 1895, 2036, 2037, 2094, 2095, 2164, 2165, 2232, 2233, 2292, 2293, 2374, 2375, 2437, 2464, 2481, 2488, 2511, 2604, 2682, 2745, 3165, 3166, 3200, 3201, 3638, 3639, 3696, 3848, 3849, 3852, 3889, 3890, 3908, 3909, 3986, 3987, 3990, 3991, 4030, 4031, 4059, 4079, 4100, 4145, 4150, 4161, 4176, 4177, 4219, 4220, 4302, 4303, 4373, 4374, 4470, 4515, 4532, 4573, 4648, 4720], "summary": {"covered_lines": 222, "num_statements": 236, "percent_covered": 94.0677966101695, "percent_covered_display": "94", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [160, 161, 174, 175, 176, 177, 180, 182, 183, 185, 186, 202, 203, 204], "excluded_lines": []}}}, "src/seedpass/core/menu_handler.py": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 16, 20, 21, 23, 26, 27, 102, 103], "summary": {"covered_lines": 17, "num_statements": 127, "percent_covered": 13.385826771653543, "percent_covered_display": "13", "missing_lines": 110, "excluded_lines": 8}, "missing_lines": [24, 29, 30, 31, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 55, 56, 58, 59, 62, 63, 64, 66, 67, 73, 74, 75, 82, 83, 84, 85, 86, 88, 89, 92, 93, 94, 95, 96, 97, 105, 106, 107, 108, 115, 116, 117, 118, 119, 122, 123, 124, 125, 127, 128, 129, 131, 133, 134, 135, 136, 137, 138, 139, 141, 142, 143, 144, 151, 152, 153, 154, 155, 156, 157, 158, 163, 164, 165, 166, 167, 170, 174, 177, 178, 179, 180, 181, 186, 187, 188, 189, 190, 193, 197, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209], "excluded_lines": [16, 17, 98, 99, 100, 210, 211, 212], "functions": {"MenuHandler.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [24], "excluded_lines": []}, "MenuHandler.handle_list_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 44, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 44, "excluded_lines": 3}, "missing_lines": [29, 30, 31, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 55, 56, 58, 59, 62, 63, 64, 66, 67, 73, 74, 75, 82, 83, 84, 85, 86, 88, 89, 92, 93, 94, 95, 96, 97], "excluded_lines": [98, 99, 100]}, "MenuHandler.handle_display_totp_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 65, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 65, "excluded_lines": 3}, "missing_lines": [105, 106, 107, 108, 115, 116, 117, 118, 119, 122, 123, 124, 125, 127, 128, 129, 131, 133, 134, 135, 136, 137, 138, 139, 141, 142, 143, 144, 151, 152, 153, 154, 155, 156, 157, 158, 163, 164, 165, 166, 167, 170, 174, 177, 178, 179, 180, 181, 186, 187, 188, 189, 190, 193, 197, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209], "excluded_lines": [210, 211, 212]}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 16, 20, 21, 23, 26, 27, 102, 103], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [16, 17]}}, "classes": {"MenuHandler": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 110, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 110, "excluded_lines": 6}, "missing_lines": [24, 29, 30, 31, 32, 33, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 55, 56, 58, 59, 62, 63, 64, 66, 67, 73, 74, 75, 82, 83, 84, 85, 86, 88, 89, 92, 93, 94, 95, 96, 97, 105, 106, 107, 108, 115, 116, 117, 118, 119, 122, 123, 124, 125, 127, 128, 129, 131, 133, 134, 135, 136, 137, 138, 139, 141, 142, 143, 144, 151, 152, 153, 154, 155, 156, 157, 158, 163, 164, 165, 166, 167, 170, 174, 177, 178, 179, 180, 181, 186, 187, 188, 189, 190, 193, 197, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209], "excluded_lines": [98, 99, 100, 210, 211, 212]}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 16, 20, 21, 23, 26, 27, 102, 103], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [16, 17]}}}, "src/seedpass/core/migrations.py": {"executed_lines": [1, 3, 5, 7, 10, 15, 16, 17, 19, 22, 23, 29, 30, 46, 47, 61, 62, 71, 74], "summary": {"covered_lines": 18, "num_statements": 58, "percent_covered": 31.03448275862069, "percent_covered_display": "31", "missing_lines": 40, "excluded_lines": 0}, "missing_lines": [25, 26, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 64, 65, 66, 67, 68, 76, 77, 78, 80, 81, 82, 83, 84, 85, 87], "excluded_lines": [], "functions": {"migration": {"executed_lines": [15, 19], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "migration.decorator": {"executed_lines": [16, 17], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "_v0_to_v1": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [25, 26], "excluded_lines": []}, "_v1_to_v2": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43], "excluded_lines": []}, "_v2_to_v3": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [49, 50, 51, 52, 53, 54, 55, 56, 57, 58], "excluded_lines": []}, "_v3_to_v4": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [64, 65, 66, 67, 68], "excluded_lines": []}, "apply_migrations": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [76, 77, 78, 80, 81, 82, 83, 84, 85, 87], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 7, 10, 22, 23, 29, 30, 46, 47, 61, 62, 71, 74], "summary": {"covered_lines": 14, "num_statements": 14, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 5, 7, 10, 15, 16, 17, 19, 22, 23, 29, 30, 46, 47, 61, 62, 71, 74], "summary": {"covered_lines": 18, "num_statements": 58, "percent_covered": 31.03448275862069, "percent_covered_display": "31", "missing_lines": 40, "excluded_lines": 0}, "missing_lines": [25, 26, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 64, 65, 66, 67, 68, 76, 77, 78, 80, 81, 82, 83, 84, 85, 87], "excluded_lines": []}}}, "src/seedpass/core/password_generation.py": {"executed_lines": [3, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 47, 49, 55, 58, 61, 62, 63, 76, 77, 78, 79, 80, 81, 82, 83, 86, 87, 95, 129, 148, 154, 172, 181, 275, 436, 441, 464, 469], "summary": {"covered_lines": 42, "num_statements": 277, "percent_covered": 15.16245487364621, "percent_covered_display": "15", "missing_lines": 235, "excluded_lines": 13}, "missing_lines": [110, 111, 112, 113, 114, 116, 117, 119, 123, 124, 125, 126, 127, 131, 132, 134, 141, 142, 144, 145, 146, 150, 151, 152, 163, 164, 165, 166, 167, 168, 169, 170, 175, 176, 177, 178, 179, 202, 204, 205, 208, 211, 212, 215, 219, 221, 222, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 236, 238, 239, 240, 243, 246, 247, 248, 249, 250, 251, 252, 259, 260, 263, 264, 268, 270, 271, 272, 273, 291, 292, 293, 294, 295, 297, 298, 299, 300, 301, 303, 306, 307, 308, 309, 311, 316, 317, 318, 319, 322, 323, 325, 327, 328, 329, 332, 333, 334, 335, 336, 337, 339, 340, 341, 342, 343, 344, 346, 347, 348, 349, 350, 351, 353, 354, 355, 356, 357, 358, 361, 362, 363, 364, 366, 367, 368, 369, 370, 371, 372, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 404, 405, 406, 411, 414, 415, 420, 421, 422, 423, 424, 428, 430, 431, 432, 433, 438, 444, 445, 446, 448, 449, 455, 456, 461, 466, 480, 481, 482, 490, 497, 498, 499, 500, 501, 502, 504, 505, 507, 509, 512, 513, 514, 524, 525, 526, 527, 528, 529, 530, 531, 532, 534, 535, 536, 538, 539, 542, 543, 544, 545, 548, 550, 551, 552, 554, 555, 556, 557, 558, 559, 571], "excluded_lines": [39, 40, 41, 42, 43, 45, 516, 517, 518, 519, 520, 521, 522], "functions": {"PasswordGenerator.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [110, 111, 112, 113, 114, 116, 117, 119, 123, 124, 125, 126, 127], "excluded_lines": []}, "PasswordGenerator._derive_password_entropy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [131, 132, 134, 141, 142, 144, 145, 146], "excluded_lines": []}, "PasswordGenerator._map_entropy_to_chars": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [150, 151, 152], "excluded_lines": []}, "PasswordGenerator._fisher_yates_hmac": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [163, 164, 165, 166, 167, 168, 169, 170], "excluded_lines": []}, "PasswordGenerator._shuffle_deterministically": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [175, 176, 177, 178, 179], "excluded_lines": []}, "PasswordGenerator.generate_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 0}, "missing_lines": [202, 204, 205, 208, 211, 212, 215, 219, 221, 222, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 236, 238, 239, 240, 243, 246, 247, 248, 249, 250, 251, 252, 259, 260, 263, 264, 268, 270, 271, 272, 273], "excluded_lines": []}, "PasswordGenerator._enforce_complexity": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 98, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 98, "excluded_lines": 0}, "missing_lines": [291, 292, 293, 294, 295, 297, 298, 299, 300, 301, 303, 306, 307, 308, 309, 311, 316, 317, 318, 319, 322, 323, 325, 332, 333, 334, 335, 336, 337, 339, 340, 341, 342, 343, 344, 346, 347, 348, 349, 350, 351, 353, 354, 355, 356, 357, 358, 361, 362, 363, 364, 366, 367, 368, 369, 370, 371, 372, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 404, 405, 406, 411, 414, 415, 420, 421, 422, 423, 424, 428, 430, 431, 432, 433], "excluded_lines": []}, "PasswordGenerator._enforce_complexity.get_dk_value": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [327, 328, 329], "excluded_lines": []}, "derive_ssh_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [438], "excluded_lines": []}, "derive_ssh_key_pair": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [444, 445, 446, 448, 449, 455, 456, 461], "excluded_lines": []}, "derive_seed_phrase": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [466], "excluded_lines": []}, "derive_pgp_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 44, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 44, "excluded_lines": 1}, "missing_lines": [480, 481, 482, 490, 497, 498, 499, 500, 501, 502, 504, 505, 507, 509, 512, 524, 525, 526, 527, 528, 529, 530, 531, 532, 534, 535, 536, 538, 539, 542, 543, 544, 545, 548, 550, 551, 552, 554, 555, 556, 557, 558, 559, 571], "excluded_lines": [516]}, "derive_pgp_key.DRNG.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [513, 514], "excluded_lines": []}, "derive_pgp_key.DRNG.__call__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [517, 518, 519, 520, 521, 522]}, "": {"executed_lines": [3, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 47, 49, 55, 58, 61, 62, 63, 76, 77, 78, 79, 80, 81, 82, 83, 86, 87, 95, 129, 148, 154, 172, 181, 275, 436, 441, 464, 469], "summary": {"covered_lines": 42, "num_statements": 42, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [39, 40, 41, 42, 43, 45]}}, "classes": {"PasswordPolicy": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PasswordGenerator": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 179, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 179, "excluded_lines": 0}, "missing_lines": [110, 111, 112, 113, 114, 116, 117, 119, 123, 124, 125, 126, 127, 131, 132, 134, 141, 142, 144, 145, 146, 150, 151, 152, 163, 164, 165, 166, 167, 168, 169, 170, 175, 176, 177, 178, 179, 202, 204, 205, 208, 211, 212, 215, 219, 221, 222, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 236, 238, 239, 240, 243, 246, 247, 248, 249, 250, 251, 252, 259, 260, 263, 264, 268, 270, 271, 272, 273, 291, 292, 293, 294, 295, 297, 298, 299, 300, 301, 303, 306, 307, 308, 309, 311, 316, 317, 318, 319, 322, 323, 325, 327, 328, 329, 332, 333, 334, 335, 336, 337, 339, 340, 341, 342, 343, 344, 346, 347, 348, 349, 350, 351, 353, 354, 355, 356, 357, 358, 361, 362, 363, 364, 366, 367, 368, 369, 370, 371, 372, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 404, 405, 406, 411, 414, 415, 420, 421, 422, 423, 424, 428, 430, 431, 432, 433], "excluded_lines": []}, "derive_pgp_key.DRNG": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 6}, "missing_lines": [513, 514], "excluded_lines": [517, 518, 519, 520, 521, 522]}, "": {"executed_lines": [3, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 39, 40, 47, 49, 55, 58, 61, 62, 63, 76, 77, 78, 79, 80, 81, 82, 83, 86, 87, 95, 129, 148, 154, 172, 181, 275, 436, 441, 464, 469], "summary": {"covered_lines": 42, "num_statements": 96, "percent_covered": 43.75, "percent_covered_display": "44", "missing_lines": 54, "excluded_lines": 7}, "missing_lines": [438, 444, 445, 446, 448, 449, 455, 456, 461, 466, 480, 481, 482, 490, 497, 498, 499, 500, 501, 502, 504, 505, 507, 509, 512, 524, 525, 526, 527, 528, 529, 530, 531, 532, 534, 535, 536, 538, 539, 542, 543, 544, 545, 548, 550, 551, 552, 554, 555, 556, 557, 558, 559, 571], "excluded_lines": [39, 40, 41, 42, 43, 45, 516]}}}, "src/seedpass/core/portable_backup.py": {"executed_lines": [2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 22, 23, 24, 26, 28, 29, 32, 33, 35, 36, 39, 45, 124], "summary": {"covered_lines": 25, "num_statements": 84, "percent_covered": 29.761904761904763, "percent_covered_display": "30", "missing_lines": 59, "excluded_lines": 0}, "missing_lines": [42, 62, 63, 64, 65, 66, 68, 69, 71, 72, 77, 78, 79, 80, 81, 83, 84, 85, 87, 89, 99, 100, 101, 102, 104, 105, 106, 107, 108, 109, 110, 111, 117, 118, 119, 121, 132, 133, 134, 136, 137, 138, 140, 141, 143, 144, 149, 150, 151, 152, 153, 154, 156, 158, 160, 161, 162, 164, 165], "excluded_lines": [], "functions": {"_derive_export_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [42], "excluded_lines": []}, "export_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 35, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 35, "excluded_lines": 0}, "missing_lines": [62, 63, 64, 65, 66, 68, 69, 71, 72, 77, 78, 79, 80, 81, 83, 84, 85, 87, 89, 99, 100, 101, 102, 104, 105, 106, 107, 108, 109, 110, 111, 117, 118, 119, 121], "excluded_lines": []}, "import_backup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 23, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 23, "excluded_lines": 0}, "missing_lines": [132, 133, 134, 136, 137, 138, 140, 141, 143, 144, 149, 150, 151, 152, 153, 154, 156, 158, 160, 161, 162, 164, 165], "excluded_lines": []}, "": {"executed_lines": [2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 22, 23, 24, 26, 28, 29, 32, 33, 35, 36, 39, 45, 124], "summary": {"covered_lines": 25, "num_statements": 25, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"PortableMode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 22, 23, 24, 26, 28, 29, 32, 33, 35, 36, 39, 45, 124], "summary": {"covered_lines": 25, "num_statements": 84, "percent_covered": 29.761904761904763, "percent_covered_display": "30", "missing_lines": 59, "excluded_lines": 0}, "missing_lines": [42, 62, 63, 64, 65, 66, 68, 69, 71, 72, 77, 78, 79, 80, 81, 83, 84, 85, 87, 89, 99, 100, 101, 102, 104, 105, 106, 107, 108, 109, 110, 111, 117, 118, 119, 121, 132, 133, 134, 136, 137, 138, 140, 141, 143, 144, 149, 150, 151, 152, 153, 154, 156, 158, 160, 161, 162, 164, 165], "excluded_lines": []}}}, "src/seedpass/core/profile_service.py": {"executed_lines": [1, 3, 4, 6, 8, 10, 12, 17, 18, 20, 23], "summary": {"covered_lines": 9, "num_statements": 51, "percent_covered": 17.647058823529413, "percent_covered_display": "18", "missing_lines": 42, "excluded_lines": 7}, "missing_lines": [21, 25, 26, 27, 28, 29, 30, 35, 37, 38, 39, 40, 42, 43, 44, 45, 46, 48, 49, 50, 56, 58, 59, 63, 66, 68, 69, 70, 71, 73, 74, 82, 85, 87, 88, 89, 95, 98, 99, 100, 103, 105], "excluded_lines": [12, 13, 14, 106, 107, 108, 109], "functions": {"ProfileService.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [21], "excluded_lines": []}, "ProfileService.handle_switch_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 4}, "missing_lines": [25, 26, 27, 28, 29, 30, 35, 37, 38, 39, 40, 42, 43, 44, 45, 46, 48, 49, 50, 56, 58, 59, 63, 66, 68, 69, 70, 71, 73, 74, 82, 85, 87, 88, 89, 95, 98, 99, 100, 103, 105], "excluded_lines": [106, 107, 108, 109]}, "": {"executed_lines": [1, 3, 4, 6, 8, 10, 12, 17, 18, 20, 23], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [12, 13, 14]}}, "classes": {"ProfileService": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 42, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 42, "excluded_lines": 4}, "missing_lines": [21, 25, 26, 27, 28, 29, 30, 35, 37, 38, 39, 40, 42, 43, 44, 45, 46, 48, 49, 50, 56, 58, 59, 63, 66, 68, 69, 70, 71, 73, 74, 82, 85, 87, 88, 89, 95, 98, 99, 100, 103, 105], "excluded_lines": [106, 107, 108, 109]}, "": {"executed_lines": [1, 3, 4, 6, 8, 10, 12, 17, 18, 20, 23], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 3}, "missing_lines": [], "excluded_lines": [12, 13, 14]}}}, "src/seedpass/core/pubsub.py": {"executed_lines": [1, 2, 5, 6, 8, 9, 11, 15, 20, 27], "summary": {"covered_lines": 9, "num_statements": 14, "percent_covered": 64.28571428571429, "percent_covered_display": "64", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [13, 17, 18, 22, 23], "excluded_lines": [], "functions": {"PubSub.__init__": {"executed_lines": [9], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "PubSub.subscribe": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [13], "excluded_lines": []}, "PubSub.unsubscribe": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [17, 18], "excluded_lines": []}, "PubSub.publish": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [22, 23], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 8, 11, 15, 20, 27], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"PubSub": {"executed_lines": [9], "summary": {"covered_lines": 1, "num_statements": 6, "percent_covered": 16.666666666666668, "percent_covered_display": "17", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [13, 17, 18, 22, 23], "excluded_lines": []}, "": {"executed_lines": [1, 2, 5, 6, 8, 11, 15, 20, 27], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/seedqr.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [3, 5, 6, 9, 11, 12, 13, 14], "excluded_lines": [], "functions": {"encode_seedqr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [11, 12, 13, 14], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [3, 5, 6, 9], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [3, 5, 6, 9, 11, 12, 13, 14], "excluded_lines": []}}}, "src/seedpass/core/state_manager.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 12, 13, 15, 17, 21, 55, 63, 64, 67, 73, 76, 85], "summary": {"covered_lines": 18, "num_statements": 65, "percent_covered": 27.692307692307693, "percent_covered_display": "28", "missing_lines": 47, "excluded_lines": 0}, "missing_lines": [18, 19, 22, 23, 31, 32, 33, 34, 35, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 56, 57, 58, 59, 60, 61, 65, 68, 69, 70, 74, 77, 78, 79, 80, 81, 82, 83, 86, 87, 88, 89, 90, 91, 92, 93, 94], "excluded_lines": [], "functions": {"StateManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [18, 19], "excluded_lines": []}, "StateManager._load": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [22, 23, 31, 32, 33, 34, 35, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53], "excluded_lines": []}, "StateManager._save": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [56, 57, 58, 59, 60, 61], "excluded_lines": []}, "StateManager.state": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [65], "excluded_lines": []}, "StateManager.update_state": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [68, 69, 70], "excluded_lines": []}, "StateManager.list_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [74], "excluded_lines": []}, "StateManager.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [77, 78, 79, 80, 81, 82, 83], "excluded_lines": []}, "StateManager.remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [86, 87, 88, 89, 90, 91, 92, 93, 94], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 12, 13, 15, 17, 21, 55, 63, 64, 67, 73, 76, 85], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"StateManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 47, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 47, "excluded_lines": 0}, "missing_lines": [18, 19, 22, 23, 31, 32, 33, 34, 35, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 56, 57, 58, 59, 60, 61, 65, 68, 69, 70, 74, 77, 78, 79, 80, 81, 82, 83, 86, 87, 88, 89, 90, 91, 92, 93, 94], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 12, 13, 15, 17, 21, 55, 63, 64, 67, 73, 76, 85], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/stats_manager.py": {"executed_lines": [1, 3, 6, 7, 9, 12, 18], "summary": {"covered_lines": 5, "num_statements": 10, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [10, 14, 15, 16, 20], "excluded_lines": [], "functions": {"StatsManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [10], "excluded_lines": []}, "StatsManager.display_stats_once": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [14, 15, 16], "excluded_lines": []}, "StatsManager.reset": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [20], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 9, 12, 18], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"StatsManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [10, 14, 15, 16, 20], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 9, 12, 18], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/core/totp.py": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 20, 25, 26, 28, 29, 33, 34, 44, 45, 50, 51, 65, 66, 73, 74, 80, 81, 97, 98], "summary": {"covered_lines": 29, "num_statements": 71, "percent_covered": 40.84507042253521, "percent_covered_display": "41", "missing_lines": 42, "excluded_lines": 0}, "missing_lines": [22, 31, 38, 39, 40, 41, 42, 47, 48, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 70, 71, 76, 77, 78, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 100, 101, 102, 103], "excluded_lines": [], "functions": {"random_totp_secret": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": []}, "TotpManager.derive_secret": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [31], "excluded_lines": []}, "TotpManager.current_code": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [38, 39, 40, 41, 42], "excluded_lines": []}, "TotpManager.current_code_from_secret": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [47, 48], "excluded_lines": []}, "TotpManager.parse_otpauth": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63], "excluded_lines": []}, "TotpManager.make_otpauth_uri": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [70, 71], "excluded_lines": []}, "TotpManager.time_remaining": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [76, 77, 78], "excluded_lines": []}, "TotpManager.print_progress_bar": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95], "excluded_lines": []}, "TotpManager.print_qr_code": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [100, 101, 102, 103], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 20, 25, 26, 28, 29, 33, 34, 44, 45, 50, 51, 65, 66, 73, 74, 80, 81, 97, 98], "summary": {"covered_lines": 29, "num_statements": 29, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"TotpManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 41, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 41, "excluded_lines": 0}, "missing_lines": [31, 38, 39, 40, 41, 42, 47, 48, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 70, 71, 76, 77, 78, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 100, 101, 102, 103], "excluded_lines": []}, "": {"executed_lines": [1, 3, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 20, 25, 26, 28, 29, 33, 34, 44, 45, 50, 51, 65, 66, 73, 74, 80, 81, 97, 98], "summary": {"covered_lines": 29, "num_statements": 30, "percent_covered": 96.66666666666667, "percent_covered_display": "97", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [22], "excluded_lines": []}}}, "src/seedpass/core/vault.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 17, 18, 21, 22, 24, 25, 27, 38, 42, 48, 239, 245, 249, 275, 279], "summary": {"covered_lines": 21, "num_statements": 140, "percent_covered": 15.0, "percent_covered_display": "15", "missing_lines": 119, "excluded_lines": 0}, "missing_lines": [32, 33, 34, 35, 36, 40, 43, 63, 64, 65, 66, 67, 68, 69, 74, 75, 77, 80, 81, 82, 83, 84, 86, 87, 88, 93, 94, 95, 96, 97, 98, 99, 100, 102, 103, 110, 111, 114, 117, 118, 124, 127, 128, 129, 130, 136, 142, 143, 144, 145, 146, 147, 149, 152, 155, 156, 157, 160, 161, 163, 164, 165, 168, 169, 172, 173, 174, 175, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 191, 192, 194, 196, 197, 198, 201, 203, 204, 205, 206, 209, 210, 211, 212, 213, 216, 217, 218, 219, 220, 221, 224, 225, 226, 227, 229, 230, 232, 235, 236, 237, 241, 247, 264, 267, 270, 271, 272, 277, 281], "excluded_lines": [], "functions": {"Vault.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [32, 33, 34, 35, 36], "excluded_lines": []}, "Vault.set_encryption_manager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [40], "excluded_lines": []}, "Vault._hkdf_kdf": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [43], "excluded_lines": []}, "Vault.load_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 103, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 103, "excluded_lines": 0}, "missing_lines": [63, 64, 65, 66, 67, 68, 69, 74, 75, 77, 80, 81, 82, 83, 84, 86, 87, 88, 93, 94, 95, 96, 97, 98, 99, 100, 102, 103, 110, 111, 114, 117, 118, 124, 127, 128, 129, 130, 136, 142, 143, 144, 145, 146, 147, 149, 152, 155, 156, 157, 160, 161, 163, 164, 165, 168, 169, 172, 173, 174, 175, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 191, 192, 194, 196, 197, 198, 201, 203, 204, 205, 206, 209, 210, 211, 212, 213, 216, 217, 218, 219, 220, 221, 224, 225, 226, 227, 229, 230, 232, 235, 236, 237], "excluded_lines": []}, "Vault.save_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [241], "excluded_lines": []}, "Vault.get_encrypted_index": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [247], "excluded_lines": []}, "Vault.decrypt_and_save_index_from_nostr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [264, 267, 270, 271, 272], "excluded_lines": []}, "Vault.load_config": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [277], "excluded_lines": []}, "Vault.save_config": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [281], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 17, 18, 21, 22, 24, 25, 27, 38, 42, 48, 239, 245, 249, 275, 279], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"Vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 119, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 119, "excluded_lines": 0}, "missing_lines": [32, 33, 34, 35, 36, 40, 43, 63, 64, 65, 66, 67, 68, 69, 74, 75, 77, 80, 81, 82, 83, 84, 86, 87, 88, 93, 94, 95, 96, 97, 98, 99, 100, 102, 103, 110, 111, 114, 117, 118, 124, 127, 128, 129, 130, 136, 142, 143, 144, 145, 146, 147, 149, 152, 155, 156, 157, 160, 161, 163, 164, 165, 168, 169, 172, 173, 174, 175, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 191, 192, 194, 196, 197, 198, 201, 203, 204, 205, 206, 209, 210, 211, 212, 213, 216, 217, 218, 219, 220, 221, 224, 225, 226, 227, 229, 230, 232, 235, 236, 237, 241, 247, 264, 267, 270, 271, 272, 277, 281], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 9, 11, 17, 18, 21, 22, 24, 25, 27, 38, 42, 48, 239, 245, 249, 275, 279], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass/errors.py": {"executed_lines": [1, 3, 6, 7, 9, 13], "summary": {"covered_lines": 4, "num_statements": 5, "percent_covered": 80.0, "percent_covered_display": "80", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [10], "excluded_lines": [], "functions": {"VaultLockedError.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [10], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 9, 13], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"VaultLockedError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [10], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 9, 13], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/seedpass_gui/__init__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [3, 6, 8, 11], "excluded_lines": [], "functions": {"main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [8], "excluded_lines": []}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [3, 6, 11], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [3, 6, 8, 11], "excluded_lines": []}}}, "src/seedpass_gui/__main__.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1, 3, 4], "excluded_lines": [], "functions": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1, 3, 4], "excluded_lines": []}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [1, 3, 4], "excluded_lines": []}}}, "src/seedpass_gui/app.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 303, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 303, "excluded_lines": 24}, "missing_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 21, 24, 27, 33, 36, 37, 38, 40, 41, 42, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 60, 66, 67, 68, 71, 74, 81, 84, 85, 86, 87, 88, 89, 90, 91, 93, 94, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 115, 117, 118, 119, 120, 121, 123, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 150, 151, 152, 154, 155, 156, 157, 158, 159, 161, 162, 163, 165, 166, 167, 169, 170, 171, 173, 176, 177, 179, 182, 183, 185, 186, 187, 189, 190, 191, 192, 194, 195, 196, 197, 198, 199, 200, 203, 206, 207, 208, 209, 210, 212, 213, 217, 218, 219, 220, 223, 224, 226, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 261, 262, 263, 264, 265, 266, 267, 268, 270, 271, 272, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 289, 290, 292, 293, 294, 295, 296, 297, 298, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 312, 320, 321, 323, 324, 325, 326, 327, 329, 331, 334, 337, 338, 339, 340, 341, 344, 345, 346, 347, 348, 350, 351, 352, 353, 354, 355, 364, 367, 370, 371, 372, 373, 375, 380, 381, 382, 384, 385, 386, 388, 389, 390, 391, 393, 394, 395, 398, 399, 400, 401, 402, 404, 405, 408, 411, 412, 413, 414, 416, 417, 418, 419, 420, 422, 423, 424, 425, 426, 427, 428, 429, 430, 432, 434, 435, 436, 437, 439, 440, 441, 442, 443, 444, 448, 449, 451, 452, 453, 454, 455, 456, 457, 461, 464, 466, 469], "excluded_lines": [57, 58, 59, 445, 446, 447, 458, 459, 460, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 484, 485, 486], "functions": {"LockScreenWindow.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [33, 36, 37, 38, 40, 41, 42, 46, 47, 48, 49, 50, 51], "excluded_lines": []}, "LockScreenWindow.handle_unlock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 3}, "missing_lines": [54, 55, 56, 60, 66, 67, 68], "excluded_lines": [57, 58, 59]}, "MainWindow.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 31, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 31, "excluded_lines": 0}, "missing_lines": [81, 84, 85, 86, 87, 88, 89, 90, 91, 93, 94, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 115, 117, 118, 119, 120, 121, 123], "excluded_lines": []}, "MainWindow.refresh_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139], "excluded_lines": []}, "MainWindow.add_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [151, 152], "excluded_lines": []}, "MainWindow.edit_entry": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [155, 156, 157, 158, 159], "excluded_lines": []}, "MainWindow.search_entries": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [162, 163], "excluded_lines": []}, "MainWindow.manage_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [166, 167], "excluded_lines": []}, "MainWindow.show_totp_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [170, 171], "excluded_lines": []}, "MainWindow.start_vault_sync": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [176, 179], "excluded_lines": []}, "MainWindow.start_vault_sync._runner": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [177], "excluded_lines": []}, "MainWindow.sync_started": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [183], "excluded_lines": []}, "MainWindow.sync_finished": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [186, 187], "excluded_lines": []}, "MainWindow.vault_locked": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [190, 191, 192], "excluded_lines": []}, "MainWindow.cleanup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [195, 196, 197, 198, 199, 200], "excluded_lines": []}, "EntryDialog.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 42, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 42, "excluded_lines": 0}, "missing_lines": [207, 208, 209, 210, 212, 213, 217, 218, 219, 220, 223, 224, 226, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259], "excluded_lines": []}, "EntryDialog.save": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 51, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 51, "excluded_lines": 0}, "missing_lines": [262, 263, 264, 265, 266, 267, 268, 270, 271, 272, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 289, 290, 292, 293, 294, 295, 296, 297, 298, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 312, 320, 321, 323, 324, 325, 326, 327, 329, 331], "excluded_lines": []}, "SearchDialog.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [338, 339, 340, 341, 344, 345, 346, 347, 348], "excluded_lines": []}, "SearchDialog.do_search": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [351, 352, 353, 354, 355, 364], "excluded_lines": []}, "TotpViewerWindow.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [371, 372, 373, 375, 380, 381, 382, 384, 385, 386], "excluded_lines": []}, "TotpViewerWindow._update_loop": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [389, 390, 391], "excluded_lines": []}, "TotpViewerWindow.refresh_codes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [394, 395, 398, 399, 400, 401, 402], "excluded_lines": []}, "TotpViewerWindow.cleanup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [405], "excluded_lines": []}, "RelayManagerDialog.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [412, 413, 414, 416, 417, 418, 419, 420, 422, 423, 424, 425, 426, 427, 428, 429, 430, 432], "excluded_lines": []}, "RelayManagerDialog.refresh": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [435, 436, 437], "excluded_lines": []}, "RelayManagerDialog.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 3}, "missing_lines": [440, 441, 442, 443, 444, 448, 449], "excluded_lines": [445, 446, 447]}, "RelayManagerDialog.remove_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 3}, "missing_lines": [452, 453, 454, 455, 456, 457, 461], "excluded_lines": [458, 459, 460]}, "build": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [466], "excluded_lines": []}, "SeedPassApp.startup": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 11}, "missing_lines": [], "excluded_lines": [471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481]}, "main": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [485, 486]}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 46, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 46, "excluded_lines": 2}, "missing_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 21, 24, 27, 53, 71, 74, 125, 150, 154, 161, 165, 169, 173, 182, 185, 189, 194, 203, 206, 261, 334, 337, 350, 367, 370, 388, 393, 404, 408, 411, 434, 439, 451, 464, 469], "excluded_lines": [470, 484]}}, "classes": {"LockScreenWindow": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 3}, "missing_lines": [33, 36, 37, 38, 40, 41, 42, 46, 47, 48, 49, 50, 51, 54, 55, 56, 60, 66, 67, 68], "excluded_lines": [57, 58, 59]}, "MainWindow": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 72, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 72, "excluded_lines": 0}, "missing_lines": [81, 84, 85, 86, 87, 88, 89, 90, 91, 93, 94, 100, 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 112, 113, 115, 117, 118, 119, 120, 121, 123, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 151, 152, 155, 156, 157, 158, 159, 162, 163, 166, 167, 170, 171, 176, 177, 179, 183, 186, 187, 190, 191, 192, 195, 196, 197, 198, 199, 200], "excluded_lines": []}, "EntryDialog": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 93, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 93, "excluded_lines": 0}, "missing_lines": [207, 208, 209, 210, 212, 213, 217, 218, 219, 220, 223, 224, 226, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 262, 263, 264, 265, 266, 267, 268, 270, 271, 272, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 289, 290, 292, 293, 294, 295, 296, 297, 298, 300, 301, 302, 303, 304, 305, 306, 307, 308, 310, 312, 320, 321, 323, 324, 325, 326, 327, 329, 331], "excluded_lines": []}, "SearchDialog": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [338, 339, 340, 341, 344, 345, 346, 347, 348, 351, 352, 353, 354, 355, 364], "excluded_lines": []}, "TotpViewerWindow": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [371, 372, 373, 375, 380, 381, 382, 384, 385, 386, 389, 390, 391, 394, 395, 398, 399, 400, 401, 402, 405], "excluded_lines": []}, "RelayManagerDialog": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 35, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 35, "excluded_lines": 6}, "missing_lines": [412, 413, 414, 416, 417, 418, 419, 420, 422, 423, 424, 425, 426, 427, 428, 429, 430, 432, 435, 436, 437, 440, 441, 442, 443, 444, 448, 449, 452, 453, 454, 455, 456, 457, 461], "excluded_lines": [445, 446, 447, 458, 459, 460]}, "SeedPassApp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 11}, "missing_lines": [], "excluded_lines": [471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481]}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 47, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 47, "excluded_lines": 4}, "missing_lines": [1, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 21, 24, 27, 53, 71, 74, 125, 150, 154, 161, 165, 169, 173, 182, 185, 189, 194, 203, 206, 261, 334, 337, 350, 367, 370, 388, 393, 404, 408, 411, 434, 439, 451, 464, 466, 469], "excluded_lines": [470, 484, 485, 486]}}}, "src/tests/conftest.py": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 14, 15, 26, 27, 28, 29, 30, 33, 36, 40, 41, 42, 45, 46, 52, 58, 66, 67, 68, 71, 74, 77, 78, 79, 82, 83, 84, 85, 89, 90, 95, 96, 115, 116, 153, 154, 194, 195], "summary": {"covered_lines": 48, "num_statements": 105, "percent_covered": 45.714285714285715, "percent_covered_display": "46", "missing_lines": 57, "excluded_lines": 0}, "missing_lines": [37, 75, 80, 86, 91, 92, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 117, 145, 146, 147, 148, 149, 150, 156, 157, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 172, 174, 175, 176, 178, 179, 181, 182, 183, 185, 186, 187, 188, 189, 191, 196], "excluded_lines": [], "functions": {"anyio_backend": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [37], "excluded_lines": []}, "mute_logging": {"executed_lines": [42], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pytest_addoption": {"executed_lines": [46, 52, 58], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pytest_configure": {"executed_lines": [67, 68], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pytest_collection_modifyitems": {"executed_lines": [74, 77, 78, 79, 82, 83, 84, 85], "summary": {"covered_lines": 8, "num_statements": 11, "percent_covered": 72.72727272727273, "percent_covered_display": "73", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [75, 80, 86], "excluded_lines": []}, "vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [91, 92], "excluded_lines": []}, "password_manager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112], "excluded_lines": []}, "client": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [117, 145, 146, 147, 148, 149, 150], "excluded_lines": []}, "make_dummy_nostr_client": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [156, 157, 159, 191], "excluded_lines": []}, "make_dummy_nostr_client._make": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 172, 174, 175, 178, 181, 182, 185, 186, 187, 188, 189], "excluded_lines": []}, "make_dummy_nostr_client._make.DummyKeys.private_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [176], "excluded_lines": []}, "make_dummy_nostr_client._make.DummyKeys.public_key_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [179], "excluded_lines": []}, "make_dummy_nostr_client._make.DummyKeyManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [183], "excluded_lines": []}, "dummy_nostr_client": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [196], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 14, 15, 26, 27, 28, 29, 30, 33, 36, 40, 41, 45, 66, 71, 89, 90, 95, 96, 115, 116, 153, 154, 194, 195], "summary": {"covered_lines": 34, "num_statements": 34, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"make_dummy_nostr_client._make.DummyKeys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [176, 179], "excluded_lines": []}, "make_dummy_nostr_client._make.DummyKeyManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [183], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 14, 15, 26, 27, 28, 29, 30, 33, 36, 40, 41, 42, 45, 46, 52, 58, 66, 67, 68, 71, 74, 77, 78, 79, 82, 83, 84, 85, 89, 90, 95, 96, 115, 116, 153, 154, 194, 195], "summary": {"covered_lines": 48, "num_statements": 102, "percent_covered": 47.05882352941177, "percent_covered_display": "47", "missing_lines": 54, "excluded_lines": 0}, "missing_lines": [37, 75, 80, 86, 91, 92, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 117, 145, 146, 147, 148, 149, 150, 156, 157, 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, 170, 172, 174, 175, 178, 181, 182, 185, 186, 187, 188, 189, 191, 196], "excluded_lines": []}}}, "src/tests/helpers.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 11, 12, 18, 22, 25, 42, 43, 49, 53, 54, 59, 63, 64, 74, 79, 83, 84, 85, 88, 89, 92, 93, 96, 97, 101, 102, 109, 112, 121, 125, 130, 134, 139, 140, 143, 144, 148, 149, 152, 155, 156, 160, 161, 165, 166, 174, 177, 180, 183, 186, 209], "summary": {"covered_lines": 57, "num_statements": 167, "percent_covered": 34.131736526946106, "percent_covered_display": "34", "missing_lines": 110, "excluded_lines": 0}, "missing_lines": [31, 32, 33, 34, 36, 37, 38, 39, 44, 45, 46, 47, 50, 55, 56, 57, 60, 65, 66, 67, 68, 70, 71, 72, 76, 77, 80, 86, 90, 94, 98, 103, 104, 105, 106, 107, 110, 113, 114, 115, 116, 118, 119, 122, 123, 126, 127, 128, 131, 132, 135, 136, 141, 145, 150, 153, 157, 162, 167, 168, 169, 170, 171, 172, 175, 178, 181, 184, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 226, 227, 228, 230, 231, 233], "excluded_lines": [], "functions": {"create_vault": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [31, 32, 33, 34, 36, 37, 38, 39], "excluded_lines": []}, "DummyEvent.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [44, 45, 46, 47], "excluded_lines": []}, "DummyEvent.content": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [50], "excluded_lines": []}, "DummyUnsignedEvent.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [55, 56, 57], "excluded_lines": []}, "DummyUnsignedEvent.sign_with_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [60], "excluded_lines": []}, "DummyBuilder.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [65, 66, 67, 68, 70, 71, 72], "excluded_lines": []}, "DummyBuilder.tags": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [76, 77], "excluded_lines": []}, "DummyBuilder.build": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [80], "excluded_lines": []}, "DummyTag.identifier": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [86], "excluded_lines": []}, "DummyTag.event": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [90], "excluded_lines": []}, "DummyTag.alt": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [94], "excluded_lines": []}, "DummyTag.expiration": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [98], "excluded_lines": []}, "DummyFilter.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [103, 104, 105, 106, 107], "excluded_lines": []}, "DummyFilter.author": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [110], "excluded_lines": []}, "DummyFilter.kind": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [113, 114, 115, 116, 118, 119], "excluded_lines": []}, "DummyFilter.identifier": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [122, 123], "excluded_lines": []}, "DummyFilter.id": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [126, 127, 128], "excluded_lines": []}, "DummyFilter.limit": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [131, 132], "excluded_lines": []}, "DummyFilter.since": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [135, 136], "excluded_lines": []}, "DummyTimestamp.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [141], "excluded_lines": []}, "DummyTimestamp.from_secs": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [145], "excluded_lines": []}, "DummyEventId.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [150], "excluded_lines": []}, "DummyEventId.to_hex": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [153], "excluded_lines": []}, "DummyEventId.parse": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [157], "excluded_lines": []}, "DummySendResult.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [162], "excluded_lines": []}, "DummyRelayClient.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [167, 168, 169, 170, 171, 172], "excluded_lines": []}, "DummyRelayClient.add_relays": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [175], "excluded_lines": []}, "DummyRelayClient.add_relay": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [178], "excluded_lines": []}, "DummyRelayClient.connect": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [181], "excluded_lines": []}, "DummyRelayClient.disconnect": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [184], "excluded_lines": []}, "DummyRelayClient.send_event": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207], "excluded_lines": []}, "DummyRelayClient.fetch_events": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 19, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 19, "excluded_lines": 0}, "missing_lines": [210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 226, 227, 230, 233], "excluded_lines": []}, "DummyRelayClient.fetch_events.Result.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [228], "excluded_lines": []}, "DummyRelayClient.fetch_events.Result.to_vec": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [231], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 11, 12, 18, 22, 25, 42, 43, 49, 53, 54, 59, 63, 64, 74, 79, 83, 84, 85, 88, 89, 92, 93, 96, 97, 101, 102, 109, 112, 121, 125, 130, 134, 139, 140, 143, 144, 148, 149, 152, 155, 156, 160, 161, 165, 166, 174, 177, 180, 183, 186, 209], "summary": {"covered_lines": 57, "num_statements": 57, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"DummyEvent": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [44, 45, 46, 47, 50], "excluded_lines": []}, "DummyUnsignedEvent": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [55, 56, 57, 60], "excluded_lines": []}, "DummyBuilder": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [65, 66, 67, 68, 70, 71, 72, 76, 77, 80], "excluded_lines": []}, "DummyTag": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [86, 90, 94, 98], "excluded_lines": []}, "DummyFilter": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 21, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 21, "excluded_lines": 0}, "missing_lines": [103, 104, 105, 106, 107, 110, 113, 114, 115, 116, 118, 119, 122, 123, 126, 127, 128, 131, 132, 135, 136], "excluded_lines": []}, "DummyTimestamp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [141, 145], "excluded_lines": []}, "DummyEventId": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [150, 153, 157], "excluded_lines": []}, "DummySendResult": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [162], "excluded_lines": []}, "DummyRelayClient": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 50, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 50, "excluded_lines": 0}, "missing_lines": [167, 168, 169, 170, 171, 172, 175, 178, 181, 184, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 226, 227, 230, 233], "excluded_lines": []}, "DummyRelayClient.fetch_events.Result": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [228, 231], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 11, 12, 18, 22, 25, 42, 43, 49, 53, 54, 59, 63, 64, 74, 79, 83, 84, 85, 88, 89, 92, 93, 96, 97, 101, 102, 109, 112, 121, 125, 130, 134, 139, 140, 143, 144, 148, 149, 152, 155, 156, 160, 161, 165, 166, 174, 177, 180, 183, 186, 209], "summary": {"covered_lines": 57, "num_statements": 65, "percent_covered": 87.6923076923077, "percent_covered_display": "88", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [31, 32, 33, 34, 36, 37, 38, 39], "excluded_lines": []}}}, "src/tests/test_ai_tui_agent_harness.py": {"executed_lines": [1, 3, 4, 5, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 24, 25, 26, 28, 29, 31, 33, 34, 35, 36, 37, 40, 41, 43, 44, 46, 47, 49, 50, 51, 52, 55, 56, 57, 58, 59, 61, 62, 64, 65, 67, 68, 69, 70, 71, 74, 75, 76, 77, 78, 80, 81, 83, 84, 86, 87, 88, 89, 94, 95, 96, 97, 105, 107, 108, 109, 110, 112, 113, 115, 118, 119, 120, 121, 124, 125, 126, 129, 132, 135, 136, 137, 140, 141, 142, 143, 144, 146, 147, 148, 149, 150, 152, 153, 154, 156, 159, 160, 161, 162, 163, 166, 167, 168, 169, 171, 172, 174, 175, 177, 178, 180, 183], "summary": {"covered_lines": 118, "num_statements": 123, "percent_covered": 95.9349593495935, "percent_covered_display": "96", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [116, 127, 130, 133, 157], "excluded_lines": [], "functions": {"_load_harness_module": {"executed_lines": [11, 12, 13, 14, 15, 16, 17, 18], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_run_step_records_passed_result": {"executed_lines": [25, 26, 28, 31, 33, 34, 35, 36, 37], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_run_step_records_passed_result._ok": {"executed_lines": [29], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_run_step_records_failed_result_and_reraises": {"executed_lines": [41, 43, 46, 47, 49, 50, 51, 52], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_run_step_records_failed_result_and_reraises._boom": {"executed_lines": [44], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_waits_when_choice_omitted": {"executed_lines": [56, 57, 61, 64, 67, 68, 69, 70, 71], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_waits_when_choice_omitted.Runner.__init__": {"executed_lines": [58, 59], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_waits_when_choice_omitted.Runner.sendline": {"executed_lines": [62], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_waits_when_choice_omitted.Runner.wait_for": {"executed_lines": [65], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_sends_choice_when_provided": {"executed_lines": [75, 76, 80, 83, 86, 87, 88, 89], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_sends_choice_when_provided.Runner.__init__": {"executed_lines": [77, 78], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_sends_choice_when_provided.Runner.sendline": {"executed_lines": [81], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_sends_choice_when_provided.Runner.expect_and_send": {"executed_lines": [84], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password": {"executed_lines": [95, 96, 107, 112, 115, 118, 119, 120, 121], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password.Runner.__init__": {"executed_lines": [97, 105], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password.Runner.try_wait_for": {"executed_lines": [108, 109, 110], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password.Runner.sendline": {"executed_lines": [113], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password.Runner.pump": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [116], "excluded_lines": []}, "test_complete_onboarding_times_out_without_expected_prompts": {"executed_lines": [125, 126, 129, 132, 135, 136, 137], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_times_out_without_expected_prompts.Runner.try_wait_for": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [127], "excluded_lines": []}, "test_complete_onboarding_times_out_without_expected_prompts.Runner.sendline": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [130], "excluded_lines": []}, "test_complete_onboarding_times_out_without_expected_prompts.Runner.pump": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [133], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns": {"executed_lines": [141, 142, 146, 152, 156, 159, 160, 161, 162, 163], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns.Runner.__init__": {"executed_lines": [143, 144], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns.Runner.wait_for": {"executed_lines": [147, 148, 149, 150], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns.Runner.expect_and_send": {"executed_lines": [153, 154], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns.Runner.pump": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [157], "excluded_lines": []}, "test_drain_to_main_menu_times_out_when_no_prompt_progress": {"executed_lines": [167, 168, 171, 174, 177, 178, 180, 183], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_times_out_when_no_prompt_progress.Runner.wait_for": {"executed_lines": [169], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_times_out_when_no_prompt_progress.Runner.expect_and_send": {"executed_lines": [172], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_drain_to_main_menu_times_out_when_no_prompt_progress.Runner.pump": {"executed_lines": [175], "summary": {"covered_lines": 1, "num_statements": 1, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 10, 21, 24, 40, 55, 74, 94, 124, 140, 166], "summary": {"covered_lines": 15, "num_statements": 15, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"test_add_entry_menu_open_waits_when_choice_omitted.Runner": {"executed_lines": [58, 59, 62, 65], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_add_entry_menu_open_sends_choice_when_provided.Runner": {"executed_lines": [77, 78, 81, 84], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_complete_onboarding_reaches_main_menu_and_sends_password.Runner": {"executed_lines": [97, 105, 108, 109, 110, 113], "summary": {"covered_lines": 6, "num_statements": 7, "percent_covered": 85.71428571428571, "percent_covered_display": "86", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [116], "excluded_lines": []}, "test_complete_onboarding_times_out_without_expected_prompts.Runner": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 0}, "missing_lines": [127, 130, 133], "excluded_lines": []}, "test_drain_to_main_menu_uses_helper_prompt_then_returns.Runner": {"executed_lines": [143, 144, 147, 148, 149, 150, 153, 154], "summary": {"covered_lines": 8, "num_statements": 9, "percent_covered": 88.88888888888889, "percent_covered_display": "89", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [157], "excluded_lines": []}, "test_drain_to_main_menu_times_out_when_no_prompt_progress.Runner": {"executed_lines": [169, 172, 175], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 24, 25, 26, 28, 29, 31, 33, 34, 35, 36, 37, 40, 41, 43, 44, 46, 47, 49, 50, 51, 52, 55, 56, 57, 61, 64, 67, 68, 69, 70, 71, 74, 75, 76, 80, 83, 86, 87, 88, 89, 94, 95, 96, 107, 112, 115, 118, 119, 120, 121, 124, 125, 126, 129, 132, 135, 136, 137, 140, 141, 142, 146, 152, 156, 159, 160, 161, 162, 163, 166, 167, 168, 171, 174, 177, 178, 180, 183], "summary": {"covered_lines": 93, "num_statements": 93, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/tests/test_check_critical_coverage.py": {"executed_lines": [1, 3, 4, 5, 7, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 26, 27, 30, 31, 34, 44, 45, 46, 49, 50, 56, 57, 60, 61, 62, 78, 81, 82, 83, 84], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"_load_module": {"executed_lines": [11, 12, 13, 16, 17, 18, 19, 20], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_parse_threshold_overrides_valid": {"executed_lines": [27, 30, 31], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_parse_threshold_overrides_invalid": {"executed_lines": [45, 46], "summary": {"covered_lines": 2, "num_statements": 2, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_find_file_payload_accepts_absolute_path_suffix": {"executed_lines": [50, 56, 57], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "test_compute_function_coverage_reports_uncovered": {"executed_lines": [61, 62, 78, 81, 82, 83, 84], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 10, 23, 26, 34, 44, 49, 60], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 7, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 26, 27, 30, 31, 34, 44, 45, 46, 49, 50, 56, 57, 60, 61, 62, 78, 81, 82, 83, 84], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/utils/__init__.py": {"executed_lines": [3, 5, 7, 9, 10, 19, 27, 28, 29, 30, 31, 37, 40, 41, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 10}, "missing_lines": [], "excluded_lines": [40, 41, 42, 43, 45, 46, 48, 49, 50, 51], "functions": {"": {"executed_lines": [3, 5, 7, 9, 10, 19, 27, 28, 29, 30, 31, 37, 40, 41, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 10}, "missing_lines": [], "excluded_lines": [40, 41, 42, 43, 45, 46, 48, 49, 50, 51]}}, "classes": {"": {"executed_lines": [3, 5, 7, 9, 10, 19, 27, 28, 29, 30, 31, 37, 40, 41, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 10}, "missing_lines": [], "excluded_lines": [40, 41, 42, 43, 45, 46, 48, 49, 50, 51]}}}, "src/utils/atomic_write.py": {"executed_lines": [1, 14, 16, 17, 18, 19, 22, 62], "summary": {"covered_lines": 7, "num_statements": 22, "percent_covered": 31.818181818181817, "percent_covered_display": "32", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [44, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59], "excluded_lines": [], "functions": {"atomic_write": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 15, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [44, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59], "excluded_lines": []}, "": {"executed_lines": [1, 14, 16, 17, 18, 19, 22, 62], "summary": {"covered_lines": 7, "num_statements": 7, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 14, 16, 17, 18, 19, 22, 62], "summary": {"covered_lines": 7, "num_statements": 22, "percent_covered": 31.818181818181817, "percent_covered_display": "32", "missing_lines": 15, "excluded_lines": 0}, "missing_lines": [44, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59], "excluded_lines": []}}}, "src/utils/checksum.py": {"executed_lines": [3, 13, 14, 15, 16, 17, 18, 20, 22, 23, 26, 29, 34, 40, 78, 109, 140, 165, 201], "summary": {"covered_lines": 18, "num_statements": 95, "percent_covered": 18.94736842105263, "percent_covered_display": "19", "missing_lines": 77, "excluded_lines": 0}, "missing_lines": [31, 36, 37, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 65, 66, 67, 70, 75, 89, 90, 91, 92, 93, 94, 95, 96, 99, 101, 102, 103, 105, 106, 120, 121, 122, 123, 124, 125, 126, 127, 128, 131, 137, 151, 152, 153, 155, 156, 157, 158, 160, 161, 162, 176, 177, 178, 180, 181, 182, 185, 186, 187, 188, 192, 198, 203, 204, 205, 206, 207, 208, 211, 212, 213, 217, 223], "excluded_lines": [], "functions": {"canonical_json_dumps": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [31], "excluded_lines": []}, "json_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [36, 37], "excluded_lines": []}, "calculate_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 65, 66, 67, 70, 75], "excluded_lines": []}, "verify_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [89, 90, 91, 92, 93, 94, 95, 96, 99, 101, 102, 103, 105, 106], "excluded_lines": []}, "update_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [120, 121, 122, 123, 124, 125, 126, 127, 128, 131, 137], "excluded_lines": []}, "verify_and_update_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [151, 152, 153, 155, 156, 157, 158, 160, 161, 162], "excluded_lines": []}, "initialize_checksum": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [176, 177, 178, 180, 181, 182, 185, 186, 187, 188, 192, 198], "excluded_lines": []}, "update_checksum_file": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [203, 204, 205, 206, 207, 208, 211, 212, 213, 217, 223], "excluded_lines": []}, "": {"executed_lines": [3, 13, 14, 15, 16, 17, 18, 20, 22, 23, 26, 29, 34, 40, 78, 109, 140, 165, 201], "summary": {"covered_lines": 18, "num_statements": 18, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 13, 14, 15, 16, 17, 18, 20, 22, 23, 26, 29, 34, 40, 78, 109, 140, 165, 201], "summary": {"covered_lines": 18, "num_statements": 95, "percent_covered": 18.94736842105263, "percent_covered_display": "19", "missing_lines": 77, "excluded_lines": 0}, "missing_lines": [31, 36, 37, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 65, 66, 67, 70, 75, 89, 90, 91, 92, 93, 94, 95, 96, 99, 101, 102, 103, 105, 106, 120, 121, 122, 123, 124, 125, 126, 127, 128, 131, 137, 151, 152, 153, 155, 156, 157, 158, 160, 161, 162, 176, 177, 178, 180, 181, 182, 185, 186, 187, 188, 192, 198, 203, 204, 205, 206, 207, 208, 211, 212, 213, 217, 223], "excluded_lines": []}}}, "src/utils/clipboard.py": {"executed_lines": [1, 3, 4, 5, 6, 8, 11, 12, 15, 18, 35, 52], "summary": {"covered_lines": 10, "num_statements": 26, "percent_covered": 38.46153846153846, "percent_covered_display": "38", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [20, 21, 22, 23, 24, 25, 29, 38, 40, 42, 43, 44, 46, 47, 48, 49], "excluded_lines": [], "functions": {"_ensure_clipboard": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [20, 21, 22, 23, 24, 25, 29], "excluded_lines": []}, "copy_to_clipboard": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [38, 40, 42, 46, 47, 48, 49], "excluded_lines": []}, "copy_to_clipboard.clear_clipboard": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [43, 44], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 11, 12, 15, 18, 35, 52], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"ClipboardUnavailableError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 8, 11, 12, 15, 18, 35, 52], "summary": {"covered_lines": 10, "num_statements": 26, "percent_covered": 38.46153846153846, "percent_covered_display": "38", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [20, 21, 22, 23, 24, 25, 29, 38, 40, 42, 43, 44, 46, 47, 48, 49], "excluded_lines": []}}}, "src/utils/color_scheme.py": {"executed_lines": [1, 3, 6, 7, 10, 16, 29], "summary": {"covered_lines": 6, "num_statements": 12, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [12, 31, 32, 33, 34, 35], "excluded_lines": [], "functions": {"_apply_orange": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [12], "excluded_lines": []}, "color_text": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [31, 32, 33, 34, 35], "excluded_lines": []}, "": {"executed_lines": [1, 3, 6, 7, 10, 16, 29], "summary": {"covered_lines": 6, "num_statements": 6, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 6, 7, 10, 16, 29], "summary": {"covered_lines": 6, "num_statements": 12, "percent_covered": 50.0, "percent_covered_display": "50", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [12, 31, 32, 33, 34, 35], "excluded_lines": []}}}, "src/utils/file_lock.py": {"executed_lines": [1, 3, 4, 5, 6, 7, 10, 11, 42, 43], "summary": {"covered_lines": 9, "num_statements": 27, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [21, 22, 23, 24, 25, 26, 32, 38, 39, 53, 54, 55, 56, 57, 63, 69, 70, 71], "excluded_lines": [], "functions": {"exclusive_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [21, 22, 23, 24, 25, 26, 32, 38, 39], "excluded_lines": []}, "shared_lock": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [53, 54, 55, 56, 57, 63, 69, 70, 71], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 6, 7, 10, 11, 42, 43], "summary": {"covered_lines": 9, "num_statements": 9, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 6, 7, 10, 11, 42, 43], "summary": {"covered_lines": 9, "num_statements": 27, "percent_covered": 33.333333333333336, "percent_covered_display": "33", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [21, 22, 23, 24, 25, 26, 32, 38, 39, 53, 54, 55, 56, 57, 63, 69, 70, 71], "excluded_lines": []}}}, "src/utils/fingerprint.py": {"executed_lines": [3, 11, 12, 13, 16, 19], "summary": {"covered_lines": 5, "num_statements": 16, "percent_covered": 31.25, "percent_covered_display": "31", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [30, 32, 33, 36, 37, 40, 41, 43, 44, 45, 46], "excluded_lines": [], "functions": {"generate_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 11, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [30, 32, 33, 36, 37, 40, 41, 43, 44, 45, 46], "excluded_lines": []}, "": {"executed_lines": [3, 11, 12, 13, 16, 19], "summary": {"covered_lines": 5, "num_statements": 5, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [3, 11, 12, 13, 16, 19], "summary": {"covered_lines": 5, "num_statements": 16, "percent_covered": 31.25, "percent_covered_display": "31", "missing_lines": 11, "excluded_lines": 0}, "missing_lines": [30, 32, 33, 36, 37, 40, 41, 43, 44, 45, 46], "excluded_lines": []}}}, "src/utils/fingerprint_manager.py": {"executed_lines": [3, 4, 5, 6, 7, 9, 11, 12, 15, 18, 19, 27, 43, 56, 69, 90, 111, 141, 185, 195, 214, 225, 229, 234], "summary": {"covered_lines": 23, "num_statements": 122, "percent_covered": 18.852459016393443, "percent_covered_display": "19", "missing_lines": 99, "excluded_lines": 0}, "missing_lines": [34, 35, 36, 37, 50, 51, 53, 54, 60, 61, 62, 63, 64, 67, 71, 72, 73, 74, 75, 76, 77, 78, 81, 82, 85, 86, 87, 88, 94, 95, 100, 104, 107, 108, 109, 122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 138, 139, 154, 155, 156, 157, 158, 159, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 180, 182, 183, 192, 193, 205, 206, 207, 208, 209, 211, 212, 216, 217, 218, 219, 221, 222, 223, 227, 231, 232, 244, 245, 246, 248, 249], "excluded_lines": [], "functions": {"FingerprintManager.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [34, 35, 36, 37], "excluded_lines": []}, "FingerprintManager.get_current_fingerprint_dir": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [50, 51, 53, 54], "excluded_lines": []}, "FingerprintManager._ensure_app_directory": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [60, 61, 62, 63, 64, 67], "excluded_lines": []}, "FingerprintManager._load_fingerprints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [71, 72, 73, 74, 75, 76, 77, 78, 81, 82, 85, 86, 87, 88], "excluded_lines": []}, "FingerprintManager._save_fingerprints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [94, 95, 100, 104, 107, 108, 109], "excluded_lines": []}, "FingerprintManager.add_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 138, 139], "excluded_lines": []}, "FingerprintManager.remove_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 24, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 24, "excluded_lines": 0}, "missing_lines": [154, 155, 156, 157, 158, 159, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 180, 182, 183], "excluded_lines": []}, "FingerprintManager.list_fingerprints": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [192, 193], "excluded_lines": []}, "FingerprintManager.select_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [205, 206, 207, 208, 209, 211, 212], "excluded_lines": []}, "FingerprintManager.set_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 0}, "missing_lines": [216, 217, 218, 219, 221, 222, 223], "excluded_lines": []}, "FingerprintManager.get_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [227], "excluded_lines": []}, "FingerprintManager.display_name": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [231, 232], "excluded_lines": []}, "FingerprintManager.get_fingerprint_directory": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 0}, "missing_lines": [244, 245, 246, 248, 249], "excluded_lines": []}, "": {"executed_lines": [3, 4, 5, 6, 7, 9, 11, 12, 15, 18, 19, 27, 43, 56, 69, 90, 111, 141, 185, 195, 214, 225, 229, 234], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"FingerprintManager": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 99, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 99, "excluded_lines": 0}, "missing_lines": [34, 35, 36, 37, 50, 51, 53, 54, 60, 61, 62, 63, 64, 67, 71, 72, 73, 74, 75, 76, 77, 78, 81, 82, 85, 86, 87, 88, 94, 95, 100, 104, 107, 108, 109, 122, 123, 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136, 138, 139, 154, 155, 156, 157, 158, 159, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 180, 182, 183, 192, 193, 205, 206, 207, 208, 209, 211, 212, 216, 217, 218, 219, 221, 222, 223, 227, 231, 232, 244, 245, 246, 248, 249], "excluded_lines": []}, "": {"executed_lines": [3, 4, 5, 6, 7, 9, 11, 12, 15, 18, 19, 27, 43, 56, 69, 90, 111, 141, 185, 195, 214, 225, 229, 234], "summary": {"covered_lines": 23, "num_statements": 23, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/utils/imghdr_stub.py": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 77, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 77, "excluded_lines": 39}, "missing_lines": [7, 9, 10, 12, 14, 25, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 51, 54, 56, 57, 58, 59, 62, 65, 67, 68, 71, 74, 76, 77, 80, 83, 85, 86, 89, 92, 94, 95, 98, 101, 103, 104, 107, 110, 112, 113, 116, 119, 121, 122, 125, 128, 130, 131, 134, 137, 139, 140, 143, 146, 148, 149, 152, 155, 157, 158, 161, 164, 166, 167, 170], "excluded_lines": [178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 219, 220], "functions": {"what": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44], "excluded_lines": []}, "test_jpeg": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [56, 57, 58, 59], "excluded_lines": []}, "test_png": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [67, 68], "excluded_lines": []}, "test_gif": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [76, 77], "excluded_lines": []}, "test_tiff": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [85, 86], "excluded_lines": []}, "test_rgb": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [94, 95], "excluded_lines": []}, "test_pbm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [103, 104], "excluded_lines": []}, "test_pgm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [112, 113], "excluded_lines": []}, "test_ppm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [121, 122], "excluded_lines": []}, "test_rast": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [130, 131], "excluded_lines": []}, "test_xbm": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [139, 140], "excluded_lines": []}, "test_bmp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [148, 149], "excluded_lines": []}, "test_webp": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [157, 158], "excluded_lines": []}, "test_exr": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [166, 167], "excluded_lines": []}, "test": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 14}, "missing_lines": [], "excluded_lines": [179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192]}, "testall": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 21}, "missing_lines": [], "excluded_lines": [196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216]}, "": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 33, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 33, "excluded_lines": 4}, "missing_lines": [7, 9, 10, 12, 14, 25, 51, 54, 62, 65, 71, 74, 80, 83, 89, 92, 98, 101, 107, 110, 116, 119, 125, 128, 134, 137, 143, 146, 152, 155, 161, 164, 170], "excluded_lines": [178, 195, 219, 220]}}, "classes": {"": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 77, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 77, "excluded_lines": 39}, "missing_lines": [7, 9, 10, 12, 14, 25, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 51, 54, 56, 57, 58, 59, 62, 65, 67, 68, 71, 74, 76, 77, 80, 83, 85, 86, 89, 92, 94, 95, 98, 101, 103, 104, 107, 110, 112, 113, 116, 119, 121, 122, 125, 128, 130, 131, 134, 137, 139, 140, 143, 146, 148, 149, 152, 155, 157, 158, 161, 164, 166, 167, 170], "excluded_lines": [178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 219, 220]}}}, "src/utils/input_utils.py": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 13, 25, 48], "summary": {"covered_lines": 10, "num_statements": 40, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 30, "excluded_lines": 4}, "missing_lines": [15, 16, 17, 18, 19, 20, 21, 22, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 50, 51, 52, 54, 55, 58], "excluded_lines": [9, 10, 27, 28], "functions": {"_timed_input_posix": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 0}, "missing_lines": [15, 16, 17, 18, 19, 20, 21, 22], "excluded_lines": []}, "_timed_input_windows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 2}, "missing_lines": [29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45], "excluded_lines": [27, 28]}, "timed_input": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [50, 51, 52, 54, 55, 58], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 13, 25, 48], "summary": {"covered_lines": 10, "num_statements": 10, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [9, 10]}}, "classes": {"": {"executed_lines": [1, 2, 3, 4, 5, 7, 8, 9, 10, 13, 25, 48], "summary": {"covered_lines": 10, "num_statements": 40, "percent_covered": 25.0, "percent_covered_display": "25", "missing_lines": 30, "excluded_lines": 4}, "missing_lines": [15, 16, 17, 18, 19, 20, 21, 22, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 50, 51, 52, 54, 55, 58], "excluded_lines": [9, 10, 27, 28]}}}, "src/utils/key_derivation.py": {"executed_lines": [3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 30, 31, 32, 35, 38, 39, 41, 44, 47, 49, 53, 54, 55, 57, 58, 59, 66, 71, 74, 136, 172, 214, 222, 227, 251], "summary": {"covered_lines": 35, "num_statements": 117, "percent_covered": 29.914529914529915, "percent_covered_display": "30", "missing_lines": 82, "excluded_lines": 5}, "missing_lines": [96, 97, 98, 100, 101, 104, 105, 108, 109, 111, 113, 115, 116, 123, 126, 127, 129, 131, 132, 133, 147, 148, 149, 151, 152, 153, 155, 156, 157, 166, 181, 183, 186, 188, 189, 191, 194, 201, 203, 204, 208, 209, 210, 211, 216, 217, 218, 219, 224, 229, 230, 231, 233, 234, 236, 237, 238, 239, 240, 242, 243, 244, 245, 246, 247, 248, 279, 280, 281, 282, 283, 284, 285, 289, 290, 291, 292, 293, 295, 296, 297, 298], "excluded_lines": [49, 50, 167, 168, 169], "functions": {"derive_key_from_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 20, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 20, "excluded_lines": 0}, "missing_lines": [96, 97, 98, 100, 101, 104, 105, 108, 109, 111, 113, 115, 116, 123, 126, 127, 129, 131, 132, 133], "excluded_lines": []}, "derive_key_from_password_argon2": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 3}, "missing_lines": [147, 148, 149, 151, 152, 153, 155, 156, 157, 166], "excluded_lines": [167, 168, 169]}, "derive_key_from_parent_seed": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 14, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 14, "excluded_lines": 0}, "missing_lines": [181, 183, 186, 188, 189, 191, 194, 201, 203, 204, 208, 209, 210, 211], "excluded_lines": []}, "derive_index_key_seed_only": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [216, 217, 218, 219], "excluded_lines": []}, "derive_index_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [224], "excluded_lines": []}, "derive_totp_secret": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 0}, "missing_lines": [229, 230, 231, 233, 234, 236, 237, 238, 239, 240, 242, 243, 244, 245, 246, 247, 248], "excluded_lines": []}, "calibrate_argon2_time_cost": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 16, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 16, "excluded_lines": 0}, "missing_lines": [279, 280, 281, 282, 283, 284, 285, 289, 290, 291, 292, 293, 295, 296, 297, 298], "excluded_lines": []}, "": {"executed_lines": [3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 30, 31, 32, 35, 38, 39, 41, 44, 47, 49, 53, 54, 55, 57, 58, 59, 66, 71, 74, 136, 172, 214, 222, 227, 251], "summary": {"covered_lines": 35, "num_statements": 35, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 2}, "missing_lines": [], "excluded_lines": [49, 50]}}, "classes": {"EncryptionMode": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "KdfConfig": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 30, 31, 32, 35, 38, 39, 41, 44, 47, 49, 53, 54, 55, 57, 58, 59, 66, 71, 74, 136, 172, 214, 222, 227, 251], "summary": {"covered_lines": 35, "num_statements": 117, "percent_covered": 29.914529914529915, "percent_covered_display": "30", "missing_lines": 82, "excluded_lines": 5}, "missing_lines": [96, 97, 98, 100, 101, 104, 105, 108, 109, 111, 113, 115, 116, 123, 126, 127, 129, 131, 132, 133, 147, 148, 149, 151, 152, 153, 155, 156, 157, 166, 181, 183, 186, 188, 189, 191, 194, 201, 203, 204, 208, 209, 210, 211, 216, 217, 218, 219, 224, 229, 230, 231, 233, 234, 236, 237, 238, 239, 240, 242, 243, 244, 245, 246, 247, 248, 279, 280, 281, 282, 283, 284, 285, 289, 290, 291, 292, 293, 295, 296, 297, 298], "excluded_lines": [49, 50, 167, 168, 169]}}}, "src/utils/key_hierarchy.py": {"executed_lines": [1, 3, 4, 5, 8], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [21, 28], "excluded_lines": [], "functions": {"kd": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [21, 28], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 8], "summary": {"covered_lines": 4, "num_statements": 4, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 8], "summary": {"covered_lines": 4, "num_statements": 6, "percent_covered": 66.66666666666667, "percent_covered_display": "67", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [21, 28], "excluded_lines": []}}}, "src/utils/key_validation.py": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 10, 13, 23, 41, 51, 63], "summary": {"covered_lines": 12, "num_statements": 29, "percent_covered": 41.37931034482759, "percent_covered_display": "41", "missing_lines": 17, "excluded_lines": 15}, "missing_lines": [15, 16, 17, 25, 26, 27, 35, 43, 44, 45, 53, 54, 55, 56, 57, 65, 66], "excluded_lines": [18, 19, 20, 36, 37, 38, 46, 47, 48, 58, 59, 60, 67, 68, 69], "functions": {"validate_totp_secret": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 3}, "missing_lines": [15, 16, 17], "excluded_lines": [18, 19, 20]}, "validate_ssh_key_pair": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 3}, "missing_lines": [25, 26, 27, 35], "excluded_lines": [36, 37, 38]}, "validate_pgp_private_key": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 3, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 3, "excluded_lines": 3}, "missing_lines": [43, 44, 45], "excluded_lines": [46, 47, 48]}, "validate_nostr_keys": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 5, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 5, "excluded_lines": 3}, "missing_lines": [53, 54, 55, 56, 57], "excluded_lines": [58, 59, 60]}, "validate_seed_phrase": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 3}, "missing_lines": [65, 66], "excluded_lines": [67, 68, 69]}, "": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 10, 13, 23, 41, 51, 63], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 6, 7, 8, 10, 13, 23, 41, 51, 63], "summary": {"covered_lines": 12, "num_statements": 29, "percent_covered": 41.37931034482759, "percent_covered_display": "41", "missing_lines": 17, "excluded_lines": 15}, "missing_lines": [15, 16, 17, 25, 26, 27, 35, 43, 44, 45, 53, 54, 55, 56, 57, 65, 66], "excluded_lines": [18, 19, 20, 36, 37, 38, 46, 47, 48, 58, 59, 60, 67, 68, 69]}}}, "src/utils/logging_utils.py": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 12, 18, 19, 21, 32, 38, 44, 45, 54, 57, 58, 62], "summary": {"covered_lines": 15, "num_statements": 23, "percent_covered": 65.21739130434783, "percent_covered_display": "65", "missing_lines": 8, "excluded_lines": 13}, "missing_lines": [35, 41, 47, 48, 49, 51, 59, 60], "excluded_lines": [12, 13, 14, 15, 21, 22, 23, 24, 25, 26, 27, 28, 29], "functions": {"ConsolePauseFilter.filter": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [15]}, "ChecksumWarningFilter.filter": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [24, 25, 26, 27, 28, 29]}, "pause_console_logging": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [35], "excluded_lines": []}, "resume_console_logging": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [41], "excluded_lines": []}, "console_logging_paused": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [47, 48, 49, 51], "excluded_lines": []}, "pause_logging_for_ui": {"executed_lines": [57, 58, 62], "summary": {"covered_lines": 3, "num_statements": 3, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "pause_logging_for_ui.wrapper": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 2, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 2, "excluded_lines": 0}, "missing_lines": [59, 60], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 12, 18, 19, 21, 32, 38, 44, 45, 54], "summary": {"covered_lines": 12, "num_statements": 12, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [12, 13, 14, 21, 22, 23]}}, "classes": {"ConsolePauseFilter": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 1}, "missing_lines": [], "excluded_lines": [15]}, "ChecksumWarningFilter": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 6}, "missing_lines": [], "excluded_lines": [24, 25, 26, 27, 28, 29]}, "": {"executed_lines": [1, 2, 3, 4, 6, 9, 10, 12, 18, 19, 21, 32, 38, 44, 45, 54, 57, 58, 62], "summary": {"covered_lines": 15, "num_statements": 23, "percent_covered": 65.21739130434783, "percent_covered_display": "65", "missing_lines": 8, "excluded_lines": 6}, "missing_lines": [35, 41, 47, 48, 49, 51, 59, 60], "excluded_lines": [12, 13, 14, 21, 22, 23]}}}, "src/utils/memory_protection.py": {"executed_lines": [1, 3, 4, 10, 11, 17, 25, 29, 36], "summary": {"covered_lines": 8, "num_statements": 20, "percent_covered": 40.0, "percent_covered_display": "40", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [18, 19, 20, 21, 22, 23, 27, 31, 32, 33, 34, 38], "excluded_lines": [], "functions": {"InMemorySecret.__init__": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [18, 19, 20, 21, 22, 23], "excluded_lines": []}, "InMemorySecret.get_bytes": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [27], "excluded_lines": []}, "InMemorySecret.wipe": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [31, 32, 33, 34], "excluded_lines": []}, "InMemorySecret.get_str": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [38], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 10, 11, 17, 25, 29, 36], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"InMemorySecret": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 12, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 12, "excluded_lines": 0}, "missing_lines": [18, 19, 20, 21, 22, 23, 27, 31, 32, 33, 34, 38], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 10, 11, 17, 25, 29, 36], "summary": {"covered_lines": 8, "num_statements": 8, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}}, "src/utils/password_prompt.py": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 22, 24, 27, 30, 33, 36, 42, 56, 65, 66, 68, 71, 158, 219, 259], "summary": {"covered_lines": 21, "num_statements": 126, "percent_covered": 16.666666666666668, "percent_covered_display": "17", "missing_lines": 105, "excluded_lines": 0}, "missing_lines": [39, 45, 46, 47, 48, 49, 50, 51, 52, 53, 59, 60, 61, 62, 89, 90, 91, 92, 93, 94, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 113, 114, 120, 123, 124, 125, 127, 128, 131, 132, 133, 134, 137, 138, 139, 141, 142, 143, 144, 145, 146, 149, 150, 151, 153, 154, 155, 180, 181, 182, 184, 185, 186, 187, 188, 190, 191, 194, 195, 196, 197, 199, 200, 201, 203, 204, 205, 206, 207, 208, 212, 213, 214, 216, 235, 236, 237, 238, 239, 240, 241, 242, 243, 245, 247, 248, 249, 250, 251, 252, 255, 256, 268], "excluded_lines": [], "functions": {"_env_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [39], "excluded_lines": []}, "_get_max_attempts": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [45, 46, 47, 48, 49, 50, 51, 52, 53], "excluded_lines": []}, "_apply_backoff": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [59, 60, 61, 62], "excluded_lines": []}, "prompt_new_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 45, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 45, "excluded_lines": 0}, "missing_lines": [89, 90, 91, 92, 93, 94, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 113, 114, 120, 123, 124, 125, 127, 128, 131, 132, 133, 134, 137, 138, 139, 141, 142, 143, 144, 145, 146, 149, 150, 151, 153, 154, 155], "excluded_lines": []}, "prompt_existing_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 27, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 27, "excluded_lines": 0}, "missing_lines": [180, 181, 182, 184, 185, 186, 187, 188, 190, 191, 194, 195, 196, 197, 199, 200, 201, 203, 204, 205, 206, 207, 208, 212, 213, 214, 216], "excluded_lines": []}, "confirm_action": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 18, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 18, "excluded_lines": 0}, "missing_lines": [235, 236, 237, 238, 239, 240, 241, 242, 243, 245, 247, 248, 249, 250, 251, 252, 255, 256], "excluded_lines": []}, "prompt_for_password": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [268], "excluded_lines": []}, "": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 22, 24, 27, 30, 33, 36, 42, 56, 65, 66, 68, 71, 158, 219, 259], "summary": {"covered_lines": 21, "num_statements": 21, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"PasswordPromptError": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}, "": {"executed_lines": [3, 14, 15, 16, 17, 18, 19, 21, 22, 24, 27, 30, 33, 36, 42, 56, 65, 66, 68, 71, 158, 219, 259], "summary": {"covered_lines": 21, "num_statements": 126, "percent_covered": 16.666666666666668, "percent_covered_display": "17", "missing_lines": 105, "excluded_lines": 0}, "missing_lines": [39, 45, 46, 47, 48, 49, 50, 51, 52, 53, 59, 60, 61, 62, 89, 90, 91, 92, 93, 94, 96, 97, 99, 100, 101, 102, 104, 105, 108, 109, 110, 111, 113, 114, 120, 123, 124, 125, 127, 128, 131, 132, 133, 134, 137, 138, 139, 141, 142, 143, 144, 145, 146, 149, 150, 151, 153, 154, 155, 180, 181, 182, 184, 185, 186, 187, 188, 190, 191, 194, 195, 196, 197, 199, 200, 201, 203, 204, 205, 206, 207, 208, 212, 213, 214, 216, 235, 236, 237, 238, 239, 240, 241, 242, 243, 245, 247, 248, 249, 250, 251, 252, 255, 256, 268], "excluded_lines": []}}}, "src/utils/seed_prompt.py": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 17, 18, 20, 23, 42, 51, 76, 107, 121], "summary": {"covered_lines": 17, "num_statements": 128, "percent_covered": 13.28125, "percent_covered_display": "13", "missing_lines": 111, "excluded_lines": 11}, "missing_lines": [31, 32, 33, 34, 35, 36, 37, 38, 39, 45, 46, 47, 48, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72, 73, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 102, 104, 109, 110, 111, 112, 113, 114, 118, 150, 152, 153, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 184, 185, 186, 187, 188, 189, 190, 191, 194, 195, 196, 197, 198, 199, 200, 201, 204, 205, 206, 207, 208, 209, 211, 212, 213, 214], "excluded_lines": [7, 8, 13, 14, 15, 53, 54, 78, 79, 115, 116], "functions": {"_get_max_attempts": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 9, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 9, "excluded_lines": 0}, "missing_lines": [31, 32, 33, 34, 35, 36, 37, 38, 39], "excluded_lines": []}, "_apply_backoff": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 4, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 4, "excluded_lines": 0}, "missing_lines": [45, 46, 47, 48], "excluded_lines": []}, "_masked_input_windows": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 17, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 17, "excluded_lines": 2}, "missing_lines": [56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72, 73], "excluded_lines": [53, 54]}, "_masked_input_posix": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 22, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 22, "excluded_lines": 2}, "missing_lines": [81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 102, 104], "excluded_lines": [78, 79]}, "masked_input": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 7, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 7, "excluded_lines": 2}, "missing_lines": [109, 110, 111, 112, 113, 114, 118], "excluded_lines": [115, 116]}, "prompt_seed_words": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 52, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 52, "excluded_lines": 0}, "missing_lines": [150, 152, 153, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 184, 185, 186, 187, 188, 189, 190, 191, 194, 195, 196, 197, 198, 199, 200, 201, 204, 205, 206, 207, 208, 209, 211, 212, 213, 214], "excluded_lines": []}, "": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 17, 18, 20, 23, 42, 51, 76, 107, 121], "summary": {"covered_lines": 17, "num_statements": 17, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 5}, "missing_lines": [], "excluded_lines": [7, 8, 13, 14, 15]}}, "classes": {"": {"executed_lines": [1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 17, 18, 20, 23, 42, 51, 76, 107, 121], "summary": {"covered_lines": 17, "num_statements": 128, "percent_covered": 13.28125, "percent_covered_display": "13", "missing_lines": 111, "excluded_lines": 11}, "missing_lines": [31, 32, 33, 34, 35, 36, 37, 38, 39, 45, 46, 47, 48, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72, 73, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 102, 104, 109, 110, 111, 112, 113, 114, 118, 150, 152, 153, 155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 184, 185, 186, 187, 188, 189, 190, 191, 194, 195, 196, 197, 198, 199, 200, 201, 204, 205, 206, 207, 208, 209, 211, 212, 213, 214], "excluded_lines": [7, 8, 13, 14, 15, 53, 54, 78, 79, 115, 116]}}}, "src/utils/terminal_utils.py": {"executed_lines": [1, 3, 4, 5, 7, 9, 12, 29, 34, 57, 73, 116], "summary": {"covered_lines": 11, "num_statements": 75, "percent_covered": 14.666666666666666, "percent_covered_display": "15", "missing_lines": 64, "excluded_lines": 6}, "missing_lines": [14, 15, 16, 17, 18, 19, 20, 26, 31, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 106, 107, 108, 109, 110, 111, 113, 118, 119, 120, 121, 122, 123], "excluded_lines": [21, 22, 25, 102, 103, 104], "functions": {"format_profile": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 8, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 8, "excluded_lines": 3}, "missing_lines": [14, 15, 16, 17, 18, 19, 20, 26], "excluded_lines": [21, 22, 25]}, "clear_screen": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 1, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 1, "excluded_lines": 0}, "missing_lines": [31], "excluded_lines": []}, "clear_and_print_fingerprint": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 13, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 13, "excluded_lines": 0}, "missing_lines": [42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54], "excluded_lines": []}, "clear_and_print_profile_chain": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 10, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 10, "excluded_lines": 0}, "missing_lines": [61, 62, 63, 64, 65, 66, 67, 68, 69, 70], "excluded_lines": []}, "clear_header_with_notification": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 26, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 26, "excluded_lines": 3}, "missing_lines": [82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 106, 107, 108, 109, 110, 111, 113], "excluded_lines": [102, 103, 104]}, "pause": {"executed_lines": [], "summary": {"covered_lines": 0, "num_statements": 6, "percent_covered": 0.0, "percent_covered_display": "0", "missing_lines": 6, "excluded_lines": 0}, "missing_lines": [118, 119, 120, 121, 122, 123], "excluded_lines": []}, "": {"executed_lines": [1, 3, 4, 5, 7, 9, 12, 29, 34, 57, 73, 116], "summary": {"covered_lines": 11, "num_statements": 11, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": []}}, "classes": {"": {"executed_lines": [1, 3, 4, 5, 7, 9, 12, 29, 34, 57, 73, 116], "summary": {"covered_lines": 11, "num_statements": 75, "percent_covered": 14.666666666666666, "percent_covered_display": "15", "missing_lines": 64, "excluded_lines": 6}, "missing_lines": [14, 15, 16, 17, 18, 19, 20, 26, 31, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 106, 107, 108, 109, 110, 111, 113, 118, 119, 120, 121, 122, 123], "excluded_lines": [21, 22, 25, 102, 103, 104]}}}}, "totals": {"covered_lines": 1503, "num_statements": 9825, "percent_covered": 15.297709923664122, "percent_covered_display": "15", "missing_lines": 8322, "excluded_lines": 274}} \ No newline at end of file diff --git a/artifacts/coverage/critical_gate.full.after_workers.json b/artifacts/coverage/critical_gate.full.after_workers.json new file mode 100644 index 00000000..602eeea4 --- /dev/null +++ b/artifacts/coverage/critical_gate.full.after_workers.json @@ -0,0 +1,35 @@ +{ + "status": "passed", + "failing_modules": [], + "modules": { + "src/main.py": { + "threshold_percent": 50.0, + "actual_percent": 54.170571696344894, + "meets_threshold": true, + "uncovered_functions": [], + "error": null + }, + "src/seedpass/core/encryption.py": { + "threshold_percent": 80.0, + "actual_percent": 83.09037900874635, + "meets_threshold": true, + "uncovered_functions": [], + "error": null + }, + "src/seedpass/core/manager.py": { + "threshold_percent": 60.0, + "actual_percent": 62.11616722160562, + "meets_threshold": true, + "uncovered_functions": [], + "error": null + }, + "src/seedpass/core/migrations.py": { + "threshold_percent": 90.0, + "actual_percent": 96.55172413793103, + "meets_threshold": true, + "uncovered_functions": [], + "error": null + } + }, + "coverage_json": "/home/user/Documents/GitHub/SeedPass/artifacts/coverage/coverage.full.after_workers.json" +} \ No newline at end of file diff --git a/artifacts/coverage/critical_gate.full.json b/artifacts/coverage/critical_gate.full.json new file mode 100644 index 00000000..660421a5 --- /dev/null +++ b/artifacts/coverage/critical_gate.full.json @@ -0,0 +1,44 @@ +{ + "status": "passed", + "failing_modules": [], + "modules": { + "src/main.py": { + "threshold_percent": 50.0, + "actual_percent": 54.170571696344894, + "meets_threshold": true, + "uncovered_functions": [], + "error": null + }, + "src/seedpass/core/encryption.py": { + "threshold_percent": 80.0, + "actual_percent": 83.09037900874635, + "meets_threshold": true, + "uncovered_functions": [], + "error": null + }, + "src/seedpass/core/manager.py": { + "threshold_percent": 60.0, + "actual_percent": 61.59822419533851, + "meets_threshold": true, + "uncovered_functions": [ + { + "name": "PasswordManager._worker", + "line": 1727 + }, + { + "name": "PasswordManager._async_worker", + "line": 1743 + } + ], + "error": null + }, + "src/seedpass/core/migrations.py": { + "threshold_percent": 90.0, + "actual_percent": 96.55172413793103, + "meets_threshold": true, + "uncovered_functions": [], + "error": null + } + }, + "coverage_json": "/home/user/Documents/GitHub/SeedPass/artifacts/coverage/coverage.full.json" +} \ No newline at end of file diff --git a/artifacts/coverage/critical_gate.smoke.json b/artifacts/coverage/critical_gate.smoke.json new file mode 100644 index 00000000..4c6855e7 --- /dev/null +++ b/artifacts/coverage/critical_gate.smoke.json @@ -0,0 +1,191 @@ +{ + "status": "passed", + "failing_modules": [], + "modules": { + "src/main.py": { + "threshold_percent": 0.0, + "actual_percent": 0.0, + "meets_threshold": true, + "uncovered_functions": [ + { + "name": "_warn_missing_optional_dependencies", + "line": 58 + }, + { + "name": "load_global_config", + "line": 71 + }, + { + "name": "configure_logging", + "line": 84 + }, + { + "name": "confirm_action", + "line": 117 + }, + { + "name": "drain_notifications", + "line": 134 + }, + { + "name": "get_notification_text", + "line": 149 + }, + { + "name": "handle_switch_fingerprint", + "line": 166 + }, + { + "name": "handle_add_new_fingerprint", + "line": 210 + }, + { + "name": "handle_remove_fingerprint", + "line": 223 + }, + { + "name": "_cleanup_and_exit", + "line": 247 + }, + { + "name": "handle_list_fingerprints", + "line": 276 + }, + { + "name": "handle_display_npub", + "line": 298 + }, + { + "name": "_display_live_stats", + "line": 316 + }, + { + "name": "handle_display_stats", + "line": 363 + }, + { + "name": "print_matches", + "line": 372 + }, + { + "name": "handle_post_to_nostr", + "line": 408 + }, + { + "name": "handle_retrieve_from_nostr", + "line": 435 + }, + { + "name": "handle_view_relays", + "line": 473 + }, + { + "name": "_safe_close_client_pool", + "line": 490 + }, + { + "name": "_reload_relays", + "line": 501 + }, + { + "name": "handle_add_relay", + "line": 514 + }, + { + "name": "handle_remove_relay", + "line": 545 + }, + { + "name": "handle_reset_relays", + "line": 582 + }, + { + "name": "handle_set_inactivity_timeout", + "line": 601 + }, + { + "name": "handle_set_kdf_iterations", + "line": 635 + }, + { + "name": "handle_set_additional_backup_location", + "line": 684 + }, + { + "name": "handle_set_profile_name", + "line": 733 + }, + { + "name": "handle_toggle_secret_mode", + "line": 752 + }, + { + "name": "handle_toggle_quick_unlock", + "line": 803 + }, + { + "name": "handle_toggle_offline_mode", + "line": 840 + }, + { + "name": "handle_profiles_menu", + "line": 878 + }, + { + "name": "handle_nostr_menu", + "line": 917 + }, + { + "name": "handle_settings", + "line": 971 + }, + { + "name": "display_menu", + "line": 1073 + }, + { + "name": "main", + "line": 1237 + }, + { + "name": "signal_handler", + "line": 1418 + } + ], + "error": null + }, + "src/seedpass/core/manager.py": { + "threshold_percent": 0.0, + "actual_percent": 8.213096559378469, + "meets_threshold": true, + "uncovered_functions": [ + { + "name": "PasswordManager.cached_derive", + "line": 1376 + }, + { + "name": "PasswordManager._worker", + "line": 1665 + }, + { + "name": "PasswordManager._worker", + "line": 1702 + }, + { + "name": "PasswordManager._worker", + "line": 1727 + }, + { + "name": "PasswordManager._async_worker", + "line": 1743 + }, + { + "name": "PasswordManager._load_archived_entries", + "line": 3913 + } + ], + "error": null + } + }, + "coverage_json": "/home/user/Documents/GitHub/SeedPass/artifacts/coverage/coverage.smoke.json" +} \ No newline at end of file diff --git a/docs/SPEC.md b/docs/SPEC.md new file mode 100644 index 00000000..c5a2d408 --- /dev/null +++ b/docs/SPEC.md @@ -0,0 +1,44 @@ +# SeedPass Specification + +## Key Hierarchy + +SeedPass derives a hierarchy of keys from a single BIP-39 parent seed using HKDF: + +- **Master Key** – `HKDF(seed, "seedpass:v1:master")` +- **KEY_STORAGE** – used to encrypt vault data. +- **KEY_INDEX** – protects the metadata index. +- **KEY_PW_DERIVE** – deterministic password generation. +- **KEY_TOTP_DET** – deterministic TOTP secrets. + +Each context string keeps derived keys domain separated. + +## KDF Parameters + +Passwords are protected with **PBKDF2-HMAC-SHA256**. The default work factor is +**50,000 iterations** but may be adjusted via the settings slider. The config +stores a `KdfConfig` structure with the chosen iteration count, algorithm name, +and the current spec version (`CURRENT_KDF_VERSION = 1`). Argon2 is available +with a default `time_cost` of 2 when selected. + +## Message Formats + +SeedPass synchronizes profiles over Nostr using three event kinds: + +- **Manifest (`30070`)** – high level snapshot description and current version. +- **Snapshot Chunk (`30071`)** – compressed, encrypted portions of the vault. +- **Delta (`30072`)** – incremental changes since the last snapshot. + +Events encode JSON and include tags for checksums, fingerprints, and timestamps. + +## Versioning + +Configuration and KDF schemas are versioned so clients can migrate older +profiles. Nostr events carry a version field in the manifest, and the software +follows semantic versioning for releases. + +## Memory Protection + +SeedPass encrypts sensitive values in memory and attempts to wipe them when no +longer needed. This zeroization is best-effort only; Python's memory management +may retain copies of decrypted data. Critical cryptographic operations may move +to a Rust/WASM module in the future to provide stronger guarantees. diff --git a/docs/agent_testing_roadmap.md b/docs/agent_testing_roadmap.md new file mode 100644 index 00000000..93bbbe1b --- /dev/null +++ b/docs/agent_testing_roadmap.md @@ -0,0 +1,73 @@ +# Agent Testing Roadmap + +This roadmap tracks how AI-agent driven testing should evolve for SeedPass. + +## Current Baseline (Implemented) + +The current baseline is available via: + +- `python scripts/ai_tui_agent_test.py` +- `docs/ai_agent_tui_testing.md` + +Current strengths: + +- deterministic end-to-end TUI flow in isolated `HOME` +- structured artifacts (`report.json`, clean/raw transcripts) +- coverage of onboarding, invalid inputs, add/retrieve/search/list/modify/archive, 2FA display, settings toggles, lock/unlock, stats, graceful exit + +Known limitations: + +- single large scenario can be harder to triage than smaller suites +- prompt matching is text-driven and sensitive to wording changes +- no dedicated β€œstress mode” for repeated random-but-seeded menu fuzzing yet + +## Near-Term Roadmap (Next 1-2 cycles) + +1. Split harness into scenario profiles: + - `core`: fast smoke path + - `extended`: all entry types + settings paths + - `stress`: repeated deterministic negative-input cycles +2. Add stricter artifact schema checks: + - fail when unknown coverage keys appear + - include app version, git SHA, and runtime metadata in `report.json` +3. Add targeted assertions for critical post-conditions: + - archive state consistency after restore + - lock/unlock recovers all managers and key hierarchy +4. Add a compact summary command for agents: + - parse latest report and print one-line status + failed checkpoints + +## Mid-Term Roadmap + +1. Differential transcript checks: + - compare current clean transcript against approved baselines + - allow configurable β€œsoft differences” (timestamps, progress bars) +2. Seeded input-fuzz campaigns: + - deterministic generation of invalid menu/index/text inputs + - reproducible runs via fixed RNG seed in report metadata +3. Failure clustering: + - classify failures into prompt drift, logic errors, state corruption, crash +4. CI lane for agent harness: + - run `core` on every PR + - run `extended` on merge queue/nightly + +## Long-Term Roadmap + +1. Coverage-driven TUI planning: + - map harness steps to code regions and prioritize unexercised paths +2. Stateful model checking for menu transitions: + - verify reachable/valid transitions and back-navigation invariants +3. Multi-profile and migration scenario pack: + - legacy index import/migration and cross-profile operations in one harness family +4. Security-oriented interactive tests: + - secret-mode leakage checks in output streams + - clipboard behavior assertions in controlled environments + +## Operating Rules for Agents + +1. Prefer deterministic inputs and stable prompt matching. +2. Keep each new checkpoint tied to a concrete user-visible behavior. +3. Add regression tests in `src/tests/` for every discovered logic bug. +4. Treat harness failures as either: + - product defect to fix, or + - harness synchronization defect to harden. +5. Record the final decision in PR notes with report paths. diff --git a/docs/ai_agent_tui_testing.md b/docs/ai_agent_tui_testing.md new file mode 100644 index 00000000..b23ff294 --- /dev/null +++ b/docs/ai_agent_tui_testing.md @@ -0,0 +1,149 @@ +# AI Agent TUI Testing + +This document defines a repeatable, methodical TUI test workflow for AI agents. + +## Goal + +Run SeedPass as a real interactive user and produce deterministic artifacts: + +1. Step-level pass/fail. +2. Coverage checkpoints for major TUI features. +3. Full transcript for debugging and regression comparison. + +## Runner + +Use: + +```bash +source .venv/bin/activate +python scripts/ai_tui_agent_test.py +``` + +The runner: + +- creates an isolated temporary `HOME` +- launches `src/main.py --no-clipboard` +- executes a scenario profile (`core`, `extended`, or `stress`) +- writes artifacts to `artifacts/agent_tui_test//` + +## Scenario Profiles + +- `core`: fast smoke path (onboarding, invalid input checks, add/retrieve/search/list, exit) +- `extended`: full end-to-end path including all entry kinds, archive/restore, and settings flows +- `stress`: deterministic repeated negative-input and back-navigation loops + +## Agent Commands Today + +Use these command tiers when agents are validating changes: + +1. Fast targeted checks (recommended during iteration): + +```bash +source .venv/bin/activate +pytest -q src/tests/test_manager_add_password.py src/tests/test_archive_restore.py src/tests/test_stats_screen.py src/tests/test_bip85_init.py +pytest -q src/tests/test_ai_tui_agent_harness.py +python scripts/ai_tui_agent_test.py --scenario core +``` + +2. Full regression check (before merge): + +```bash +source .venv/bin/activate +pytest -q +pytest -q --cov=src --cov-report=json:artifacts/coverage/coverage.json src/tests +python scripts/check_critical_coverage.py artifacts/coverage/coverage.json +python scripts/ai_tui_agent_test.py --scenario extended +``` + +3. Stability sweep for TUI prompt timing: + +```bash +source .venv/bin/activate +python scripts/ai_tui_agent_test.py --scenario stress --stress-cycles 6 --stress-seed 1337 +``` + +## Artifacts + +Each run writes: + +- `report.json`: status, step results, coverage points, failure info. +- `transcript.clean.txt`: ANSI-stripped terminal output. +- `transcript.raw.txt`: raw terminal output with ANSI. + +`report.json` also includes scenario-specific validation metadata: + +- `required_coverage_keys` +- `required_post_conditions` +- `post_conditions` + +## Current Coverage Points + +The harness marks these checkpoints as `true` only when observed: + +- `startup_onboarding` +- `main_menu` +- `invalid_input_resilience` +- `add_password_quick` +- `invalid_length_validation` +- `add_totp` +- `add_all_entry_types` +- `retrieve_entry` +- `search_entries` +- `list_entries` +- `modify_entry` +- `archive_restore` +- `totp_codes_view` +- `settings_toggles_lock_unlock` +- `settings_stats` +- `graceful_exit` + +`extended` scenario also enforces post-conditions: + +- `archive_restore_consistency`: restored entries are no longer listed in archived view +- `lock_unlock_recovers_retrieval`: retrieval still works after lock/unlock + +## CI/Agent Use Pattern + +Recommended agent sequence: + +1. `python scripts/ai_tui_agent_test.py` +2. Parse `report.json` +3. Fail task if `status != "passed"` or any checkpoint is `false` +4. If failed, inspect `transcript.clean.txt` for prompt-flow drift or regressions +5. Inspect `artifacts/coverage/coverage.json` and critical coverage gate output when module thresholds fail + +## Optional Flags + +```bash +python scripts/ai_tui_agent_test.py --help +``` + +Useful options: + +- `--scenario`: `core`, `extended`, or `stress` +- `--stress-cycles`: number of loops for `stress` profile +- `--stress-seed`: fixed RNG seed for deterministic invalid-input campaigns in `stress` +- `--timeout`: per-prompt timeout +- `--password`: fixed password used during test +- `--output-dir`: custom artifact root +- `--keep-home`: preserve generated profile state for local debugging +- `--verbose`: print step progress + +Coverage gate helper: + +- `python scripts/check_critical_coverage.py artifacts/coverage/coverage.json` +- Use `--threshold PATH=PERCENT` to override defaults. +- Use `--no-default-thresholds` for focused local smoke checks. + +## Extending Coverage + +When adding new TUI flows: + +1. Add deterministic steps to `scripts/ai_tui_agent_test.py`. +2. Add a new coverage checkpoint key. +3. Assert on concrete prompt/output text, not timing. +4. Keep inputs deterministic and avoid clipboard-dependent behavior. + +## Roadmap + +Future testing milestones are tracked in `docs/agent_testing_roadmap.md`. diff --git a/docs/assets/theme.js b/docs/assets/theme.js index 518779eb..88670fbe 100644 --- a/docs/assets/theme.js +++ b/docs/assets/theme.js @@ -46,9 +46,26 @@ document.addEventListener('DOMContentLoaded', () => { } } + function escapeHtml(text) { + if (!text) return text; + return text + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); + } + function highlight(text, q) { + if (!q) return escapeHtml(text); const re = new RegExp('(' + q.replace(/[.*+?^${}()|[\\]\\]/g, '\\$&') + ')', 'gi'); - return text.replace(re, '$1'); + return text.split(re).map((part, index) => { + if (index % 2 === 1) { + return '' + escapeHtml(part) + ''; + } else { + return escapeHtml(part); + } + }).join(''); } searchInput?.addEventListener('input', async e => { diff --git a/docs/ci-health-2026-02-19.md b/docs/ci-health-2026-02-19.md new file mode 100644 index 00000000..e7064778 --- /dev/null +++ b/docs/ci-health-2026-02-19.md @@ -0,0 +1,11 @@ +# CI Health Report - 2026-02-19 + +## Run Summary +- **Tests**: 653 passed, 8 skipped. +- **Flakes**: None detected in single run. +- **Environment**: Local sandbox, dependencies installed from `requirements.lock`. + +## Observations +- `pgpy` emits DeprecationWarning for `imghdr`. +- `toga` emits DeprecationWarning for `Pack.padding` and `Pack.padding_top`. +- `pytest-xdist` was required but not installed initially; installed from `requirements.lock`. diff --git a/docs/docs/content/01-getting-started/01-advanced_cli.md b/docs/docs/content/01-getting-started/01-advanced_cli.md index 13336a3f..dde456c9 100644 --- a/docs/docs/content/01-getting-started/01-advanced_cli.md +++ b/docs/docs/content/01-getting-started/01-advanced_cli.md @@ -78,7 +78,7 @@ Manage the entire vault for a profile. ### Nostr Commands -Interact with the Nostr network for backup and synchronization. +Interact with the Nostr network for backup and synchronization. Offline mode is enabled by default, so disable it with `seedpass config toggle-offline` before using these commands. | Action | Command | Examples | | :--- | :--- | :--- | @@ -127,7 +127,7 @@ Run or stop the local HTTP API. | Action | Command | Examples | | :--- | :--- | :--- | | Start the API | `api start` | `seedpass api start --host 0.0.0.0 --port 8000` | -| Stop the API | `api stop` | `seedpass api stop` | +| Stop the API | `api stop --token TOKEN` | `seedpass api stop --token ` | --- @@ -214,7 +214,7 @@ Set the `SEEDPASS_CORS_ORIGINS` environment variable to a comma‑separated list SEEDPASS_CORS_ORIGINS=http://localhost:3000 seedpass api start ``` -Shut down the server with `seedpass api stop`. +Shut down the server with `seedpass api stop --token `. --- diff --git a/docs/docs/content/01-getting-started/02-api_reference.md b/docs/docs/content/01-getting-started/02-api_reference.md index 38ac3b68..25d52da7 100644 --- a/docs/docs/content/01-getting-started/02-api_reference.md +++ b/docs/docs/content/01-getting-started/02-api_reference.md @@ -7,19 +7,19 @@ This guide covers how to start the SeedPass API, authenticate requests, and inte ## Starting the API -Run `seedpass api start` from your terminal. The command prints a one‑time token used for authentication: +Run `seedpass api start` from your terminal. The command prints a short‑lived JWT token used for authentication: ```bash $ seedpass api start -API token: abcdef1234567890 +API token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9... ``` -Keep this token secret. Every request must include it in the `Authorization` header using the `Bearer` scheme. +Keep this token secret and avoid logging it. Tokens expire after a few minutes and every request must include one in the `Authorization` header using the `Bearer` scheme. ## Endpoints - `GET /api/v1/entry?query=` – Search entries matching a query. -- `GET /api/v1/entry/{id}` – Retrieve a single entry by its index. +- `GET /api/v1/entry/{id}` – Retrieve a single entry by its index. Requires an `X-SeedPass-Password` header. - `POST /api/v1/entry` – Create a new entry of any supported type. - `PUT /api/v1/entry/{id}` – Modify an existing entry. - `PUT /api/v1/config/{key}` – Update a configuration value. @@ -31,18 +31,17 @@ Keep this token secret. Every request must include it in the `Authorization` hea - `POST /api/v1/fingerprint` – Add a new seed fingerprint. - `DELETE /api/v1/fingerprint/{fp}` – Remove a fingerprint. - `POST /api/v1/fingerprint/select` – Switch the active fingerprint. -- `GET /api/v1/totp/export` – Export all TOTP entries as JSON. -- `GET /api/v1/totp` – Return current TOTP codes and remaining time. +- `GET /api/v1/totp/export` – Export all TOTP entries as JSON. Requires an `X-SeedPass-Password` header. +- `GET /api/v1/totp` – Return current TOTP codes and remaining time. Requires an `X-SeedPass-Password` header. - `GET /api/v1/stats` – Return statistics about the active seed profile. - `GET /api/v1/notifications` – Retrieve and clear queued notifications. Messages appear in the persistent notification box but remain queued until fetched. -- `GET /api/v1/parent-seed` – Reveal the parent seed or save it with `?file=`. - `GET /api/v1/nostr/pubkey` – Fetch the Nostr public key for the active seed. - `POST /api/v1/checksum/verify` – Verify the checksum of the running script. - `POST /api/v1/checksum/update` – Update the stored script checksum. - `POST /api/v1/change-password` – Change the master password for the active profile. - `POST /api/v1/vault/import` – Import a vault backup from a file or path. -- `POST /api/v1/vault/export` – Export the vault and download the encrypted file. -- `POST /api/v1/vault/backup-parent-seed` – Save an encrypted backup of the parent seed. +- `POST /api/v1/vault/export` – Export the vault and download the encrypted file. Requires an additional `X-SeedPass-Password` header. +- `POST /api/v1/vault/backup-parent-seed` – Save an encrypted backup of the parent seed. Requires a `confirm` flag in the request body and an `X-SeedPass-Password` header. - `POST /api/v1/vault/lock` – Lock the vault and clear sensitive data from memory. - `GET /api/v1/relays` – List configured Nostr relays. - `POST /api/v1/relays` – Add a relay URL. @@ -50,7 +49,30 @@ Keep this token secret. Every request must include it in the `Authorization` hea - `POST /api/v1/relays/reset` – Reset the relay list to defaults. - `POST /api/v1/shutdown` – Stop the server gracefully. -**Security Warning:** Accessing `/api/v1/parent-seed` exposes your master seed in plain text. Use it only from a trusted environment. + +## Secure Deployment + +Always run the API behind HTTPS. Use a reverse proxy such as Nginx or Caddy to terminate TLS and forward requests to SeedPass. Example Nginx configuration: + +``` +server { + listen 443 ssl; + ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; + + location / { + proxy_pass http://127.0.0.1:8000; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} +``` + +For local testing, Uvicorn can serve TLS directly: + +``` +uvicorn seedpass.api:app --ssl-certfile=cert.pem --ssl-keyfile=key.pem +``` ## Example Requests @@ -58,7 +80,7 @@ Send requests with the token in the header: ```bash curl -H "Authorization: Bearer " \ - "http://127.0.0.1:8000/api/v1/entry?query=email" + "https://127.0.0.1:8000/api/v1/entry?query=email" ``` ### Creating an Entry @@ -149,8 +171,9 @@ curl -X POST http://127.0.0.1:8000/api/v1/fingerprint/select \ Download an encrypted vault backup via `POST /api/v1/vault/export`: ```bash -curl -X POST http://127.0.0.1:8000/api/v1/vault/export \ +curl -X POST https://127.0.0.1:8000/api/v1/vault/export \ -H "Authorization: Bearer " \ + -H "X-SeedPass-Password: " \ -o backup.json ``` @@ -180,8 +203,9 @@ Trigger an encrypted seed backup with `/api/v1/vault/backup-parent-seed`: ```bash curl -X POST http://127.0.0.1:8000/api/v1/vault/backup-parent-seed \ -H "Authorization: Bearer " \ + -H "X-SeedPass-Password: " \ -H "Content-Type: application/json" \ - -d '{"path": "seed_backup.enc"}' + -d '{"path": "seed_backup.enc", "confirm": true}' ``` ### Retrieving Vault Statistics diff --git a/docs/docs/content/01-getting-started/04-migrations.md b/docs/docs/content/01-getting-started/04-migrations.md index f6a1ce05..c3b20f84 100644 --- a/docs/docs/content/01-getting-started/04-migrations.md +++ b/docs/docs/content/01-getting-started/04-migrations.md @@ -3,6 +3,8 @@ SeedPass stores its password index in an encrypted JSON file. Each index contains a `schema_version` field so the application knows how to upgrade older files. +> **Note:** Recent releases derive passwords and other artifacts using a new deterministic algorithm that works consistently across Python versions. Artifacts produced with older versions will not match outputs from this release and must be regenerated. + ## How migrations work When the vault loads the index, `Vault.load_index()` checks the version and diff --git a/docs/docs/content/01-getting-started/06-gui_adapter.md b/docs/docs/content/01-getting-started/06-gui_adapter.md index dcb2dac0..89f015bb 100644 --- a/docs/docs/content/01-getting-started/06-gui_adapter.md +++ b/docs/docs/content/01-getting-started/06-gui_adapter.md @@ -14,10 +14,17 @@ python -m seedpass_gui seedpass-gui ``` -Only `toga-core` and the headless `toga-dummy` backend ship with the project. -The installation scripts automatically install the correct BeeWare backend so -the GUI works out of the box. If you set up SeedPass manually, install the -backend for your platform: +GUI dependencies are optional. Install them alongside SeedPass with: + +```bash +pip install "seedpass[gui]" + +# or when working from a local checkout +pip install -e .[gui] +``` + +After installing the optional GUI extras, add the BeeWare backend for your +platform: ```bash # Linux diff --git a/docs/docs/content/index.md b/docs/docs/content/index.md index 1015c891..cc733ecf 100644 --- a/docs/docs/content/index.md +++ b/docs/docs/content/index.md @@ -10,6 +10,10 @@ This software was not developed by an experienced security expert and should be used with caution. There may be bugs and missing features. Each vault chunk is limited to 50β€―KB and SeedPass periodically publishes a new snapshot to keep accumulated deltas small. The security of the program's memory management and logs has not been evaluated and may leak sensitive information. Loss or exposure of the parent seed places all derived passwords, accounts, and other artifacts at risk. +**🚨 Breaking Change** + +Recent releases derive passwords and other artifacts using a fully deterministic algorithm that behaves consistently across Python versions. This improvement means artifacts generated with earlier versions of SeedPass will not match those produced now. Regenerate any previously derived data or retain the old version if you need to reproduce older passwords or keys. + --- ### Supported OS @@ -46,6 +50,7 @@ maintainable while enabling a consistent experience on multiple platforms. - [Running the Application](#running-the-application) - [Managing Multiple Seeds](#managing-multiple-seeds) - [Additional Entry Types](#additional-entry-types) + - [Recovery](#recovery) - [Security Considerations](#security-considerations) - [Contributing](#contributing) - [License](#license) @@ -78,7 +83,7 @@ maintainable while enabling a consistent experience on multiple platforms. - **Change Master Password:** Rotate your encryption password at any time. - **Checksum Verification Utilities:** Verify or regenerate the script checksum. - **Relay Management:** List, add, remove or reset configured Nostr relays. -- **Offline Mode:** Disable network sync to work entirely locally. +- **Offline Mode (default):** SeedPass runs without network sync until you explicitly enable it. ## Prerequisites @@ -115,6 +120,11 @@ isn't on your PATH. If these tools are unavailable you'll see a link to download the installer now attempts to download Python 3.12 automatically so you don't have to compile packages from source. **Note:** If this fallback fails, install Python 3.12 manually or install the [Microsoft Visual C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) and rerun the installer. + +#### Installer Dependency Checks + +The installer verifies that core build toolingβ€”C/C++ build tools, Rust, CMake, and the imaging/GTK librariesβ€”are available before completing. Pass `--no-gui` to skip installing GUI packages. On Linux, ensure `xclip` or `wl-clipboard` is installed for clipboard support. + ### Uninstall Run the matching uninstaller if you need to remove a previous installation or clean up an old `seedpass` command: @@ -185,20 +195,22 @@ When upgrading pip, use `python -m pip` inside the virtual environment so that p ```bash python -m pip install --upgrade pip -python -m pip install -r src/requirements.txt +python -m pip install --require-hashes -r requirements.lock python -m pip install -e . ``` #### Linux Clipboard Support On Linux, `pyperclip` relies on external utilities like `xclip` or `xsel`. -SeedPass will attempt to install **xclip** automatically if neither tool is -available. If the automatic installation fails, you can install it manually: +SeedPass does not install these tools automatically. To use clipboard features +such as secret mode, install **xclip** manually: ```bash -sudo apt-get install xclip +sudo apt install xclip ``` +After installing `xclip`, restart SeedPass to enable clipboard support. + ## Quick Start After installing dependencies, activate your virtual environment and install @@ -233,8 +245,8 @@ seedpass list --filter totp # on an external drive. ``` -For additional command examples, see [docs/advanced_cli.md](docs/advanced_cli.md). -Details on the REST API can be found in [docs/api_reference.md](docs/api_reference.md). +For additional command examples, see [01-getting-started/01-advanced_cli.md](01-getting-started/01-advanced_cli.md). +Details on the REST API can be found in [01-getting-started/02-api_reference.md](01-getting-started/02-api_reference.md). ### Vault JSON Layout @@ -273,7 +285,7 @@ You can explore other CLI commands using: ```bash seedpass --help ``` -For a full list of commands see [docs/advanced_cli.md](docs/advanced_cli.md). The REST API is described in [docs/api_reference.md](docs/api_reference.md). +For a full list of commands see [01-getting-started/01-advanced_cli.md](01-getting-started/01-advanced_cli.md). The REST API is described in [01-getting-started/02-api_reference.md](01-getting-started/02-api_reference.md). ### Running the Application @@ -403,6 +415,22 @@ SeedPass allows you to manage multiple seed profiles (previously referred to as **Note:** The term "seed profile" is used to represent different sets of seeds you can manage within SeedPass. This provides an intuitive way to handle multiple identities or sets of passwords. + +### Recovery + +If you previously backed up your vault to Nostr you can restore it during the +initial setup. You must provide both your 12β€Š-word master seed and the master +password that encrypted the vault; without the correct password the retrieved +data cannot be decrypted. + +1. Start SeedPass and choose option **4** when prompted to set up a seed. +2. Paste your BIP‑85 seed phrase when asked. +3. Enter the master password associated with that seed. +4. SeedPass initializes the profile and attempts to download the encrypted + vault from the configured relays. +5. A success message confirms the vault was restored. If no data is found a + failure message is shown and a new empty vault is created. + ### Configuration File and Settings SeedPass keeps per-profile settings in an encrypted file named `seedpass_config.json.enc` inside each profile directory under `~/.seedpass/`. This file stores your chosen Nostr relays and the optional settings PIN. New profiles start with the following default relays: @@ -444,17 +472,17 @@ Back in the Settings menu you can: whether both the encrypted database and the script itself pass checksum validation. * Choose `14` to toggle Secret Mode and set the clipboard clear delay. -* Select `15` to toggle Offline Mode and work locally without contacting Nostr. +* Select `15` to toggle Offline Mode. SeedPass starts offline; disable it here to enable Nostr syncing. * Choose `16` to toggle Quick Unlock so subsequent actions skip the password prompt. Startup delay is unchanged. * Select `17` to return to the main menu. ## Running Tests -SeedPass includes a small suite of unit tests located under `src/tests`. **Before running `pytest`, be sure to install the test requirements.** Activate your virtual environment and run `pip install -r src/requirements.txt` to ensure all testing dependencies are available. Then run the tests with **pytest**. Use `-vv` to see INFO-level log messages from each passing test: +SeedPass includes a small suite of unit tests located under `src/tests`. **Before running `pytest`, be sure to install the test requirements.** Activate your virtual environment and run `pip install --require-hashes -r requirements.lock` to ensure all testing dependencies are available. Then run the tests with **pytest**. Use `-vv` to see INFO-level log messages from each passing test: ```bash -pip install -r src/requirements.txt +pip install --require-hashes -r requirements.lock pytest -vv ``` @@ -531,14 +559,14 @@ Mutation testing is disabled in the GitHub workflow due to reliability issues an - **Backup Your Data:** Regularly back up your encrypted data and checksum files to prevent data loss. - **Backup the Settings PIN:** Your settings PIN is stored in the encrypted configuration file. Keep a copy of this file or remember the PIN, as losing it will require deleting the file and reconfiguring your relays. - **Protect Your Passwords:** Do not share your master password or seed phrases with anyone and ensure they are strong and unique. -- **Revealing the Parent Seed:** The `vault reveal-parent-seed` command and `/api/v1/parent-seed` endpoint print your seed in plain text. Run them only in a secure environment. +- **Backing Up the Parent Seed:** Use the CLI `vault reveal-parent-seed` command or the `/api/v1/vault/backup-parent-seed` endpoint with explicit confirmation to create an encrypted backup. The API does not return the seed directly. - **No PBKDF2 Salt Needed:** SeedPass deliberately omits an explicit PBKDF2 salt. Every password is derived from a unique 512-bit BIP-85 child seed, which already provides stronger per-password uniqueness than a conventional 128-bit salt. - **Checksum Verification:** Always verify the script's checksum to ensure its integrity and protect against unauthorized modifications. - **Potential Bugs and Limitations:** Be aware that the software may contain bugs and lacks certain features. Snapshot chunks are capped at 50β€―KB and the client rotates snapshots after enough delta events accumulate. The security of memory management and logs has not been thoroughly evaluated and may pose risks of leaking sensitive information. - **Multiple Seeds Management:** While managing multiple seeds adds flexibility, it also increases the responsibility to secure each seed and its associated password. - **No PBKDF2 Salt Required:** SeedPass deliberately omits an explicit PBKDF2 salt. Every password is derived from a unique 512-bit BIP-85 child seed, which already provides stronger per-password uniqueness than a conventional 128-bit salt. - **Default KDF Iterations:** New profiles start with 50,000 PBKDF2 iterations. Use `seedpass config set kdf_iterations` to change this. -- **Offline Mode:** Disable Nostr sync to keep all operations local until you re-enable networking. +- **Offline Mode (default):** Nostr sync is disabled until you explicitly enable it via the Settings menu or `seedpass config toggle-offline`. - **Quick Unlock:** Store a hashed copy of your password so future actions skip the prompt. Startup delay no longer changes. Use with caution on shared systems. ## Contributing diff --git a/docs/installer_testing.md b/docs/installer_testing.md new file mode 100644 index 00000000..b48e89cf --- /dev/null +++ b/docs/installer_testing.md @@ -0,0 +1,44 @@ +# Installer Testing + +This document describes how SeedPass installer smoke tests are validated across +operating systems and branches (`main`, `beta`). + +## CI Workflow + +GitHub Actions workflow: `.github/workflows/installer-smoke.yml` + +- `pull_request` (reduced matrix): + - Ubuntu + Windows + - `beta` branch + - `tui` mode +- `schedule` + `workflow_dispatch` (full matrix): + - Ubuntu / macOS / Windows + - `main` + `beta` + - `tui` and GUI-capable modes (`both` where supported) + +Each job verifies: + +1. installer exits successfully +2. launcher is created +3. installed git branch matches requested branch +4. `seedpass --help` runs through launcher +5. installer can be re-run (idempotence smoke check) + +## Local Smoke Tests + +### Linux / macOS + +```bash +bash scripts/installer_smoke_unix.sh beta tui +bash scripts/installer_smoke_unix.sh beta both +``` + +### Windows (PowerShell) + +```powershell +./scripts/installer_smoke_windows.ps1 -Branch beta -Mode tui +./scripts/installer_smoke_windows.ps1 -Branch beta -Mode both +``` + +The smoke scripts use an isolated temporary home/profile directory so local +user data is not modified. diff --git a/docs/nostr_setup.md b/docs/nostr_setup.md new file mode 100644 index 00000000..0c738e22 --- /dev/null +++ b/docs/nostr_setup.md @@ -0,0 +1,33 @@ +# Nostr Setup + +This guide explains how SeedPass uses the Nostr protocol for encrypted vault backups and how to configure relays. SeedPass starts in offline mode, so you must explicitly disable it before any network synchronization. Run `seedpass config toggle-offline` or use the Settings menu to enable online syncing. + +## Relay Configuration + +SeedPass communicates with the Nostr network through a list of relays. You can manage these relays from the CLI: + +```bash +seedpass nostr list-relays # show configured relays +seedpass nostr add-relay # add a relay URL +seedpass nostr remove-relay # remove relay by index +``` + +At least one relay is required for publishing and retrieving backups. Choose relays you trust to remain online and avoid those that charge high fees or aggressively rate‑limit connections. + +## Manifest and Delta Events + +Backups are published as parameterised replaceable events: + +- **Kind 30070 – Manifest:** describes the snapshot and lists chunk IDs. The optional `delta_since` field stores the UNIX timestamp of the latest delta event. +- **Kind 30071 – Snapshot Chunk:** each 50 KB fragment of the compressed, encrypted vault. +- **Kind 30072 – Delta:** captures changes since the last snapshot. + +When restoring, SeedPass downloads the most recent manifest and applies any newer delta events. + +## Troubleshooting + +- **No events found:** ensure the relays are reachable and that the correct fingerprint is selected. +- **Connection failures:** some relays only support WebSocket over TLS; verify you are using `wss://` URLs where required. +- **Stale data:** if deltas accumulate without a fresh snapshot, run `seedpass nostr sync` to publish an updated snapshot. + +Increasing log verbosity with `--verbose` can also help diagnose relay or network issues. diff --git a/docs/packaging.md b/docs/packaging.md new file mode 100644 index 00000000..03a095cd --- /dev/null +++ b/docs/packaging.md @@ -0,0 +1,38 @@ +# Packaging SeedPass + +This guide describes how to build platform-native packages for SeedPass using [BeeWare Briefcase](https://briefcase.readthedocs.io/). + +## Prerequisites + +* Python 3.12 with development headers (`python3-dev` on Debian/Ubuntu). +* Briefcase installed in your virtual environment: + +```bash +pip install briefcase +``` + +## Linux + +The helper script in `packaging/build-linux.sh` performs `briefcase create`, `build`, and `package` for the current project. + +```bash +./packaging/build-linux.sh +``` + +Briefcase outputs its build artifacts in `build/seedpass-gui/ubuntu/noble/`. These files can be bundled in container formats such as Flatpak or Snap. Example manifests are included: + +* `packaging/flatpak/seedpass.yml` targets the `org.gnome.Platform` runtime and copies the Briefcase build into the Flatpak bundle. +* `packaging/snapcraft.yaml` stages the Briefcase build and lists GTK libraries in `stage-packages` so the Snap includes its GUI dependencies. + +## macOS and Windows + +Scripts are provided to document the commands expected on each platform. They must be run on their respective operating systems: + +* `packaging/build-macos.sh` +* `packaging/build-windows.ps1` + +Each script runs Briefcase's `create`, `build`, and `package` steps with `--no-input`. + +## Reproducible Releases + +The `packaging/` directory contains the scripts and manifests needed to regenerate desktop packages. Invoke the appropriate script on the target OS, then use the supplied Flatpak or Snap manifest to bundle additional dependencies for Linux. diff --git a/docs/secret-scanning.md b/docs/secret-scanning.md new file mode 100644 index 00000000..767af921 --- /dev/null +++ b/docs/secret-scanning.md @@ -0,0 +1,17 @@ +# Secret Scanning + +SeedPass uses [Gitleaks](https://github.com/gitleaks/gitleaks) to scan the repository for accidentally committed secrets. The scan runs automatically for pull requests and on a nightly schedule. Any findings will cause the build to fail. + +## Suppressing False Positives + +If a file or string triggers the scanner but does not contain a real secret, add it to the allowlist in `.gitleaks.toml`. + +```toml +[allowlist] +# Ignore specific files +paths = ["path/to/file.txt"] +# Ignore strings that match a regular expression +regexes = ["""dummy_api_key"""] +``` + +Commit the updated `.gitleaks.toml` to stop future alerts for the allowed items. diff --git a/docs/security.md b/docs/security.md new file mode 100644 index 00000000..e79b536d --- /dev/null +++ b/docs/security.md @@ -0,0 +1,30 @@ +# Security Testing and Calibration + +This project includes fuzz tests and a calibration routine to tune Argon2 parameters for your hardware. + +## Running Fuzz Tests + +The fuzz tests exercise encryption and decryption with random data using [Hypothesis](https://hypothesis.readthedocs.io/). +Activate the project's virtual environment and run: + +```bash +pytest src/tests/test_encryption_fuzz.py +``` + +Running the entire test suite will also execute these fuzz tests. + +## Calibrating Argon2 Time Cost + +Argon2 performance varies by device. To calibrate the `time_cost` parameter, run the helper function: + +```bash +python - <<'PY' +from seedpass.core.config_manager import ConfigManager +from utils.key_derivation import calibrate_argon2_time_cost + +# assuming ``cfg`` is a ConfigManager for your profile +calibrate_argon2_time_cost(cfg) +PY +``` + +The selected `time_cost` is stored in the profile's configuration and used for subsequent key derivations. diff --git a/landing/index.html b/landing/index.html index 678c5b93..d558c130 100644 --- a/landing/index.html +++ b/landing/index.html @@ -76,6 +76,16 @@ flowchart TB classDef default fill:#ffffff,stroke:#e94a39,stroke-width:2px,color:#283c4f; Get Started +
+

Install SeedPass (stable)

+
+
bash -c "$(curl -sSL https://raw.githubusercontent.com/PR0M3TH3AN/SeedPass/main/scripts/install.sh)"
+ +
+
@@ -202,6 +212,8 @@ flowchart TD

SeedPass allows you to manage multiple seed profiles (fingerprints). You can switch between different seeds to compartmentalize your passwords.

Nostr Relay Integration

SeedPass publishes your encrypted vault to Nostr in 50 KB chunks using parameterised replaceable events. A manifest describes each snapshot while deltas record updates. When too many deltas accumulate, a new snapshot is rotated in automatically.

+

Recovery from Nostr

+

Restoring a vault on a new device requires both your 12 word master seed and the master password that encrypted the vault. Without the correct password the downloaded archive cannot be decrypted.

Checksum Verification

Built-in checksum verification ensures your SeedPass installation hasn't been tampered with.

Interactive TUI

@@ -255,4 +267,4 @@ Enter your choice (1-7) or press Enter to exit: - \ No newline at end of file + diff --git a/landing/script.js b/landing/script.js index c8202fe7..5d714604 100644 --- a/landing/script.js +++ b/landing/script.js @@ -65,5 +65,34 @@ document.querySelectorAll('a[href^="#"]').forEach(anchor => { // Log when the page is loaded document.addEventListener('DOMContentLoaded', function() { + document.querySelectorAll('[data-copy-target]').forEach((button) => { + button.addEventListener('click', async () => { + const targetId = button.getAttribute('data-copy-target'); + const target = document.getElementById(targetId); + if (!target) return; + + const text = target.textContent.trim(); + + try { + await navigator.clipboard.writeText(text); + } catch (_err) { + const temp = document.createElement('textarea'); + temp.value = text; + document.body.appendChild(temp); + temp.select(); + document.execCommand('copy'); + document.body.removeChild(temp); + } + + const original = button.innerHTML; + button.classList.add('copied'); + button.innerHTML = ' Copied'; + setTimeout(() => { + button.classList.remove('copied'); + button.innerHTML = original; + }, 1800); + }); + }); + console.log('SeedPass landing page loaded'); }); diff --git a/landing/style.css b/landing/style.css index 7061f5b0..e6606a7c 100644 --- a/landing/style.css +++ b/landing/style.css @@ -231,6 +231,14 @@ footer .social-media a:focus { .nav-links.active { display: flex; } + + .install-command-shell { + flex-direction: column; + } + + .install-copy-button { + min-height: 40px; + } } /* Section Titles */ @@ -337,6 +345,53 @@ footer .social-media a:focus { transform: translateY(-3px); } +.install-quickstart { + margin: 28px auto 0; + max-width: 900px; + text-align: left; +} + +.install-label { + margin: 0 0 8px; + font-size: 0.95rem; + color: rgba(255, 255, 255, 0.9); +} + +.install-command-shell { + display: flex; + align-items: stretch; + gap: 10px; +} + +.install-code { + flex: 1; + margin: 0; +} + +.install-copy-button { + border: 1px solid rgba(255, 255, 255, 0.25); + background: rgba(255, 255, 255, 0.08); + color: #ffffff; + border-radius: 8px; + padding: 0 14px; + font-weight: 600; + cursor: pointer; + white-space: nowrap; + transition: background-color 0.2s ease, border-color 0.2s ease; +} + +.install-copy-button:hover, +.install-copy-button:focus { + background: rgba(255, 255, 255, 0.18); + border-color: rgba(255, 255, 255, 0.45); + outline: none; +} + +.install-copy-button.copied { + background: #2ea043; + border-color: #2ea043; +} + /* Mini flow chart in hero */ .mini-chart { max-width: 600px; @@ -985,6 +1040,20 @@ body.dark-mode .code-block { box-shadow: 0 2px 8px var(--shadow-dark); } +body.dark-mode .install-label { + color: #c9d1d9; +} + +body.dark-mode .install-copy-button { + border-color: rgba(255, 255, 255, 0.3); + background: rgba(255, 255, 255, 0.08); +} + +body.dark-mode .install-copy-button:hover, +body.dark-mode .install-copy-button:focus { + background: rgba(255, 255, 255, 0.18); +} + body.dark-mode .disclaimer .container { background-color: #2c2f33; color: var(--footer-text); @@ -1002,4 +1071,4 @@ body.dark-mode .disclaimer ul li:focus-within { body.dark-mode footer { background-color: var(--background-dark); -} \ No newline at end of file +} diff --git a/packaging/build-linux.sh b/packaging/build-linux.sh new file mode 100755 index 00000000..e496261c --- /dev/null +++ b/packaging/build-linux.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -e +briefcase create linux --no-input +briefcase build linux --no-input +briefcase package linux --no-input diff --git a/packaging/build-macos.sh b/packaging/build-macos.sh new file mode 100755 index 00000000..df2bbc02 --- /dev/null +++ b/packaging/build-macos.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -e +briefcase create macos --no-input +briefcase build macos --no-input +briefcase package macos --no-input diff --git a/packaging/build-windows.ps1 b/packaging/build-windows.ps1 new file mode 100644 index 00000000..3defff0c --- /dev/null +++ b/packaging/build-windows.ps1 @@ -0,0 +1,3 @@ +briefcase create windows --no-input +briefcase build windows --no-input +briefcase package windows --no-input diff --git a/packaging/flatpak/seedpass.yml b/packaging/flatpak/seedpass.yml new file mode 100644 index 00000000..b49d3eca --- /dev/null +++ b/packaging/flatpak/seedpass.yml @@ -0,0 +1,18 @@ +app-id: io.seedpass.SeedPass +runtime: org.gnome.Platform +runtime-version: '46' +sdk: org.gnome.Sdk +command: seedpass-gui +modules: + - name: seedpass + buildsystem: simple + build-commands: + - mkdir -p /app/bin + - cp -r ../../build/seedpass-gui/ubuntu/noble/* /app/bin/ + sources: + - type: dir + path: ../../ +finish-args: + - --share=network + - --socket=fallback-x11 + - --socket=wayland diff --git a/packaging/snapcraft.yaml b/packaging/snapcraft.yaml new file mode 100644 index 00000000..a965aaed --- /dev/null +++ b/packaging/snapcraft.yaml @@ -0,0 +1,22 @@ +name: seedpass +base: core22 +version: '0.1.0' +summary: Deterministic password manager +description: | + SeedPass deterministically generates passwords using BIP-39 seeds. +grade: devel +confinement: strict +apps: + seedpass-gui: + command: bin/seedpass-gui + plugs: + - network + - x11 +parts: + seedpass: + plugin: dump + source: build/seedpass-gui/ubuntu/noble/app + stage-packages: + - libgtk-3-0 + - libglib2.0-0 + - libgdk-pixbuf2.0-0 diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..d80a79bd --- /dev/null +++ b/poetry.lock @@ -0,0 +1,3629 @@ +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +description = "Happy Eyeballs for asyncio" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"}, + {file = "aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558"}, +] + +[[package]] +name = "aiohttp" +version = "3.12.15" +description = "Async http client/server framework (asyncio)" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "aiohttp-3.12.15-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b6fc902bff74d9b1879ad55f5404153e2b33a82e72a95c89cec5eb6cc9e92fbc"}, + {file = "aiohttp-3.12.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:098e92835b8119b54c693f2f88a1dec690e20798ca5f5fe5f0520245253ee0af"}, + {file = "aiohttp-3.12.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:40b3fee496a47c3b4a39a731954c06f0bd9bd3e8258c059a4beb76ac23f8e421"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ce13fcfb0bb2f259fb42106cdc63fa5515fb85b7e87177267d89a771a660b79"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3beb14f053222b391bf9cf92ae82e0171067cc9c8f52453a0f1ec7c37df12a77"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c39e87afe48aa3e814cac5f535bc6199180a53e38d3f51c5e2530f5aa4ec58c"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5f1b4ce5bc528a6ee38dbf5f39bbf11dd127048726323b72b8e85769319ffc4"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1004e67962efabbaf3f03b11b4c43b834081c9e3f9b32b16a7d97d4708a9abe6"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8faa08fcc2e411f7ab91d1541d9d597d3a90e9004180edb2072238c085eac8c2"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fe086edf38b2222328cdf89af0dde2439ee173b8ad7cb659b4e4c6f385b2be3d"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:79b26fe467219add81d5e47b4a4ba0f2394e8b7c7c3198ed36609f9ba161aecb"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b761bac1192ef24e16706d761aefcb581438b34b13a2f069a6d343ec8fb693a5"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e153e8adacfe2af562861b72f8bc47f8a5c08e010ac94eebbe33dc21d677cd5b"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:fc49c4de44977aa8601a00edbf157e9a421f227aa7eb477d9e3df48343311065"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2776c7ec89c54a47029940177e75c8c07c29c66f73464784971d6a81904ce9d1"}, + {file = "aiohttp-3.12.15-cp310-cp310-win32.whl", hash = "sha256:2c7d81a277fa78b2203ab626ced1487420e8c11a8e373707ab72d189fcdad20a"}, + {file = "aiohttp-3.12.15-cp310-cp310-win_amd64.whl", hash = "sha256:83603f881e11f0f710f8e2327817c82e79431ec976448839f3cd05d7afe8f830"}, + {file = "aiohttp-3.12.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d3ce17ce0220383a0f9ea07175eeaa6aa13ae5a41f30bc61d84df17f0e9b1117"}, + {file = "aiohttp-3.12.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:010cc9bbd06db80fe234d9003f67e97a10fe003bfbedb40da7d71c1008eda0fe"}, + {file = "aiohttp-3.12.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f9d7c55b41ed687b9d7165b17672340187f87a773c98236c987f08c858145a9"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc4fbc61bb3548d3b482f9ac7ddd0f18c67e4225aaa4e8552b9f1ac7e6bda9e5"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7fbc8a7c410bb3ad5d595bb7118147dfbb6449d862cc1125cf8867cb337e8728"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74dad41b3458dbb0511e760fb355bb0b6689e0630de8a22b1b62a98777136e16"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b6f0af863cf17e6222b1735a756d664159e58855da99cfe965134a3ff63b0b0"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5b7fe4972d48a4da367043b8e023fb70a04d1490aa7d68800e465d1b97e493b"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6443cca89553b7a5485331bc9bedb2342b08d073fa10b8c7d1c60579c4a7b9bd"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c5f40ec615e5264f44b4282ee27628cea221fcad52f27405b80abb346d9f3f8"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2abbb216a1d3a2fe86dbd2edce20cdc5e9ad0be6378455b05ec7f77361b3ab50"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:db71ce547012a5420a39c1b744d485cfb823564d01d5d20805977f5ea1345676"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ced339d7c9b5030abad5854aa5413a77565e5b6e6248ff927d3e174baf3badf7"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7c7dd29c7b5bda137464dc9bfc738d7ceea46ff70309859ffde8c022e9b08ba7"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:421da6fd326460517873274875c6c5a18ff225b40da2616083c5a34a7570b685"}, + {file = "aiohttp-3.12.15-cp311-cp311-win32.whl", hash = "sha256:4420cf9d179ec8dfe4be10e7d0fe47d6d606485512ea2265b0d8c5113372771b"}, + {file = "aiohttp-3.12.15-cp311-cp311-win_amd64.whl", hash = "sha256:edd533a07da85baa4b423ee8839e3e91681c7bfa19b04260a469ee94b778bf6d"}, + {file = "aiohttp-3.12.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:802d3868f5776e28f7bf69d349c26fc0efadb81676d0afa88ed00d98a26340b7"}, + {file = "aiohttp-3.12.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2800614cd560287be05e33a679638e586a2d7401f4ddf99e304d98878c29444"}, + {file = "aiohttp-3.12.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8466151554b593909d30a0a125d638b4e5f3836e5aecde85b66b80ded1cb5b0d"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e5a495cb1be69dae4b08f35a6c4579c539e9b5706f606632102c0f855bcba7c"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6404dfc8cdde35c69aaa489bb3542fb86ef215fc70277c892be8af540e5e21c0"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ead1c00f8521a5c9070fcb88f02967b1d8a0544e6d85c253f6968b785e1a2ab"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6990ef617f14450bc6b34941dba4f12d5613cbf4e33805932f853fbd1cf18bfb"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd736ed420f4db2b8148b52b46b88ed038d0354255f9a73196b7bbce3ea97545"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c5092ce14361a73086b90c6efb3948ffa5be2f5b6fbcf52e8d8c8b8848bb97c"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aaa2234bb60c4dbf82893e934d8ee8dea30446f0647e024074237a56a08c01bd"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6d86a2fbdd14192e2f234a92d3b494dd4457e683ba07e5905a0b3ee25389ac9f"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a041e7e2612041a6ddf1c6a33b883be6a421247c7afd47e885969ee4cc58bd8d"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5015082477abeafad7203757ae44299a610e89ee82a1503e3d4184e6bafdd519"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56822ff5ddfd1b745534e658faba944012346184fbfe732e0d6134b744516eea"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b2acbbfff69019d9014508c4ba0401822e8bae5a5fdc3b6814285b71231b60f3"}, + {file = "aiohttp-3.12.15-cp312-cp312-win32.whl", hash = "sha256:d849b0901b50f2185874b9a232f38e26b9b3d4810095a7572eacea939132d4e1"}, + {file = "aiohttp-3.12.15-cp312-cp312-win_amd64.whl", hash = "sha256:b390ef5f62bb508a9d67cb3bba9b8356e23b3996da7062f1a57ce1a79d2b3d34"}, + {file = "aiohttp-3.12.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9f922ffd05034d439dde1c77a20461cf4a1b0831e6caa26151fe7aa8aaebc315"}, + {file = "aiohttp-3.12.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2ee8a8ac39ce45f3e55663891d4b1d15598c157b4d494a4613e704c8b43112cd"}, + {file = "aiohttp-3.12.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3eae49032c29d356b94eee45a3f39fdf4b0814b397638c2f718e96cfadf4c4e4"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97752ff12cc12f46a9b20327104448042fce5c33a624f88c18f66f9368091c7"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:894261472691d6fe76ebb7fcf2e5870a2ac284c7406ddc95823c8598a1390f0d"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fa5d9eb82ce98959fc1031c28198b431b4d9396894f385cb63f1e2f3f20ca6b"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0fa751efb11a541f57db59c1dd821bec09031e01452b2b6217319b3a1f34f3d"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5346b93e62ab51ee2a9d68e8f73c7cf96ffb73568a23e683f931e52450e4148d"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:049ec0360f939cd164ecbfd2873eaa432613d5e77d6b04535e3d1fbae5a9e645"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b52dcf013b57464b6d1e51b627adfd69a8053e84b7103a7cd49c030f9ca44461"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b2af240143dd2765e0fb661fd0361a1b469cab235039ea57663cda087250ea9"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac77f709a2cde2cc71257ab2d8c74dd157c67a0558a0d2799d5d571b4c63d44d"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:47f6b962246f0a774fbd3b6b7be25d59b06fdb2f164cf2513097998fc6a29693"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:760fb7db442f284996e39cf9915a94492e1896baac44f06ae551974907922b64"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad702e57dc385cae679c39d318def49aef754455f237499d5b99bea4ef582e51"}, + {file = "aiohttp-3.12.15-cp313-cp313-win32.whl", hash = "sha256:f813c3e9032331024de2eb2e32a88d86afb69291fbc37a3a3ae81cc9917fb3d0"}, + {file = "aiohttp-3.12.15-cp313-cp313-win_amd64.whl", hash = "sha256:1a649001580bdb37c6fdb1bebbd7e3bc688e8ec2b5c6f52edbb664662b17dc84"}, + {file = "aiohttp-3.12.15-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:691d203c2bdf4f4637792efbbcdcd157ae11e55eaeb5e9c360c1206fb03d4d98"}, + {file = "aiohttp-3.12.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8e995e1abc4ed2a454c731385bf4082be06f875822adc4c6d9eaadf96e20d406"}, + {file = "aiohttp-3.12.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bd44d5936ab3193c617bfd6c9a7d8d1085a8dc8c3f44d5f1dcf554d17d04cf7d"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46749be6e89cd78d6068cdf7da51dbcfa4321147ab8e4116ee6678d9a056a0cf"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0c643f4d75adea39e92c0f01b3fb83d57abdec8c9279b3078b68a3a52b3933b6"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a23918fedc05806966a2438489dcffccbdf83e921a1170773b6178d04ade142"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74bdd8c864b36c3673741023343565d95bfbd778ffe1eb4d412c135a28a8dc89"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a146708808c9b7a988a4af3821379e379e0f0e5e466ca31a73dbdd0325b0263"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7011a70b56facde58d6d26da4fec3280cc8e2a78c714c96b7a01a87930a9530"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3bdd6e17e16e1dbd3db74d7f989e8af29c4d2e025f9828e6ef45fbdee158ec75"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:57d16590a351dfc914670bd72530fd78344b885a00b250e992faea565b7fdc05"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:bc9a0f6569ff990e0bbd75506c8d8fe7214c8f6579cca32f0546e54372a3bb54"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:536ad7234747a37e50e7b6794ea868833d5220b49c92806ae2d7e8a9d6b5de02"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f0adb4177fa748072546fb650d9bd7398caaf0e15b370ed3317280b13f4083b0"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:14954a2988feae3987f1eb49c706bff39947605f4b6fa4027c1d75743723eb09"}, + {file = "aiohttp-3.12.15-cp39-cp39-win32.whl", hash = "sha256:b784d6ed757f27574dca1c336f968f4e81130b27595e458e69457e6878251f5d"}, + {file = "aiohttp-3.12.15-cp39-cp39-win_amd64.whl", hash = "sha256:86ceded4e78a992f835209e236617bffae649371c4a50d5e5a3987f237db84b8"}, + {file = "aiohttp-3.12.15.tar.gz", hash = "sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2"}, +] + +[package.dependencies] +aiohappyeyeballs = ">=2.5.0" +aiosignal = ">=1.4.0" +async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} +attrs = ">=17.3.0" +frozenlist = ">=1.1.1" +multidict = ">=4.5,<7.0" +propcache = ">=0.2.0" +yarl = ">=1.17.0,<2.0" + +[package.extras] +speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.3.0)", "brotlicffi ; platform_python_implementation != \"CPython\""] + +[[package]] +name = "aiosignal" +version = "1.4.0" +description = "aiosignal: a list of registered asynchronous callbacks" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e"}, + {file = "aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7"}, +] + +[package.dependencies] +frozenlist = ">=1.1.0" +typing-extensions = {version = ">=4.2", markers = "python_version < \"3.13\""} + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "anyio" +version = "4.10.0" +description = "High-level concurrency and networking framework on top of asyncio or Trio" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "anyio-4.10.0-py3-none-any.whl", hash = "sha256:60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1"}, + {file = "anyio-4.10.0.tar.gz", hash = "sha256:3f3fae35c96039744587aa5b8371e7e8e603c0702999535961dd336026973ba6"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} + +[package.extras] +trio = ["trio (>=0.26.1)"] + +[[package]] +name = "argon2-cffi" +version = "25.1.0" +description = "Argon2 for Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741"}, + {file = "argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1"}, +] + +[package.dependencies] +argon2-cffi-bindings = "*" + +[[package]] +name = "argon2-cffi-bindings" +version = "25.1.0" +description = "Low-level CFFI bindings for Argon2" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:3d3f05610594151994ca9ccb3c771115bdb4daef161976a266f0dd8aa9996b8f"}, + {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8b8efee945193e667a396cbc7b4fb7d357297d6234d30a489905d96caabde56b"}, + {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3c6702abc36bf3ccba3f802b799505def420a1b7039862014a65db3205967f5a"}, + {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1c70058c6ab1e352304ac7e3b52554daadacd8d453c1752e547c76e9c99ac44"}, + {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2fd3bfbff3c5d74fef31a722f729bf93500910db650c925c2d6ef879a7e51cb"}, + {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4f9665de60b1b0e99bcd6be4f17d90339698ce954cfd8d9cf4f91c995165a92"}, + {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ba92837e4a9aa6a508c8d2d7883ed5a8f6c308c89a4790e1e447a220deb79a85"}, + {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-win32.whl", hash = "sha256:84a461d4d84ae1295871329b346a97f68eade8c53b6ed9a7ca2d7467f3c8ff6f"}, + {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b55aec3565b65f56455eebc9b9f34130440404f27fe21c3b375bf1ea4d8fbae6"}, + {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:87c33a52407e4c41f3b70a9c2d3f6056d88b10dad7695be708c5021673f55623"}, + {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500"}, + {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44"}, + {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0"}, + {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6"}, + {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a"}, + {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d"}, + {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99"}, + {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2"}, + {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98"}, + {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94"}, + {file = "argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e"}, + {file = "argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d"}, + {file = "argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584"}, + {file = "argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690"}, + {file = "argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520"}, + {file = "argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d"}, +] + +[package.dependencies] +cffi = {version = ">=1.0.1", markers = "python_version < \"3.14\""} + +[[package]] +name = "async-timeout" +version = "5.0.1" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version == \"3.10\"" +files = [ + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, +] + +[[package]] +name = "attrs" +version = "25.3.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, + {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, +] + +[package.extras] +benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] +tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] + +[[package]] +name = "bcrypt" +version = "4.3.0" +description = "Modern password hashing for your software and your servers" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "bcrypt-4.3.0-cp313-cp313t-macosx_10_12_universal2.whl", hash = "sha256:f01e060f14b6b57bbb72fc5b4a83ac21c443c9a2ee708e04a10e9192f90a6281"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5eeac541cefd0bb887a371ef73c62c3cd78535e4887b310626036a7c0a817bb"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59e1aa0e2cd871b08ca146ed08445038f42ff75968c7ae50d2fdd7860ade2180"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:0042b2e342e9ae3d2ed22727c1262f76cc4f345683b5c1715f0250cf4277294f"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74a8d21a09f5e025a9a23e7c0fd2c7fe8e7503e4d356c0a2c1486ba010619f09"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:0142b2cb84a009f8452c8c5a33ace5e3dfec4159e7735f5afe9a4d50a8ea722d"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_34_aarch64.whl", hash = "sha256:12fa6ce40cde3f0b899729dbd7d5e8811cb892d31b6f7d0334a1f37748b789fd"}, + {file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_34_x86_64.whl", hash = "sha256:5bd3cca1f2aa5dbcf39e2aa13dd094ea181f48959e1071265de49cc2b82525af"}, + {file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:335a420cfd63fc5bc27308e929bee231c15c85cc4c496610ffb17923abf7f231"}, + {file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:0e30e5e67aed0187a1764911af023043b4542e70a7461ad20e837e94d23e1d6c"}, + {file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b8d62290ebefd49ee0b3ce7500f5dbdcf13b81402c05f6dafab9a1e1b27212f"}, + {file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2ef6630e0ec01376f59a006dc72918b1bf436c3b571b80fa1968d775fa02fe7d"}, + {file = "bcrypt-4.3.0-cp313-cp313t-win32.whl", hash = "sha256:7a4be4cbf241afee43f1c3969b9103a41b40bcb3a3f467ab19f891d9bc4642e4"}, + {file = "bcrypt-4.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c1949bf259a388863ced887c7861da1df681cb2388645766c89fdfd9004c669"}, + {file = "bcrypt-4.3.0-cp38-abi3-macosx_10_12_universal2.whl", hash = "sha256:f81b0ed2639568bf14749112298f9e4e2b28853dab50a8b357e31798686a036d"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:864f8f19adbe13b7de11ba15d85d4a428c7e2f344bac110f667676a0ff84924b"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e36506d001e93bffe59754397572f21bb5dc7c83f54454c990c74a468cd589e"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:842d08d75d9fe9fb94b18b071090220697f9f184d4547179b60734846461ed59"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7c03296b85cb87db865d91da79bf63d5609284fc0cab9472fdd8367bbd830753"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:62f26585e8b219cdc909b6a0069efc5e4267e25d4a3770a364ac58024f62a761"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:beeefe437218a65322fbd0069eb437e7c98137e08f22c4660ac2dc795c31f8bb"}, + {file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:97eea7408db3a5bcce4a55d13245ab3fa566e23b4c67cd227062bb49e26c585d"}, + {file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:191354ebfe305e84f344c5964c7cd5f924a3bfc5d405c75ad07f232b6dffb49f"}, + {file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:41261d64150858eeb5ff43c753c4b216991e0ae16614a308a15d909503617732"}, + {file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:33752b1ba962ee793fa2b6321404bf20011fe45b9afd2a842139de3011898fef"}, + {file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:50e6e80a4bfd23a25f5c05b90167c19030cf9f87930f7cb2eacb99f45d1c3304"}, + {file = "bcrypt-4.3.0-cp38-abi3-win32.whl", hash = "sha256:67a561c4d9fb9465ec866177e7aebcad08fe23aaf6fbd692a6fab69088abfc51"}, + {file = "bcrypt-4.3.0-cp38-abi3-win_amd64.whl", hash = "sha256:584027857bc2843772114717a7490a37f68da563b3620f78a849bcb54dc11e62"}, + {file = "bcrypt-4.3.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0d3efb1157edebfd9128e4e46e2ac1a64e0c1fe46fb023158a407c7892b0f8c3"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08bacc884fd302b611226c01014eca277d48f0a05187666bca23aac0dad6fe24"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6746e6fec103fcd509b96bacdfdaa2fbde9a553245dbada284435173a6f1aef"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:afe327968aaf13fc143a56a3360cb27d4ad0345e34da12c7290f1b00b8fe9a8b"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d9af79d322e735b1fc33404b5765108ae0ff232d4b54666d46730f8ac1a43676"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f1e3ffa1365e8702dc48c8b360fef8d7afeca482809c5e45e653af82ccd088c1"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:3004df1b323d10021fda07a813fd33e0fd57bef0e9a480bb143877f6cba996fe"}, + {file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:531457e5c839d8caea9b589a1bcfe3756b0547d7814e9ce3d437f17da75c32b0"}, + {file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:17a854d9a7a476a89dcef6c8bd119ad23e0f82557afbd2c442777a16408e614f"}, + {file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6fb1fd3ab08c0cbc6826a2e0447610c6f09e983a281b919ed721ad32236b8b23"}, + {file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e965a9c1e9a393b8005031ff52583cedc15b7884fce7deb8b0346388837d6cfe"}, + {file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:79e70b8342a33b52b55d93b3a59223a844962bef479f6a0ea318ebbcadf71505"}, + {file = "bcrypt-4.3.0-cp39-abi3-win32.whl", hash = "sha256:b4d4e57f0a63fd0b358eb765063ff661328f69a04494427265950c71b992a39a"}, + {file = "bcrypt-4.3.0-cp39-abi3-win_amd64.whl", hash = "sha256:e53e074b120f2877a35cc6c736b8eb161377caae8925c17688bd46ba56daaa5b"}, + {file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c950d682f0952bafcceaf709761da0a32a942272fad381081b51096ffa46cea1"}, + {file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:107d53b5c67e0bbc3f03ebf5b030e0403d24dda980f8e244795335ba7b4a027d"}, + {file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:b693dbb82b3c27a1604a3dff5bfc5418a7e6a781bb795288141e5f80cf3a3492"}, + {file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:b6354d3760fcd31994a14c89659dee887f1351a06e5dac3c1142307172a79f90"}, + {file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a839320bf27d474e52ef8cb16449bb2ce0ba03ca9f44daba6d93fa1d8828e48a"}, + {file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:bdc6a24e754a555d7316fa4774e64c6c3997d27ed2d1964d55920c7c227bc4ce"}, + {file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:55a935b8e9a1d2def0626c4269db3fcd26728cbff1e84f0341465c31c4ee56d8"}, + {file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:57967b7a28d855313a963aaea51bf6df89f833db4320da458e5b3c5ab6d4c938"}, + {file = "bcrypt-4.3.0.tar.gz", hash = "sha256:3a3fd2204178b6d2adcf09cb4f6426ffef54762577a7c9b54c159008cb288c18"}, +] + +[package.extras] +tests = ["pytest (>=3.2.1,!=3.3.0)"] +typecheck = ["mypy"] + +[[package]] +name = "bech32" +version = "1.2.0" +description = "Reference implementation for Bech32 and segwit addresses." +optional = false +python-versions = ">=3.5" +groups = ["main"] +files = [ + {file = "bech32-1.2.0-py3-none-any.whl", hash = "sha256:990dc8e5a5e4feabbdf55207b5315fdd9b73db40be294a19b3752cde9e79d981"}, + {file = "bech32-1.2.0.tar.gz", hash = "sha256:7d6db8214603bd7871fcfa6c0826ef68b85b0abd90fa21c285a9c5e21d2bd899"}, +] + +[[package]] +name = "bip-utils" +version = "2.9.3" +description = "Generation of mnemonics, seeds, private/public keys and addresses for different types of cryptocurrencies" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "bip_utils-2.9.3-py3-none-any.whl", hash = "sha256:ee26b8417a576c7f89b847da37316db01a5cece1994c1609d37fbeefb91ad45e"}, + {file = "bip_utils-2.9.3.tar.gz", hash = "sha256:72a8c95484b57e92311b0b2a3d5195b0ce4395c19a0b157d4a289e8b1300f48a"}, +] + +[package.dependencies] +cbor2 = ">=5.1.2,<6.0.0" +coincurve = [ + {version = ">=16.0.0", markers = "python_version == \"3.10\""}, + {version = ">=18.0.0", markers = "python_version == \"3.11\""}, + {version = ">=19.0.1", markers = "python_version >= \"3.12\""}, +] +crcmod = ">=1.7,<2.0" +ecdsa = ">=0.17,<1.0" +ed25519-blake2b = [ + {version = ">=1.4,<2.0.0", markers = "python_version < \"3.12\""}, + {version = ">=1.4.1,<2.0.0", markers = "python_version >= \"3.12\""}, +] +py-sr25519-bindings = [ + {version = ">=0.1.4,<2.0.0", markers = "python_version == \"3.10\""}, + {version = ">=0.2.0,<2.0.0", markers = "python_version >= \"3.11\""}, +] +pycryptodome = ">=3.15,<4.0" +pynacl = ">=1.5,<2.0" + +[package.extras] +develop = ["coverage (>=5.3)", "flake8 (>=3.8)", "isort (>=5.8)", "mypy (>=0.900)", "prospector[with-mypy,with-pyroma] (>=1.7)", "pytest (>=7.0)", "pytest-cov (>=2.10)"] + +[[package]] +name = "black" +version = "24.10.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, + {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, + {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, + {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, + {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, + {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, + {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, + {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, + {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, + {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, + {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, + {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, + {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, + {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, + {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, + {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, + {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, + {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, + {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, + {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, + {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, + {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.10)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "boolean-py" +version = "5.0" +description = "Define boolean algebras, create and parse boolean expressions and create custom boolean DSL." +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "boolean_py-5.0-py3-none-any.whl", hash = "sha256:ef28a70bd43115208441b53a045d1549e2f0ec6e3d08a9d142cbc41c1938e8d9"}, + {file = "boolean_py-5.0.tar.gz", hash = "sha256:60cbc4bad079753721d32649545505362c754e121570ada4658b852a3a318d95"}, +] + +[package.extras] +dev = ["build", "twine"] +docs = ["Sphinx (>=3.3.1)", "doc8 (>=0.8.1)", "sphinx-rtd-theme (>=0.5.0)", "sphinxcontrib-apidoc (>=0.3.0)"] +linting = ["black", "isort", "pycodestyle"] +testing = ["pytest (>=6,!=7.0.0)", "pytest-xdist (>=2)"] + +[[package]] +name = "cachecontrol" +version = "0.14.3" +description = "httplib2 caching for requests" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "cachecontrol-0.14.3-py3-none-any.whl", hash = "sha256:b35e44a3113f17d2a31c1e6b27b9de6d4405f84ae51baa8c1d3cc5b633010cae"}, + {file = "cachecontrol-0.14.3.tar.gz", hash = "sha256:73e7efec4b06b20d9267b441c1f733664f989fb8688391b670ca812d70795d11"}, +] + +[package.dependencies] +filelock = {version = ">=3.8.0", optional = true, markers = "extra == \"filecache\""} +msgpack = ">=0.5.2,<2.0.0" +requests = ">=2.16.0" + +[package.extras] +dev = ["CacheControl[filecache,redis]", "build", "cherrypy", "codespell[tomli]", "furo", "mypy", "pytest", "pytest-cov", "ruff", "sphinx", "sphinx-copybutton", "tox", "types-redis", "types-requests"] +filecache = ["filelock (>=3.8.0)"] +redis = ["redis (>=2.10.5)"] + +[[package]] +name = "cbor2" +version = "5.6.5" +description = "CBOR (de)serializer with extensive tag support" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "cbor2-5.6.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e16c4a87fc999b4926f5c8f6c696b0d251b4745bc40f6c5aee51d69b30b15ca2"}, + {file = "cbor2-5.6.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:87026fc838370d69f23ed8572939bd71cea2b3f6c8f8bb8283f573374b4d7f33"}, + {file = "cbor2-5.6.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a88f029522aec5425fc2f941b3df90da7688b6756bd3f0472ab886d21208acbd"}, + {file = "cbor2-5.6.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9d15b638539b68aa5d5eacc56099b4543a38b2d2c896055dccf7e83d24b7955"}, + {file = "cbor2-5.6.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:47261f54a024839ec649b950013c4de5b5f521afe592a2688eebbe22430df1dc"}, + {file = "cbor2-5.6.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:559dcf0d897260a9e95e7b43556a62253e84550b77147a1ad4d2c389a2a30192"}, + {file = "cbor2-5.6.5-cp310-cp310-win_amd64.whl", hash = "sha256:5b856fda4c50c5bc73ed3664e64211fa4f015970ed7a15a4d6361bd48462feaf"}, + {file = "cbor2-5.6.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:863e0983989d56d5071270790e7ed8ddbda88c9e5288efdb759aba2efee670bc"}, + {file = "cbor2-5.6.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5cff06464b8f4ca6eb9abcba67bda8f8334a058abc01005c8e616728c387ad32"}, + {file = "cbor2-5.6.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4c7dbcdc59ea7f5a745d3e30ee5e6b6ff5ce7ac244aa3de6786391b10027bb3"}, + {file = "cbor2-5.6.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34cf5ab0dc310c3d0196caa6ae062dc09f6c242e2544bea01691fe60c0230596"}, + {file = "cbor2-5.6.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6797b824b26a30794f2b169c0575301ca9b74ae99064e71d16e6ba0c9057de51"}, + {file = "cbor2-5.6.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:73b9647eed1493097db6aad61e03d8f1252080ee041a1755de18000dd2c05f37"}, + {file = "cbor2-5.6.5-cp311-cp311-win_amd64.whl", hash = "sha256:6e14a1bf6269d25e02ef1d4008e0ce8880aa271d7c6b4c329dba48645764f60e"}, + {file = "cbor2-5.6.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e25c2aebc9db99af7190e2261168cdde8ed3d639ca06868e4f477cf3a228a8e9"}, + {file = "cbor2-5.6.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fde21ac1cf29336a31615a2c469a9cb03cf0add3ae480672d4d38cda467d07fc"}, + {file = "cbor2-5.6.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8947c102cac79d049eadbd5e2ffb8189952890df7cbc3ee262bbc2f95b011a9"}, + {file = "cbor2-5.6.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38886c41bebcd7dca57739439455bce759f1e4c551b511f618b8e9c1295b431b"}, + {file = "cbor2-5.6.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ae2b49226224e92851c333b91d83292ec62eba53a19c68a79890ce35f1230d70"}, + {file = "cbor2-5.6.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f2764804ffb6553283fc4afb10a280715905a4cea4d6dc7c90d3e89c4a93bc8d"}, + {file = "cbor2-5.6.5-cp312-cp312-win_amd64.whl", hash = "sha256:a3ac50485cf67dfaab170a3e7b527630e93cb0a6af8cdaa403054215dff93adf"}, + {file = "cbor2-5.6.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f0d0a9c5aabd48ecb17acf56004a7542a0b8d8212be52f3102b8218284bd881e"}, + {file = "cbor2-5.6.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:61ceb77e6aa25c11c814d4fe8ec9e3bac0094a1f5bd8a2a8c95694596ea01e08"}, + {file = "cbor2-5.6.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97a7e409b864fecf68b2ace8978eb5df1738799a333ec3ea2b9597bfcdd6d7d2"}, + {file = "cbor2-5.6.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f6d69f38f7d788b04c09ef2b06747536624b452b3c8b371ab78ad43b0296fab"}, + {file = "cbor2-5.6.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f91e6d74fa6917df31f8757fdd0e154203b0dd0609ec53eb957016a2b474896a"}, + {file = "cbor2-5.6.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5ce13a27ef8fddf643fc17a753fe34aa72b251d03c23da6a560c005dc171085b"}, + {file = "cbor2-5.6.5-cp313-cp313-win_amd64.whl", hash = "sha256:54c72a3207bb2d4480c2c39dad12d7971ce0853a99e3f9b8d559ce6eac84f66f"}, + {file = "cbor2-5.6.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4586a4f65546243096e56a3f18f29d60752ee9204722377021b3119a03ed99ff"}, + {file = "cbor2-5.6.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d1a18b3a58dcd9b40ab55c726160d4a6b74868f2a35b71f9e726268b46dc6a2"}, + {file = "cbor2-5.6.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a83b76367d1c3e69facbcb8cdf65ed6948678e72f433137b41d27458aa2a40cb"}, + {file = "cbor2-5.6.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90bfa36944caccec963e6ab7e01e64e31cc6664535dc06e6295ee3937c999cbb"}, + {file = "cbor2-5.6.5-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:37096663a5a1c46a776aea44906cbe5fa3952f29f50f349179c00525d321c862"}, + {file = "cbor2-5.6.5-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:93676af02bd9a0b4a62c17c5b20f8e9c37b5019b1a24db70a2ee6cb770423568"}, + {file = "cbor2-5.6.5-cp38-cp38-win_amd64.whl", hash = "sha256:8f747b7a9aaa58881a0c5b4cd4a9b8fb27eca984ed261a769b61de1f6b5bd1e6"}, + {file = "cbor2-5.6.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:94885903105eec66d7efb55f4ce9884fdc5a4d51f3bd75b6fedc68c5c251511b"}, + {file = "cbor2-5.6.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fe11c2eb518c882cfbeed456e7a552e544893c17db66fe5d3230dbeaca6b615c"}, + {file = "cbor2-5.6.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66dd25dd919cddb0b36f97f9ccfa51947882f064729e65e6bef17c28535dc459"}, + {file = "cbor2-5.6.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa61a02995f3a996c03884cf1a0b5733f88cbfd7fa0e34944bf678d4227ee712"}, + {file = "cbor2-5.6.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:824f202b556fc204e2e9a67d6d6d624e150fbd791278ccfee24e68caec578afd"}, + {file = "cbor2-5.6.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7488aec919f8408f9987a3a32760bd385d8628b23a35477917aa3923ff6ad45f"}, + {file = "cbor2-5.6.5-cp39-cp39-win_amd64.whl", hash = "sha256:a34ee99e86b17444ecbe96d54d909dd1a20e2da9f814ae91b8b71cf1ee2a95e4"}, + {file = "cbor2-5.6.5-py3-none-any.whl", hash = "sha256:3038523b8fc7de312bb9cdcbbbd599987e64307c4db357cd2030c472a6c7d468"}, + {file = "cbor2-5.6.5.tar.gz", hash = "sha256:b682820677ee1dbba45f7da11898d2720f92e06be36acec290867d5ebf3d7e09"}, +] + +[package.extras] +benchmarks = ["pytest-benchmark (==4.0.0)"] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.3.0)", "typing-extensions ; python_version < \"3.12\""] +test = ["coverage (>=7)", "hypothesis", "pytest"] + +[[package]] +name = "certifi" +version = "2025.8.3" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.7" +groups = ["main", "dev"] +files = [ + {file = "certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5"}, + {file = "certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407"}, +] + +[[package]] +name = "cffi" +version = "1.17.1" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "3.4.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7" +groups = ["main", "dev"] +files = [ + {file = "charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-win32.whl", hash = "sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-win32.whl", hash = "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e"}, + {file = "charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0"}, + {file = "charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63"}, +] + +[[package]] +name = "click" +version = "8.2.1" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.10" +groups = ["main", "dev"] +files = [ + {file = "click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b"}, + {file = "click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "clr-loader" +version = "0.2.7.post0" +description = "Generic pure Python loader for .NET runtimes" +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"gui-win\"" +files = [ + {file = "clr_loader-0.2.7.post0-py3-none-any.whl", hash = "sha256:e0b9fcc107d48347a4311a28ffe3ae78c4968edb216ffb6564cb03f7ace0bb47"}, + {file = "clr_loader-0.2.7.post0.tar.gz", hash = "sha256:b7a8b3f8fbb1bcbbb6382d887e21d1742d4f10b5ea209e4ad95568fe97e1c7c6"}, +] + +[package.dependencies] +cffi = {version = ">=1.17", markers = "python_version >= \"3.8\""} + +[[package]] +name = "coincurve" +version = "21.0.0" +description = "Safest and fastest Python library for secp256k1 elliptic curve operations" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "coincurve-21.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:986727bba6cf0c5670990358dc6af9a54f8d3e257979b992a9dbd50dd82fa0dc"}, + {file = "coincurve-21.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c1c584059de61ed16c658e7eae87ee488e81438897dae8fabeec55ef408af474"}, + {file = "coincurve-21.0.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4210b35c922b2b36c987a48c0b110ab20e490a2d6a92464ca654cb09e739fcc"}, + {file = "coincurve-21.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf67332cc647ef52ef371679c76000f096843ae266ae6df5e81906eb6463186b"}, + {file = "coincurve-21.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997607a952913c6a4bebe86815f458e77a42467b7a75353ccdc16c3336726880"}, + {file = "coincurve-21.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cfdd0938f284fb147aa1723a69f8794273ec673b10856b6e6f5f63fcc99d0c2e"}, + {file = "coincurve-21.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:88c1e3f6df2f2fbe18152c789a18659ee0429dc604fc77530370c9442395f681"}, + {file = "coincurve-21.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:530b58ed570895612ef510e28df5e8a33204b03baefb5c986e22811fa09622ef"}, + {file = "coincurve-21.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:f920af756a98edd738c0cfa431e81e3109aeec6ffd6dffb5ed4f5b5a37aacba8"}, + {file = "coincurve-21.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:070e060d0d57b496e68e48b39d5e3245681376d122827cb8e09f33669ff8cf1b"}, + {file = "coincurve-21.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:65ec42cab9c60d587fb6275c71f0ebc580625c377a894c4818fb2a2b583a184b"}, + {file = "coincurve-21.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5828cd08eab928db899238874d1aab12fa1236f30fe095a3b7e26a5fc81df0a3"}, + {file = "coincurve-21.0.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54de1cac75182de9f71ce41415faafcaf788303e21cbd0188064e268d61625e5"}, + {file = "coincurve-21.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07cda058d9394bea30d57a92fdc18ee3ca6b5bc8ef776a479a2ffec917105836"}, + {file = "coincurve-21.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9070804d7c71badfe4f0bf19b728cfe7c70c12e733938ead6b1db37920b745c0"}, + {file = "coincurve-21.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:669ab5db393637824b226de058bb7ea0cb9a0236e1842d7b22f74d4a8a1f1ff1"}, + {file = "coincurve-21.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3bcd538af097b3914ec3cb654262e72e224f95f2e9c1eb7fbd75d843ae4e528e"}, + {file = "coincurve-21.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:45b6a5e6b5536e1f46f729829d99ce1f8f847308d339e8880fe7fa1646935c10"}, + {file = "coincurve-21.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:87597cf30dfc05fa74218810776efacf8816813ab9fa6ea1490f94e9f8b15e77"}, + {file = "coincurve-21.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:b992d1b1dac85d7f542d9acbcf245667438839484d7f2b032fd032256bcd778e"}, + {file = "coincurve-21.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f60ad56113f08e8c540bb89f4f35f44d434311433195ffff22893ccfa335070c"}, + {file = "coincurve-21.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1cb1cd19fb0be22e68ecb60ad950b41f18b9b02eebeffaac9391dc31f74f08f2"}, + {file = "coincurve-21.0.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05d7e255a697b3475d7ae7640d3bdef3d5bc98ce9ce08dd387f780696606c33b"}, + {file = "coincurve-21.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a366c314df7217e3357bb8c7d2cda540b0bce180705f7a0ce2d1d9e28f62ad4"}, + {file = "coincurve-21.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b04778b75339c6e46deb9ae3bcfc2250fbe48d1324153e4310fc4996e135715"}, + {file = "coincurve-21.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8efcbdcd50cc219989a2662e6c6552f455efc000a15dd6ab3ebf4f9b187f41a3"}, + {file = "coincurve-21.0.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6df44b4e3b7acdc1453ade52a52e3f8a5b53ecdd5a06bd200f1ec4b4e250f7d9"}, + {file = "coincurve-21.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bcc0831f07cb75b91c35c13b1362e7b9dc76c376b27d01ff577bec52005e22a8"}, + {file = "coincurve-21.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:5dd7b66b83b143f3ad3861a68fc0279167a0bae44fe3931547400b7a200e90b1"}, + {file = "coincurve-21.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:78dbe439e8cb22389956a4f2f2312813b4bd0531a0b691d4f8e868c7b366555d"}, + {file = "coincurve-21.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9df5ceb5de603b9caf270629996710cf5ed1d43346887bc3895a11258644b65b"}, + {file = "coincurve-21.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:154467858d23c48f9e5ab380433bc2625027b50617400e2984cc16f5799ab601"}, + {file = "coincurve-21.0.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f57f07c44d14d939bed289cdeaba4acb986bba9f729a796b6a341eab1661eedc"}, + {file = "coincurve-21.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fb03e3a388a93d31ed56a442bdec7983ea404490e21e12af76fb1dbf097082a"}, + {file = "coincurve-21.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d09ba4fd9d26b00b06645fcd768c5ad44832a1fa847ebe8fb44970d3204c3cb7"}, + {file = "coincurve-21.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1a1e7ee73bc1b3bcf14c7b0d1f44e6485785d3b53ef7b16173c36d3cefa57f93"}, + {file = "coincurve-21.0.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ad05952b6edc593a874df61f1bc79db99d716ec48ba4302d699e14a419fe6f51"}, + {file = "coincurve-21.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4d2bf350ced38b73db9efa1ff8fd16a67a1cb35abb2dda50d89661b531f03fd3"}, + {file = "coincurve-21.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:54d9500c56d5499375e579c3917472ffcf804c3584dd79052a79974280985c74"}, + {file = "coincurve-21.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:773917f075ec4b94a7a742637d303a3a082616a115c36568eb6c873a8d950d18"}, + {file = "coincurve-21.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb82ba677fc7600a3bf200edc98f4f9604c317b18c7b3f0a10784b42686e3a53"}, + {file = "coincurve-21.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5001de8324c35eee95f34e011a5c3b4e7d9ae9ca4a862a93b2c89b3f467f511b"}, + {file = "coincurve-21.0.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4d0bb5340bcac695731bef51c3e0126f252453e2d1ae7fa1486d90eff978bf6"}, + {file = "coincurve-21.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a9b49789ff86f3cf86cfc8ff8c6c43bac2607720ec638e8ba471fa7e8765bd2"}, + {file = "coincurve-21.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b85b49e192d2ca1a906a7b978bacb55d4dcb297cc2900fbbd9b9180d50878779"}, + {file = "coincurve-21.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ad6445f0bb61b3a4404d87a857ddb2a74a642cd4d00810237641aab4d6b1a42f"}, + {file = "coincurve-21.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:d3f017f1491491f3f2c49e5d2d3a471a872d75117bfcb804d1167061c94bd347"}, + {file = "coincurve-21.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:500e5e38cd4cbc4ea8a5c631ce843b1d52ef19ac41128568214d150f75f1f387"}, + {file = "coincurve-21.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:ef81ca24511a808ad0ebdb8fdaf9c5c87f12f935b3d117acccc6520ad671bcce"}, + {file = "coincurve-21.0.0-cp39-cp39-win_arm64.whl", hash = "sha256:6ec8e859464116a3c90168cd2bd7439527d4b4b5e328b42e3c8e0475f9b0bf71"}, + {file = "coincurve-21.0.0.tar.gz", hash = "sha256:8b37ce4265a82bebf0e796e21a769e56fdbf8420411ccbe3fafee4ed75b6a6e5"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "dev"] +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coverage" +version = "7.10.2" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "coverage-7.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:79f0283ab5e6499fd5fe382ca3d62afa40fb50ff227676a3125d18af70eabf65"}, + {file = "coverage-7.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4545e906f595ee8ab8e03e21be20d899bfc06647925bc5b224ad7e8c40e08b8"}, + {file = "coverage-7.10.2-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ae385e1d58fbc6a9b1c315e5510ac52281e271478b45f92ca9b5ad42cf39643f"}, + {file = "coverage-7.10.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f0cbe5f7dd19f3a32bac2251b95d51c3b89621ac88a2648096ce40f9a5aa1e7"}, + {file = "coverage-7.10.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fd17f427f041f6b116dc90b4049c6f3e1230524407d00daa2d8c7915037b5947"}, + {file = "coverage-7.10.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7f10ca4cde7b466405cce0a0e9971a13eb22e57a5ecc8b5f93a81090cc9c7eb9"}, + {file = "coverage-7.10.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3b990df23dd51dccce26d18fb09fd85a77ebe46368f387b0ffba7a74e470b31b"}, + {file = "coverage-7.10.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc3902584d25c7eef57fb38f440aa849a26a3a9f761a029a72b69acfca4e31f8"}, + {file = "coverage-7.10.2-cp310-cp310-win32.whl", hash = "sha256:9dd37e9ac00d5eb72f38ed93e3cdf2280b1dbda3bb9b48c6941805f265ad8d87"}, + {file = "coverage-7.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:99d16f15cb5baf0729354c5bd3080ae53847a4072b9ba1e10957522fb290417f"}, + {file = "coverage-7.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c3b210d79925a476dfc8d74c7d53224888421edebf3a611f3adae923e212b27"}, + {file = "coverage-7.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf67d1787cd317c3f8b2e4c6ed1ae93497be7e30605a0d32237ac37a37a8a322"}, + {file = "coverage-7.10.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:069b779d03d458602bc0e27189876e7d8bdf6b24ac0f12900de22dd2154e6ad7"}, + {file = "coverage-7.10.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4c2de4cb80b9990e71c62c2d3e9f3ec71b804b1f9ca4784ec7e74127e0f42468"}, + {file = "coverage-7.10.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75bf7ab2374a7eb107602f1e07310cda164016cd60968abf817b7a0b5703e288"}, + {file = "coverage-7.10.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3f37516458ec1550815134937f73d6d15b434059cd10f64678a2068f65c62406"}, + {file = "coverage-7.10.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:de3c6271c482c250d3303fb5c6bdb8ca025fff20a67245e1425df04dc990ece9"}, + {file = "coverage-7.10.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:98a838101321ac3089c9bb1d4bfa967e8afed58021fda72d7880dc1997f20ae1"}, + {file = "coverage-7.10.2-cp311-cp311-win32.whl", hash = "sha256:f2a79145a531a0e42df32d37be5af069b4a914845b6f686590739b786f2f7bce"}, + {file = "coverage-7.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:e4f5f1320f8ee0d7cfa421ceb257bef9d39fd614dd3ddcfcacd284d4824ed2c2"}, + {file = "coverage-7.10.2-cp311-cp311-win_arm64.whl", hash = "sha256:d8f2d83118f25328552c728b8e91babf93217db259ca5c2cd4dd4220b8926293"}, + {file = "coverage-7.10.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:890ad3a26da9ec7bf69255b9371800e2a8da9bc223ae5d86daeb940b42247c83"}, + {file = "coverage-7.10.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38fd1ccfca7838c031d7a7874d4353e2f1b98eb5d2a80a2fe5732d542ae25e9c"}, + {file = "coverage-7.10.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:76c1ffaaf4f6f0f6e8e9ca06f24bb6454a7a5d4ced97a1bc466f0d6baf4bd518"}, + {file = "coverage-7.10.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:86da8a3a84b79ead5c7d0e960c34f580bc3b231bb546627773a3f53c532c2f21"}, + {file = "coverage-7.10.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99cef9731c8a39801830a604cc53c93c9e57ea8b44953d26589499eded9576e0"}, + {file = "coverage-7.10.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ea58b112f2966a8b91eb13f5d3b1f8bb43c180d624cd3283fb33b1cedcc2dd75"}, + {file = "coverage-7.10.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:20f405188d28da9522b7232e51154e1b884fc18d0b3a10f382d54784715bbe01"}, + {file = "coverage-7.10.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:64586ce42bbe0da4d9f76f97235c545d1abb9b25985a8791857690f96e23dc3b"}, + {file = "coverage-7.10.2-cp312-cp312-win32.whl", hash = "sha256:bc2e69b795d97ee6d126e7e22e78a509438b46be6ff44f4dccbb5230f550d340"}, + {file = "coverage-7.10.2-cp312-cp312-win_amd64.whl", hash = "sha256:adda2268b8cf0d11f160fad3743b4dfe9813cd6ecf02c1d6397eceaa5b45b388"}, + {file = "coverage-7.10.2-cp312-cp312-win_arm64.whl", hash = "sha256:164429decd0d6b39a0582eaa30c67bf482612c0330572343042d0ed9e7f15c20"}, + {file = "coverage-7.10.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:aca7b5645afa688de6d4f8e89d30c577f62956fefb1bad021490d63173874186"}, + {file = "coverage-7.10.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:96e5921342574a14303dfdb73de0019e1ac041c863743c8fe1aa6c2b4a257226"}, + {file = "coverage-7.10.2-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:11333094c1bff621aa811b67ed794865cbcaa99984dedea4bd9cf780ad64ecba"}, + {file = "coverage-7.10.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6eb586fa7d2aee8d65d5ae1dd71414020b2f447435c57ee8de8abea0a77d5074"}, + {file = "coverage-7.10.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2d358f259d8019d4ef25d8c5b78aca4c7af25e28bd4231312911c22a0e824a57"}, + {file = "coverage-7.10.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5250bda76e30382e0a2dcd68d961afcab92c3a7613606e6269855c6979a1b0bb"}, + {file = "coverage-7.10.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a91e027d66eff214d88d9afbe528e21c9ef1ecdf4956c46e366c50f3094696d0"}, + {file = "coverage-7.10.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:228946da741558904e2c03ce870ba5efd9cd6e48cbc004d9a27abee08100a15a"}, + {file = "coverage-7.10.2-cp313-cp313-win32.whl", hash = "sha256:95e23987b52d02e7c413bf2d6dc6288bd5721beb518052109a13bfdc62c8033b"}, + {file = "coverage-7.10.2-cp313-cp313-win_amd64.whl", hash = "sha256:f35481d42c6d146d48ec92d4e239c23f97b53a3f1fbd2302e7c64336f28641fe"}, + {file = "coverage-7.10.2-cp313-cp313-win_arm64.whl", hash = "sha256:65b451949cb789c346f9f9002441fc934d8ccedcc9ec09daabc2139ad13853f7"}, + {file = "coverage-7.10.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:e8415918856a3e7d57a4e0ad94651b761317de459eb74d34cc1bb51aad80f07e"}, + {file = "coverage-7.10.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f287a25a8ca53901c613498e4a40885b19361a2fe8fbfdbb7f8ef2cad2a23f03"}, + {file = "coverage-7.10.2-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:75cc1a3f8c88c69bf16a871dab1fe5a7303fdb1e9f285f204b60f1ee539b8fc0"}, + {file = "coverage-7.10.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ca07fa78cc9d26bc8c4740de1abd3489cf9c47cc06d9a8ab3d552ff5101af4c0"}, + {file = "coverage-7.10.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c2e117e64c26300032755d4520cd769f2623cde1a1d1c3515b05a3b8add0ade1"}, + {file = "coverage-7.10.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:daaf98009977f577b71f8800208f4d40d4dcf5c2db53d4d822787cdc198d76e1"}, + {file = "coverage-7.10.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ea8d8fe546c528535c761ba424410bbeb36ba8a0f24be653e94b70c93fd8a8ca"}, + {file = "coverage-7.10.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:fe024d40ac31eb8d5aae70215b41dafa264676caa4404ae155f77d2fa95c37bb"}, + {file = "coverage-7.10.2-cp313-cp313t-win32.whl", hash = "sha256:8f34b09f68bdadec122ffad312154eda965ade433559cc1eadd96cca3de5c824"}, + {file = "coverage-7.10.2-cp313-cp313t-win_amd64.whl", hash = "sha256:71d40b3ac0f26fa9ffa6ee16219a714fed5c6ec197cdcd2018904ab5e75bcfa3"}, + {file = "coverage-7.10.2-cp313-cp313t-win_arm64.whl", hash = "sha256:abb57fdd38bf6f7dcc66b38dafb7af7c5fdc31ac6029ce373a6f7f5331d6f60f"}, + {file = "coverage-7.10.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a3e853cc04987c85ec410905667eed4bf08b1d84d80dfab2684bb250ac8da4f6"}, + {file = "coverage-7.10.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0100b19f230df72c90fdb36db59d3f39232391e8d89616a7de30f677da4f532b"}, + {file = "coverage-7.10.2-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9c1cd71483ea78331bdfadb8dcec4f4edfb73c7002c1206d8e0af6797853f5be"}, + {file = "coverage-7.10.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9f75dbf4899e29a37d74f48342f29279391668ef625fdac6d2f67363518056a1"}, + {file = "coverage-7.10.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a7df481e7508de1c38b9b8043da48d94931aefa3e32b47dd20277e4978ed5b95"}, + {file = "coverage-7.10.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:835f39e618099325e7612b3406f57af30ab0a0af350490eff6421e2e5f608e46"}, + {file = "coverage-7.10.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:12e52b5aa00aa720097d6947d2eb9e404e7c1101ad775f9661ba165ed0a28303"}, + {file = "coverage-7.10.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:718044729bf1fe3e9eb9f31b52e44ddae07e434ec050c8c628bf5adc56fe4bdd"}, + {file = "coverage-7.10.2-cp314-cp314-win32.whl", hash = "sha256:f256173b48cc68486299d510a3e729a96e62c889703807482dbf56946befb5c8"}, + {file = "coverage-7.10.2-cp314-cp314-win_amd64.whl", hash = "sha256:2e980e4179f33d9b65ac4acb86c9c0dde904098853f27f289766657ed16e07b3"}, + {file = "coverage-7.10.2-cp314-cp314-win_arm64.whl", hash = "sha256:14fb5b6641ab5b3c4161572579f0f2ea8834f9d3af2f7dd8fbaecd58ef9175cc"}, + {file = "coverage-7.10.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:e96649ac34a3d0e6491e82a2af71098e43be2874b619547c3282fc11d3840a4b"}, + {file = "coverage-7.10.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1a2e934e9da26341d342d30bfe91422bbfdb3f1f069ec87f19b2909d10d8dcc4"}, + {file = "coverage-7.10.2-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:651015dcd5fd9b5a51ca79ece60d353cacc5beaf304db750407b29c89f72fe2b"}, + {file = "coverage-7.10.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:81bf6a32212f9f66da03d63ecb9cd9bd48e662050a937db7199dbf47d19831de"}, + {file = "coverage-7.10.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d800705f6951f75a905ea6feb03fff8f3ea3468b81e7563373ddc29aa3e5d1ca"}, + {file = "coverage-7.10.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:248b5394718e10d067354448dc406d651709c6765669679311170da18e0e9af8"}, + {file = "coverage-7.10.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5c61675a922b569137cf943770d7ad3edd0202d992ce53ac328c5ff68213ccf4"}, + {file = "coverage-7.10.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:52d708b5fd65589461381fa442d9905f5903d76c086c6a4108e8e9efdca7a7ed"}, + {file = "coverage-7.10.2-cp314-cp314t-win32.whl", hash = "sha256:916369b3b914186b2c5e5ad2f7264b02cff5df96cdd7cdad65dccd39aa5fd9f0"}, + {file = "coverage-7.10.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5b9d538e8e04916a5df63052d698b30c74eb0174f2ca9cd942c981f274a18eaf"}, + {file = "coverage-7.10.2-cp314-cp314t-win_arm64.whl", hash = "sha256:04c74f9ef1f925456a9fd23a7eef1103126186d0500ef9a0acb0bd2514bdc7cc"}, + {file = "coverage-7.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:765b13b164685a2f8b2abef867ad07aebedc0e090c757958a186f64e39d63dbd"}, + {file = "coverage-7.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a219b70100500d0c7fd3ebb824a3302efb6b1a122baa9d4eb3f43df8f0b3d899"}, + {file = "coverage-7.10.2-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e33e79a219105aa315439ee051bd50b6caa705dc4164a5aba6932c8ac3ce2d98"}, + {file = "coverage-7.10.2-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bc3945b7bad33957a9eca16e9e5eae4b17cb03173ef594fdaad228f4fc7da53b"}, + {file = "coverage-7.10.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bdff88e858ee608a924acfad32a180d2bf6e13e059d6a7174abbae075f30436"}, + {file = "coverage-7.10.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:44329cbed24966c0b49acb386352c9722219af1f0c80db7f218af7793d251902"}, + {file = "coverage-7.10.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:be127f292496d0fbe20d8025f73221b36117b3587f890346e80a13b310712982"}, + {file = "coverage-7.10.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6c031da749a05f7a01447dd7f47beedb498edd293e31e1878c0d52db18787df0"}, + {file = "coverage-7.10.2-cp39-cp39-win32.whl", hash = "sha256:22aca3e691c7709c5999ccf48b7a8ff5cf5a8bd6fe9b36efbd4993f5a36b2fcf"}, + {file = "coverage-7.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:c7195444b932356055a8e287fa910bf9753a84a1bc33aeb3770e8fca521e032e"}, + {file = "coverage-7.10.2-py3-none-any.whl", hash = "sha256:95db3750dd2e6e93d99fa2498f3a1580581e49c494bddccc6f85c5c21604921f"}, + {file = "coverage-7.10.2.tar.gz", hash = "sha256:5d6e6d84e6dd31a8ded64759626627247d676a23c1b892e1326f7c55c8d61055"}, +] + +[package.extras] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] + +[[package]] +name = "crcmod" +version = "1.7" +description = "CRC Generator" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "crcmod-1.7.tar.gz", hash = "sha256:dc7051a0db5f2bd48665a990d3ec1cc305a466a77358ca4492826f41f283601e"}, +] + +[[package]] +name = "cryptography" +version = "45.0.6" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = "!=3.9.0,!=3.9.1,>=3.7" +groups = ["main"] +files = [ + {file = "cryptography-45.0.6-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:048e7ad9e08cf4c0ab07ff7f36cc3115924e22e2266e034450a890d9e312dd74"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:44647c5d796f5fc042bbc6d61307d04bf29bccb74d188f18051b635f20a9c75f"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e40b80ecf35ec265c452eea0ba94c9587ca763e739b8e559c128d23bff7ebbbf"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:00e8724bdad672d75e6f069b27970883179bd472cd24a63f6e620ca7e41cc0c5"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a3085d1b319d35296176af31c90338eeb2ddac8104661df79f80e1d9787b8b2"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1b7fa6a1c1188c7ee32e47590d16a5a0646270921f8020efc9a511648e1b2e08"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:275ba5cc0d9e320cd70f8e7b96d9e59903c815ca579ab96c1e37278d231fc402"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f4028f29a9f38a2025abedb2e409973709c660d44319c61762202206ed577c42"}, + {file = "cryptography-45.0.6-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ee411a1b977f40bd075392c80c10b58025ee5c6b47a822a33c1198598a7a5f05"}, + {file = "cryptography-45.0.6-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e2a21a8eda2d86bb604934b6b37691585bd095c1f788530c1fcefc53a82b3453"}, + {file = "cryptography-45.0.6-cp311-abi3-win32.whl", hash = "sha256:d063341378d7ee9c91f9d23b431a3502fc8bfacd54ef0a27baa72a0843b29159"}, + {file = "cryptography-45.0.6-cp311-abi3-win_amd64.whl", hash = "sha256:833dc32dfc1e39b7376a87b9a6a4288a10aae234631268486558920029b086ec"}, + {file = "cryptography-45.0.6-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:3436128a60a5e5490603ab2adbabc8763613f638513ffa7d311c900a8349a2a0"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0d9ef57b6768d9fa58e92f4947cea96ade1233c0e236db22ba44748ffedca394"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea3c42f2016a5bbf71825537c2ad753f2870191134933196bee408aac397b3d9"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:20ae4906a13716139d6d762ceb3e0e7e110f7955f3bc3876e3a07f5daadec5f3"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dac5ec199038b8e131365e2324c03d20e97fe214af051d20c49db129844e8b3"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:18f878a34b90d688982e43f4b700408b478102dd58b3e39de21b5ebf6509c301"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5bd6020c80c5b2b2242d6c48487d7b85700f5e0038e67b29d706f98440d66eb5"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:eccddbd986e43014263eda489abbddfbc287af5cddfd690477993dbb31e31016"}, + {file = "cryptography-45.0.6-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:550ae02148206beb722cfe4ef0933f9352bab26b087af00e48fdfb9ade35c5b3"}, + {file = "cryptography-45.0.6-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5b64e668fc3528e77efa51ca70fadcd6610e8ab231e3e06ae2bab3b31c2b8ed9"}, + {file = "cryptography-45.0.6-cp37-abi3-win32.whl", hash = "sha256:780c40fb751c7d2b0c6786ceee6b6f871e86e8718a8ff4bc35073ac353c7cd02"}, + {file = "cryptography-45.0.6-cp37-abi3-win_amd64.whl", hash = "sha256:20d15aed3ee522faac1a39fbfdfee25d17b1284bafd808e1640a74846d7c4d1b"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:705bb7c7ecc3d79a50f236adda12ca331c8e7ecfbea51edd931ce5a7a7c4f012"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:826b46dae41a1155a0c0e66fafba43d0ede1dc16570b95e40c4d83bfcf0a451d"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:cc4d66f5dc4dc37b89cfef1bd5044387f7a1f6f0abb490815628501909332d5d"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:f68f833a9d445cc49f01097d95c83a850795921b3f7cc6488731e69bde3288da"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:3b5bf5267e98661b9b888a9250d05b063220dfa917a8203744454573c7eb79db"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2384f2ab18d9be88a6e4f8972923405e2dbb8d3e16c6b43f15ca491d7831bd18"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fc022c1fa5acff6def2fc6d7819bbbd31ccddfe67d075331a65d9cfb28a20983"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3de77e4df42ac8d4e4d6cdb342d989803ad37707cf8f3fbf7b088c9cbdd46427"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:599c8d7df950aa68baa7e98f7b73f4f414c9f02d0e8104a30c0182a07732638b"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:31a2b9a10530a1cb04ffd6aa1cd4d3be9ed49f7d77a4dafe198f3b382f41545c"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:e5b3dda1b00fb41da3af4c5ef3f922a200e33ee5ba0f0bc9ecf0b0c173958385"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:629127cfdcdc6806dfe234734d7cb8ac54edaf572148274fa377a7d3405b0043"}, + {file = "cryptography-45.0.6.tar.gz", hash = "sha256:5c966c732cf6e4a276ce83b6e4c729edda2df6929083a952cc7da973c539c719"}, +] + +[package.dependencies] +cffi = {version = ">=1.14", markers = "platform_python_implementation != \"PyPy\""} + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs ; python_full_version >= \"3.8.0\"", "sphinx-rtd-theme (>=3.0.0) ; python_full_version >= \"3.8.0\""] +docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] +nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_full_version >= \"3.8.0\""] +pep8test = ["check-sdist ; python_full_version >= \"3.8.0\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] +sdist = ["build (>=1.0.0)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["certifi (>=2024)", "cryptography-vectors (==45.0.6)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test-randomorder = ["pytest-randomly"] + +[[package]] +name = "cyclonedx-python-lib" +version = "9.1.0" +description = "Python library for CycloneDX" +optional = false +python-versions = "<4.0,>=3.8" +groups = ["dev"] +files = [ + {file = "cyclonedx_python_lib-9.1.0-py3-none-any.whl", hash = "sha256:55693fca8edaecc3363b24af14e82cc6e659eb1e8353e58b587c42652ce0fb52"}, + {file = "cyclonedx_python_lib-9.1.0.tar.gz", hash = "sha256:86935f2c88a7b47a529b93c724dbd3e903bc573f6f8bd977628a7ca1b5dadea1"}, +] + +[package.dependencies] +license-expression = ">=30,<31" +packageurl-python = ">=0.11,<2" +py-serializable = ">=2.0.0,<3.0.0" +sortedcontainers = ">=2.4.0,<3.0.0" + +[package.extras] +json-validation = ["jsonschema[format] (>=4.18,<5.0)"] +validation = ["jsonschema[format] (>=4.18,<5.0)", "lxml (>=4,<6)"] +xml-validation = ["lxml (>=4,<6)"] + +[[package]] +name = "defusedxml" +version = "0.7.1" +description = "XML bomb protection for Python stdlib modules" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["dev"] +files = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] + +[[package]] +name = "deprecated" +version = "1.2.18" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +groups = ["main"] +files = [ + {file = "Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec"}, + {file = "deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d"}, +] + +[package.dependencies] +wrapt = ">=1.10,<2" + +[package.extras] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version >= \"3.12\"", "tox"] + +[[package]] +name = "ecdsa" +version = "0.19.1" +description = "ECDSA cryptographic signature library (pure python)" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.6" +groups = ["main"] +files = [ + {file = "ecdsa-0.19.1-py2.py3-none-any.whl", hash = "sha256:30638e27cf77b7e15c4c4cc1973720149e1033827cfd00661ca5c8cc0cdb24c3"}, + {file = "ecdsa-0.19.1.tar.gz", hash = "sha256:478cba7b62555866fcb3bb3fe985e06decbdb68ef55713c4e5ab98c57d508e61"}, +] + +[package.dependencies] +six = ">=1.9.0" + +[package.extras] +gmpy = ["gmpy"] +gmpy2 = ["gmpy2"] + +[[package]] +name = "ed25519-blake2b" +version = "1.4.1" +description = "Ed25519 public-key signatures (BLAKE2b fork)" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "ed25519-blake2b-1.4.1.tar.gz", hash = "sha256:731e9f93cd1ac1a64649575f3519a99ffe0bb1e4cf7bf5f5f0be513a39df7363"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +groups = ["main", "dev"] +markers = "python_version == \"3.10\"" +files = [ + {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, + {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "execnet" +version = "2.1.1" +description = "execnet: rapid multi-Python deployment" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"}, + {file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"}, +] + +[package.extras] +testing = ["hatch", "pre-commit", "pytest", "tox"] + +[[package]] +name = "fastapi" +version = "0.116.1" +description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "fastapi-0.116.1-py3-none-any.whl", hash = "sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565"}, + {file = "fastapi-0.116.1.tar.gz", hash = "sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143"}, +] + +[package.dependencies] +pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +starlette = ">=0.40.0,<0.48.0" +typing-extensions = ">=4.8.0" + +[package.extras] +all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] +standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[standard-no-fastapi-cloud-cli] (>=0.0.8)", "httpx (>=0.23.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] + +[[package]] +name = "filelock" +version = "3.18.0" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de"}, + {file = "filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-asyncio (>=0.25.2)", "pytest-cov (>=6)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.28.1)"] +typing = ["typing-extensions (>=4.12.2) ; python_version < \"3.11\""] + +[[package]] +name = "fonttools" +version = "4.59.1" +description = "Tools to manipulate font files" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"gui-mac\"" +files = [ + {file = "fonttools-4.59.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e90a89e52deb56b928e761bb5b5f65f13f669bfd96ed5962975debea09776a23"}, + {file = "fonttools-4.59.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d29ab70658d2ec19422b25e6ace00a0b0ae4181ee31e03335eaef53907d2d83"}, + {file = "fonttools-4.59.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94f9721a564978a10d5c12927f99170d18e9a32e5a727c61eae56f956a4d118b"}, + {file = "fonttools-4.59.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8c8758a7d97848fc8b514b3d9b4cb95243714b2f838dde5e1e3c007375de6214"}, + {file = "fonttools-4.59.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2aeb829ad9d41a2ef17cab8bb5d186049ba38a840f10352e654aa9062ec32dc1"}, + {file = "fonttools-4.59.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac216a2980a2d2b3b88c68a24f8a9bfb203e2490e991b3238502ad8f1e7bfed0"}, + {file = "fonttools-4.59.1-cp310-cp310-win32.whl", hash = "sha256:d31dc137ed8ec71dbc446949eba9035926e6e967b90378805dcf667ff57cabb1"}, + {file = "fonttools-4.59.1-cp310-cp310-win_amd64.whl", hash = "sha256:5265bc52ed447187d39891b5f21d7217722735d0de9fe81326566570d12851a9"}, + {file = "fonttools-4.59.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4909cce2e35706f3d18c54d3dcce0414ba5e0fb436a454dffec459c61653b513"}, + {file = "fonttools-4.59.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:efbec204fa9f877641747f2d9612b2b656071390d7a7ef07a9dbf0ecf9c7195c"}, + {file = "fonttools-4.59.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39dfd42cc2dc647b2c5469bc7a5b234d9a49e72565b96dd14ae6f11c2c59ef15"}, + {file = "fonttools-4.59.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b11bc177a0d428b37890825d7d025040d591aa833f85f8d8878ed183354f47df"}, + {file = "fonttools-4.59.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b9b4c35b3be45e5bc774d3fc9608bbf4f9a8d371103b858c80edbeed31dd5aa"}, + {file = "fonttools-4.59.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:01158376b8a418a0bae9625c476cebfcfcb5e6761e9d243b219cd58341e7afbb"}, + {file = "fonttools-4.59.1-cp311-cp311-win32.whl", hash = "sha256:cf7c5089d37787387123f1cb8f1793a47c5e1e3d1e4e7bfbc1cc96e0f925eabe"}, + {file = "fonttools-4.59.1-cp311-cp311-win_amd64.whl", hash = "sha256:c866eef7a0ba320486ade6c32bfc12813d1a5db8567e6904fb56d3d40acc5116"}, + {file = "fonttools-4.59.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:43ab814bbba5f02a93a152ee61a04182bb5809bd2bc3609f7822e12c53ae2c91"}, + {file = "fonttools-4.59.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4f04c3ffbfa0baafcbc550657cf83657034eb63304d27b05cff1653b448ccff6"}, + {file = "fonttools-4.59.1-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d601b153e51a5a6221f0d4ec077b6bfc6ac35bfe6c19aeaa233d8990b2b71726"}, + {file = "fonttools-4.59.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c735e385e30278c54f43a0d056736942023c9043f84ee1021eff9fd616d17693"}, + {file = "fonttools-4.59.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1017413cdc8555dce7ee23720da490282ab7ec1cf022af90a241f33f9a49afc4"}, + {file = "fonttools-4.59.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5c6d8d773470a5107052874341ed3c487c16ecd179976d81afed89dea5cd7406"}, + {file = "fonttools-4.59.1-cp312-cp312-win32.whl", hash = "sha256:2a2d0d33307f6ad3a2086a95dd607c202ea8852fa9fb52af9b48811154d1428a"}, + {file = "fonttools-4.59.1-cp312-cp312-win_amd64.whl", hash = "sha256:0b9e4fa7eaf046ed6ac470f6033d52c052481ff7a6e0a92373d14f556f298dc0"}, + {file = "fonttools-4.59.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:89d9957b54246c6251345297dddf77a84d2c19df96af30d2de24093bbdf0528b"}, + {file = "fonttools-4.59.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8156b11c0d5405810d216f53907bd0f8b982aa5f1e7e3127ab3be1a4062154ff"}, + {file = "fonttools-4.59.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8387876a8011caec52d327d5e5bca705d9399ec4b17afb8b431ec50d47c17d23"}, + {file = "fonttools-4.59.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fb13823a74b3a9204a8ed76d3d6d5ec12e64cc5bc44914eb9ff1cdac04facd43"}, + {file = "fonttools-4.59.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e1ca10da138c300f768bb68e40e5b20b6ecfbd95f91aac4cc15010b6b9d65455"}, + {file = "fonttools-4.59.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2beb5bfc4887a3130f8625349605a3a45fe345655ce6031d1bac11017454b943"}, + {file = "fonttools-4.59.1-cp313-cp313-win32.whl", hash = "sha256:419f16d750d78e6d704bfe97b48bba2f73b15c9418f817d0cb8a9ca87a5b94bf"}, + {file = "fonttools-4.59.1-cp313-cp313-win_amd64.whl", hash = "sha256:c536f8a852e8d3fa71dde1ec03892aee50be59f7154b533f0bf3c1174cfd5126"}, + {file = "fonttools-4.59.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:d5c3bfdc9663f3d4b565f9cb3b8c1efb3e178186435b45105bde7328cfddd7fe"}, + {file = "fonttools-4.59.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ea03f1da0d722fe3c2278a05957e6550175571a4894fbf9d178ceef4a3783d2b"}, + {file = "fonttools-4.59.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:57a3708ca6bfccb790f585fa6d8f29432ec329618a09ff94c16bcb3c55994643"}, + {file = "fonttools-4.59.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:729367c91eb1ee84e61a733acc485065a00590618ca31c438e7dd4d600c01486"}, + {file = "fonttools-4.59.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8f8ef66ac6db450193ed150e10b3b45dde7aded10c5d279968bc63368027f62b"}, + {file = "fonttools-4.59.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:075f745d539a998cd92cb84c339a82e53e49114ec62aaea8307c80d3ad3aef3a"}, + {file = "fonttools-4.59.1-cp314-cp314-win32.whl", hash = "sha256:c2b0597522d4c5bb18aa5cf258746a2d4a90f25878cbe865e4d35526abd1b9fc"}, + {file = "fonttools-4.59.1-cp314-cp314-win_amd64.whl", hash = "sha256:e9ad4ce044e3236f0814c906ccce8647046cc557539661e35211faadf76f283b"}, + {file = "fonttools-4.59.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:652159e8214eb4856e8387ebcd6b6bd336ee258cbeb639c8be52005b122b9609"}, + {file = "fonttools-4.59.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:43d177cd0e847ea026fedd9f099dc917da136ed8792d142298a252836390c478"}, + {file = "fonttools-4.59.1-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e54437651e1440ee53a95e6ceb6ee440b67a3d348c76f45f4f48de1a5ecab019"}, + {file = "fonttools-4.59.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6065fdec8ff44c32a483fd44abe5bcdb40dd5e2571a5034b555348f2b3a52cea"}, + {file = "fonttools-4.59.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42052b56d176f8b315fbc09259439c013c0cb2109df72447148aeda677599612"}, + {file = "fonttools-4.59.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:bcd52eaa5c4c593ae9f447c1d13e7e4a00ca21d755645efa660b6999425b3c88"}, + {file = "fonttools-4.59.1-cp314-cp314t-win32.whl", hash = "sha256:02e4fdf27c550dded10fe038a5981c29f81cb9bc649ff2eaa48e80dab8998f97"}, + {file = "fonttools-4.59.1-cp314-cp314t-win_amd64.whl", hash = "sha256:412a5fd6345872a7c249dac5bcce380393f40c1c316ac07f447bc17d51900922"}, + {file = "fonttools-4.59.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1ab4c1fb45f2984b8b4a3face7cff0f67f9766e9414cbb6fd061e9d77819de98"}, + {file = "fonttools-4.59.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8ee39da0227950f88626c91e219659e6cd725ede826b1c13edd85fc4cec9bbe6"}, + {file = "fonttools-4.59.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:58a8844f96cff35860647a65345bfca87f47a2494bfb4bef754e58c082511443"}, + {file = "fonttools-4.59.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5f3f021cea6e36410874763f4a517a5e2d6ac36ca8f95521f3a9fdaad0fe73dc"}, + {file = "fonttools-4.59.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bf5fb864f80061a40c1747e0dbc4f6e738de58dd6675b07eb80bd06a93b063c4"}, + {file = "fonttools-4.59.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c29ea087843e27a7cffc78406d32a5abf166d92afde7890394e9e079c9b4dbe9"}, + {file = "fonttools-4.59.1-cp39-cp39-win32.whl", hash = "sha256:a960b09ff50c2e87864e83f352e5a90bcf1ad5233df579b1124660e1643de272"}, + {file = "fonttools-4.59.1-cp39-cp39-win_amd64.whl", hash = "sha256:e3680884189e2b7c3549f6d304376e64711fd15118e4b1ae81940cb6b1eaa267"}, + {file = "fonttools-4.59.1-py3-none-any.whl", hash = "sha256:647db657073672a8330608970a984d51573557f328030566521bc03415535042"}, + {file = "fonttools-4.59.1.tar.gz", hash = "sha256:74995b402ad09822a4c8002438e54940d9f1ecda898d2bb057729d7da983e4cb"}, +] + +[package.extras] +all = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\"", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0) ; python_version <= \"3.12\"", "xattr ; sys_platform == \"darwin\"", "zopfli (>=0.1.4)"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\""] +lxml = ["lxml (>=4.0)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr ; sys_platform == \"darwin\""] +unicode = ["unicodedata2 (>=15.1.0) ; python_version <= \"3.12\""] +woff = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "zopfli (>=0.1.4)"] + +[[package]] +name = "freezegun" +version = "1.5.4" +description = "Let your Python tests travel through time" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "freezegun-1.5.4-py3-none-any.whl", hash = "sha256:8bdd75c9d790f53d5a173d273064ccd7900984b36635be552befeedb0cd47b20"}, + {file = "freezegun-1.5.4.tar.gz", hash = "sha256:798b9372fdd4d907f33e8b6a58bc64e682d9ffa8d494ce60f780197ee81faed1"}, +] + +[package.dependencies] +python-dateutil = ">=2.7" + +[[package]] +name = "frozenlist" +version = "1.7.0" +description = "A list-like structure which implements collections.abc.MutableSequence" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a"}, + {file = "frozenlist-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716a9973a2cc963160394f701964fe25012600f3d311f60c790400b00e568b61"}, + {file = "frozenlist-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0fd1bad056a3600047fb9462cff4c5322cebc59ebf5d0a3725e0ee78955001d"}, + {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3789ebc19cb811163e70fe2bd354cea097254ce6e707ae42e56f45e31e96cb8e"}, + {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af369aa35ee34f132fcfad5be45fbfcde0e3a5f6a1ec0712857f286b7d20cca9"}, + {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac64b6478722eeb7a3313d494f8342ef3478dff539d17002f849101b212ef97c"}, + {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f89f65d85774f1797239693cef07ad4c97fdd0639544bad9ac4b869782eb1981"}, + {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1073557c941395fdfcfac13eb2456cb8aad89f9de27bae29fabca8e563b12615"}, + {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed8d2fa095aae4bdc7fdd80351009a48d286635edffee66bf865e37a9125c50"}, + {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:24c34bea555fe42d9f928ba0a740c553088500377448febecaa82cc3e88aa1fa"}, + {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:69cac419ac6a6baad202c85aaf467b65ac860ac2e7f2ac1686dc40dbb52f6577"}, + {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:960d67d0611f4c87da7e2ae2eacf7ea81a5be967861e0c63cf205215afbfac59"}, + {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:41be2964bd4b15bf575e5daee5a5ce7ed3115320fb3c2b71fca05582ffa4dc9e"}, + {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:46d84d49e00c9429238a7ce02dc0be8f6d7cd0cd405abd1bebdc991bf27c15bd"}, + {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15900082e886edb37480335d9d518cec978afc69ccbc30bd18610b7c1b22a718"}, + {file = "frozenlist-1.7.0-cp310-cp310-win32.whl", hash = "sha256:400ddd24ab4e55014bba442d917203c73b2846391dd42ca5e38ff52bb18c3c5e"}, + {file = "frozenlist-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:6eb93efb8101ef39d32d50bce242c84bcbddb4f7e9febfa7b524532a239b4464"}, + {file = "frozenlist-1.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa51e147a66b2d74de1e6e2cf5921890de6b0f4820b257465101d7f37b49fb5a"}, + {file = "frozenlist-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b35db7ce1cd71d36ba24f80f0c9e7cff73a28d7a74e91fe83e23d27c7828750"}, + {file = "frozenlist-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34a69a85e34ff37791e94542065c8416c1afbf820b68f720452f636d5fb990cd"}, + {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a646531fa8d82c87fe4bb2e596f23173caec9185bfbca5d583b4ccfb95183e2"}, + {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:79b2ffbba483f4ed36a0f236ccb85fbb16e670c9238313709638167670ba235f"}, + {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a26f205c9ca5829cbf82bb2a84b5c36f7184c4316617d7ef1b271a56720d6b30"}, + {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcacfad3185a623fa11ea0e0634aac7b691aa925d50a440f39b458e41c561d98"}, + {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c1b0fe8fe451b34f12dce46445ddf14bd2a5bcad7e324987194dc8e3a74c86"}, + {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d1a5baeaac6c0798ff6edfaeaa00e0e412d49946c53fae8d4b8e8b3566c4ae"}, + {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7edf5c043c062462f09b6820de9854bf28cc6cc5b6714b383149745e287181a8"}, + {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d50ac7627b3a1bd2dcef6f9da89a772694ec04d9a61b66cf87f7d9446b4a0c31"}, + {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce48b2fece5aeb45265bb7a58259f45027db0abff478e3077e12b05b17fb9da7"}, + {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fe2365ae915a1fafd982c146754e1de6ab3478def8a59c86e1f7242d794f97d5"}, + {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:45a6f2fdbd10e074e8814eb98b05292f27bad7d1883afbe009d96abdcf3bc898"}, + {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:21884e23cffabb157a9dd7e353779077bf5b8f9a58e9b262c6caad2ef5f80a56"}, + {file = "frozenlist-1.7.0-cp311-cp311-win32.whl", hash = "sha256:284d233a8953d7b24f9159b8a3496fc1ddc00f4db99c324bd5fb5f22d8698ea7"}, + {file = "frozenlist-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:387cbfdcde2f2353f19c2f66bbb52406d06ed77519ac7ee21be0232147c2592d"}, + {file = "frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2"}, + {file = "frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb"}, + {file = "frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478"}, + {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8"}, + {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08"}, + {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4"}, + {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b"}, + {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e"}, + {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca"}, + {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df"}, + {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5"}, + {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025"}, + {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01"}, + {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08"}, + {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43"}, + {file = "frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3"}, + {file = "frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a"}, + {file = "frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee"}, + {file = "frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d"}, + {file = "frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43"}, + {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d"}, + {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee"}, + {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb"}, + {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f"}, + {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60"}, + {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00"}, + {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b"}, + {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c"}, + {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949"}, + {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca"}, + {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b"}, + {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e"}, + {file = "frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1"}, + {file = "frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba"}, + {file = "frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d"}, + {file = "frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d"}, + {file = "frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b"}, + {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146"}, + {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74"}, + {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1"}, + {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1"}, + {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384"}, + {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb"}, + {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c"}, + {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65"}, + {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3"}, + {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657"}, + {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104"}, + {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf"}, + {file = "frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81"}, + {file = "frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e"}, + {file = "frozenlist-1.7.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cea3dbd15aea1341ea2de490574a4a37ca080b2ae24e4b4f4b51b9057b4c3630"}, + {file = "frozenlist-1.7.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7d536ee086b23fecc36c2073c371572374ff50ef4db515e4e503925361c24f71"}, + {file = "frozenlist-1.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dfcebf56f703cb2e346315431699f00db126d158455e513bd14089d992101e44"}, + {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:974c5336e61d6e7eb1ea5b929cb645e882aadab0095c5a6974a111e6479f8878"}, + {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c70db4a0ab5ab20878432c40563573229a7ed9241506181bba12f6b7d0dc41cb"}, + {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1137b78384eebaf70560a36b7b229f752fb64d463d38d1304939984d5cb887b6"}, + {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e793a9f01b3e8b5c0bc646fb59140ce0efcc580d22a3468d70766091beb81b35"}, + {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74739ba8e4e38221d2c5c03d90a7e542cb8ad681915f4ca8f68d04f810ee0a87"}, + {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e63344c4e929b1a01e29bc184bbb5fd82954869033765bfe8d65d09e336a677"}, + {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2ea2a7369eb76de2217a842f22087913cdf75f63cf1307b9024ab82dfb525938"}, + {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:836b42f472a0e006e02499cef9352ce8097f33df43baaba3e0a28a964c26c7d2"}, + {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e22b9a99741294b2571667c07d9f8cceec07cb92aae5ccda39ea1b6052ed4319"}, + {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:9a19e85cc503d958abe5218953df722748d87172f71b73cf3c9257a91b999890"}, + {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f22dac33bb3ee8fe3e013aa7b91dc12f60d61d05b7fe32191ffa84c3aafe77bd"}, + {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9ccec739a99e4ccf664ea0775149f2749b8a6418eb5b8384b4dc0a7d15d304cb"}, + {file = "frozenlist-1.7.0-cp39-cp39-win32.whl", hash = "sha256:b3950f11058310008a87757f3eee16a8e1ca97979833239439586857bc25482e"}, + {file = "frozenlist-1.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:43a82fce6769c70f2f5a06248b614a7d268080a9d20f7457ef10ecee5af82b63"}, + {file = "frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e"}, + {file = "frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f"}, +] + +[[package]] +name = "h11" +version = "0.16.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, + {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.16" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<1.0)"] + +[[package]] +name = "httpx" +version = "0.28.1" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, + {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" + +[package.extras] +brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "hypothesis" +version = "6.137.1" +description = "A library for property-based testing" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "hypothesis-6.137.1-py3-none-any.whl", hash = "sha256:7cbda6a98ed4d32aad31a5fc5bff5e119b9275fe2579a7b08863cba313a4b9be"}, + {file = "hypothesis-6.137.1.tar.gz", hash = "sha256:b086e644456da79ad460fdaf8fbf90a41a661e8a4076232dd4ea64cfbc0d0529"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +exceptiongroup = {version = ">=1.0.0", markers = "python_version < \"3.11\""} +sortedcontainers = ">=2.1.0,<3.0.0" + +[package.extras] +all = ["black (>=19.10b0)", "click (>=7.0)", "crosshair-tool (>=0.0.93)", "django (>=4.2)", "dpcontracts (>=0.4)", "hypothesis-crosshair (>=0.0.24)", "lark (>=0.10.1)", "libcst (>=0.3.16)", "numpy (>=1.19.3)", "pandas (>=1.1)", "pytest (>=4.6)", "python-dateutil (>=1.4)", "pytz (>=2014.1)", "redis (>=3.0.0)", "rich (>=9.0.0)", "tzdata (>=2025.2) ; sys_platform == \"win32\" or sys_platform == \"emscripten\"", "watchdog (>=4.0.0)"] +cli = ["black (>=19.10b0)", "click (>=7.0)", "rich (>=9.0.0)"] +codemods = ["libcst (>=0.3.16)"] +crosshair = ["crosshair-tool (>=0.0.93)", "hypothesis-crosshair (>=0.0.24)"] +dateutil = ["python-dateutil (>=1.4)"] +django = ["django (>=4.2)"] +dpcontracts = ["dpcontracts (>=0.4)"] +ghostwriter = ["black (>=19.10b0)"] +lark = ["lark (>=0.10.1)"] +numpy = ["numpy (>=1.19.3)"] +pandas = ["pandas (>=1.1)"] +pytest = ["pytest (>=4.6)"] +pytz = ["pytz (>=2014.1)"] +redis = ["redis (>=3.0.0)"] +watchdog = ["watchdog (>=4.0.0)"] +zoneinfo = ["tzdata (>=2025.2) ; sys_platform == \"win32\" or sys_platform == \"emscripten\""] + +[[package]] +name = "idna" +version = "3.10" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.6" +groups = ["main", "dev"] +files = [ + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "iniconfig" +version = "2.1.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, + {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, +] + +[[package]] +name = "license-expression" +version = "30.4.4" +description = "license-expression is a comprehensive utility library to parse, compare, simplify and normalize license expressions (such as SPDX license expressions) using boolean logic." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "license_expression-30.4.4-py3-none-any.whl", hash = "sha256:421788fdcadb41f049d2dc934ce666626265aeccefddd25e162a26f23bcbf8a4"}, + {file = "license_expression-30.4.4.tar.gz", hash = "sha256:73448f0aacd8d0808895bdc4b2c8e01a8d67646e4188f887375398c761f340fd"}, +] + +[package.dependencies] +"boolean.py" = ">=4.0" + +[package.extras] +dev = ["Sphinx (>=5.0.2)", "doc8 (>=0.11.2)", "pytest (>=7.0.1)", "pytest-xdist (>=2)", "ruff", "sphinx-autobuild", "sphinx-copybutton", "sphinx-reredirects (>=0.1.2)", "sphinx-rtd-dark-mode (>=1.3.0)", "sphinx-rtd-theme (>=1.0.0)", "sphinxcontrib-apidoc (>=0.4.0)", "twine"] + +[[package]] +name = "limits" +version = "5.5.0" +description = "Rate limiting utilities" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "limits-5.5.0-py3-none-any.whl", hash = "sha256:57217d01ffa5114f7e233d1f5e5bdc6fe60c9b24ade387bf4d5e83c5cf929bae"}, + {file = "limits-5.5.0.tar.gz", hash = "sha256:ee269fedb078a904608b264424d9ef4ab10555acc8d090b6fc1db70e913327ea"}, +] + +[package.dependencies] +deprecated = ">=1.2" +packaging = ">=21" +typing_extensions = "*" + +[package.extras] +all = ["coredis (>=3.4.0,<6)", "memcachio (>=0.3)", "motor (>=3,<4)", "pymemcache (>3,<5.0.0)", "pymongo (>4.1,<5)", "redis (>3,!=4.5.2,!=4.5.3,<7.0.0)", "redis (>=4.2.0,!=4.5.2,!=4.5.3)", "valkey (>=6)", "valkey (>=6)"] +async-memcached = ["memcachio (>=0.3)"] +async-mongodb = ["motor (>=3,<4)"] +async-redis = ["coredis (>=3.4.0,<6)"] +async-valkey = ["valkey (>=6)"] +memcached = ["pymemcache (>3,<5.0.0)"] +mongodb = ["pymongo (>4.1,<5)"] +redis = ["redis (>3,!=4.5.2,!=4.5.3,<7.0.0)"] +rediscluster = ["redis (>=4.2.0,!=4.5.2,!=4.5.3)"] +valkey = ["valkey (>=6)"] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +groups = ["main", "dev"] +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "mnemonic" +version = "0.21" +description = "Implementation of Bitcoin BIP-0039" +optional = false +python-versions = ">=3.8.1" +groups = ["main"] +files = [ + {file = "mnemonic-0.21-py3-none-any.whl", hash = "sha256:72dc9de16ec5ef47287237b9b6943da11647a03fe7cf1f139fc3d7c4a7439288"}, + {file = "mnemonic-0.21.tar.gz", hash = "sha256:1fe496356820984f45559b1540c80ff10de448368929b9c60a2b55744cc88acf"}, +] + +[[package]] +name = "msgpack" +version = "1.1.1" +description = "MessagePack serializer" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "msgpack-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:353b6fc0c36fde68b661a12949d7d49f8f51ff5fa019c1e47c87c4ff34b080ed"}, + {file = "msgpack-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:79c408fcf76a958491b4e3b103d1c417044544b68e96d06432a189b43d1215c8"}, + {file = "msgpack-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78426096939c2c7482bf31ef15ca219a9e24460289c00dd0b94411040bb73ad2"}, + {file = "msgpack-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b17ba27727a36cb73aabacaa44b13090feb88a01d012c0f4be70c00f75048b4"}, + {file = "msgpack-1.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a17ac1ea6ec3c7687d70201cfda3b1e8061466f28f686c24f627cae4ea8efd0"}, + {file = "msgpack-1.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:88d1e966c9235c1d4e2afac21ca83933ba59537e2e2727a999bf3f515ca2af26"}, + {file = "msgpack-1.1.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f6d58656842e1b2ddbe07f43f56b10a60f2ba5826164910968f5933e5178af75"}, + {file = "msgpack-1.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:96decdfc4adcbc087f5ea7ebdcfd3dee9a13358cae6e81d54be962efc38f6338"}, + {file = "msgpack-1.1.1-cp310-cp310-win32.whl", hash = "sha256:6640fd979ca9a212e4bcdf6eb74051ade2c690b862b679bfcb60ae46e6dc4bfd"}, + {file = "msgpack-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:8b65b53204fe1bd037c40c4148d00ef918eb2108d24c9aaa20bc31f9810ce0a8"}, + {file = "msgpack-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:71ef05c1726884e44f8b1d1773604ab5d4d17729d8491403a705e649116c9558"}, + {file = "msgpack-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:36043272c6aede309d29d56851f8841ba907a1a3d04435e43e8a19928e243c1d"}, + {file = "msgpack-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a32747b1b39c3ac27d0670122b57e6e57f28eefb725e0b625618d1b59bf9d1e0"}, + {file = "msgpack-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a8b10fdb84a43e50d38057b06901ec9da52baac6983d3f709d8507f3889d43f"}, + {file = "msgpack-1.1.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba0c325c3f485dc54ec298d8b024e134acf07c10d494ffa24373bea729acf704"}, + {file = "msgpack-1.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:88daaf7d146e48ec71212ce21109b66e06a98e5e44dca47d853cbfe171d6c8d2"}, + {file = "msgpack-1.1.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8b55ea20dc59b181d3f47103f113e6f28a5e1c89fd5b67b9140edb442ab67f2"}, + {file = "msgpack-1.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4a28e8072ae9779f20427af07f53bbb8b4aa81151054e882aee333b158da8752"}, + {file = "msgpack-1.1.1-cp311-cp311-win32.whl", hash = "sha256:7da8831f9a0fdb526621ba09a281fadc58ea12701bc709e7b8cbc362feabc295"}, + {file = "msgpack-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:5fd1b58e1431008a57247d6e7cc4faa41c3607e8e7d4aaf81f7c29ea013cb458"}, + {file = "msgpack-1.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ae497b11f4c21558d95de9f64fff7053544f4d1a17731c866143ed6bb4591238"}, + {file = "msgpack-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:33be9ab121df9b6b461ff91baac6f2731f83d9b27ed948c5b9d1978ae28bf157"}, + {file = "msgpack-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f64ae8fe7ffba251fecb8408540c34ee9df1c26674c50c4544d72dbf792e5ce"}, + {file = "msgpack-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a494554874691720ba5891c9b0b39474ba43ffb1aaf32a5dac874effb1619e1a"}, + {file = "msgpack-1.1.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb643284ab0ed26f6957d969fe0dd8bb17beb567beb8998140b5e38a90974f6c"}, + {file = "msgpack-1.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d275a9e3c81b1093c060c3837e580c37f47c51eca031f7b5fb76f7b8470f5f9b"}, + {file = "msgpack-1.1.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4fd6b577e4541676e0cc9ddc1709d25014d3ad9a66caa19962c4f5de30fc09ef"}, + {file = "msgpack-1.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb29aaa613c0a1c40d1af111abf025f1732cab333f96f285d6a93b934738a68a"}, + {file = "msgpack-1.1.1-cp312-cp312-win32.whl", hash = "sha256:870b9a626280c86cff9c576ec0d9cbcc54a1e5ebda9cd26dab12baf41fee218c"}, + {file = "msgpack-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:5692095123007180dca3e788bb4c399cc26626da51629a31d40207cb262e67f4"}, + {file = "msgpack-1.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3765afa6bd4832fc11c3749be4ba4b69a0e8d7b728f78e68120a157a4c5d41f0"}, + {file = "msgpack-1.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8ddb2bcfd1a8b9e431c8d6f4f7db0773084e107730ecf3472f1dfe9ad583f3d9"}, + {file = "msgpack-1.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:196a736f0526a03653d829d7d4c5500a97eea3648aebfd4b6743875f28aa2af8"}, + {file = "msgpack-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d592d06e3cc2f537ceeeb23d38799c6ad83255289bb84c2e5792e5a8dea268a"}, + {file = "msgpack-1.1.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4df2311b0ce24f06ba253fda361f938dfecd7b961576f9be3f3fbd60e87130ac"}, + {file = "msgpack-1.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e4141c5a32b5e37905b5940aacbc59739f036930367d7acce7a64e4dec1f5e0b"}, + {file = "msgpack-1.1.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b1ce7f41670c5a69e1389420436f41385b1aa2504c3b0c30620764b15dded2e7"}, + {file = "msgpack-1.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4147151acabb9caed4e474c3344181e91ff7a388b888f1e19ea04f7e73dc7ad5"}, + {file = "msgpack-1.1.1-cp313-cp313-win32.whl", hash = "sha256:500e85823a27d6d9bba1d057c871b4210c1dd6fb01fbb764e37e4e8847376323"}, + {file = "msgpack-1.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:6d489fba546295983abd142812bda76b57e33d0b9f5d5b71c09a583285506f69"}, + {file = "msgpack-1.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bba1be28247e68994355e028dcd668316db30c1f758d3241a7b903ac78dcd285"}, + {file = "msgpack-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8f93dcddb243159c9e4109c9750ba5b335ab8d48d9522c5308cd05d7e3ce600"}, + {file = "msgpack-1.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fbbc0b906a24038c9958a1ba7ae0918ad35b06cb449d398b76a7d08470b0ed9"}, + {file = "msgpack-1.1.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:61e35a55a546a1690d9d09effaa436c25ae6130573b6ee9829c37ef0f18d5e78"}, + {file = "msgpack-1.1.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:1abfc6e949b352dadf4bce0eb78023212ec5ac42f6abfd469ce91d783c149c2a"}, + {file = "msgpack-1.1.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:996f2609ddf0142daba4cefd767d6db26958aac8439ee41db9cc0db9f4c4c3a6"}, + {file = "msgpack-1.1.1-cp38-cp38-win32.whl", hash = "sha256:4d3237b224b930d58e9d83c81c0dba7aacc20fcc2f89c1e5423aa0529a4cd142"}, + {file = "msgpack-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:da8f41e602574ece93dbbda1fab24650d6bf2a24089f9e9dbb4f5730ec1e58ad"}, + {file = "msgpack-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5be6b6bc52fad84d010cb45433720327ce886009d862f46b26d4d154001994b"}, + {file = "msgpack-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3a89cd8c087ea67e64844287ea52888239cbd2940884eafd2dcd25754fb72232"}, + {file = "msgpack-1.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d75f3807a9900a7d575d8d6674a3a47e9f227e8716256f35bc6f03fc597ffbf"}, + {file = "msgpack-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d182dac0221eb8faef2e6f44701812b467c02674a322c739355c39e94730cdbf"}, + {file = "msgpack-1.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b13fe0fb4aac1aa5320cd693b297fe6fdef0e7bea5518cbc2dd5299f873ae90"}, + {file = "msgpack-1.1.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:435807eeb1bc791ceb3247d13c79868deb22184e1fc4224808750f0d7d1affc1"}, + {file = "msgpack-1.1.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4835d17af722609a45e16037bb1d4d78b7bdf19d6c0128116d178956618c4e88"}, + {file = "msgpack-1.1.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a8ef6e342c137888ebbfb233e02b8fbd689bb5b5fcc59b34711ac47ebd504478"}, + {file = "msgpack-1.1.1-cp39-cp39-win32.whl", hash = "sha256:61abccf9de335d9efd149e2fff97ed5974f2481b3353772e8e2dd3402ba2bd57"}, + {file = "msgpack-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:40eae974c873b2992fd36424a5d9407f93e97656d999f43fca9d29f820899084"}, + {file = "msgpack-1.1.1.tar.gz", hash = "sha256:77b79ce34a2bdab2594f490c8e80dd62a02d650b91a75159a63ec413b8d104cd"}, +] + +[[package]] +name = "multidict" +version = "6.6.3" +description = "multidict implementation" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "multidict-6.6.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a2be5b7b35271f7fff1397204ba6708365e3d773579fe2a30625e16c4b4ce817"}, + {file = "multidict-6.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12f4581d2930840295c461764b9a65732ec01250b46c6b2c510d7ee68872b140"}, + {file = "multidict-6.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dd7793bab517e706c9ed9d7310b06c8672fd0aeee5781bfad612f56b8e0f7d14"}, + {file = "multidict-6.6.3-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:72d8815f2cd3cf3df0f83cac3f3ef801d908b2d90409ae28102e0553af85545a"}, + {file = "multidict-6.6.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:531e331a2ee53543ab32b16334e2deb26f4e6b9b28e41f8e0c87e99a6c8e2d69"}, + {file = "multidict-6.6.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:42ca5aa9329a63be8dc49040f63817d1ac980e02eeddba763a9ae5b4027b9c9c"}, + {file = "multidict-6.6.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:208b9b9757060b9faa6f11ab4bc52846e4f3c2fb8b14d5680c8aac80af3dc751"}, + {file = "multidict-6.6.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:acf6b97bd0884891af6a8b43d0f586ab2fcf8e717cbd47ab4bdddc09e20652d8"}, + {file = "multidict-6.6.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:68e9e12ed00e2089725669bdc88602b0b6f8d23c0c95e52b95f0bc69f7fe9b55"}, + {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:05db2f66c9addb10cfa226e1acb363450fab2ff8a6df73c622fefe2f5af6d4e7"}, + {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0db58da8eafb514db832a1b44f8fa7906fdd102f7d982025f816a93ba45e3dcb"}, + {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:14117a41c8fdb3ee19c743b1c027da0736fdb79584d61a766da53d399b71176c"}, + {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:877443eaaabcd0b74ff32ebeed6f6176c71850feb7d6a1d2db65945256ea535c"}, + {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:70b72e749a4f6e7ed8fb334fa8d8496384840319512746a5f42fa0aec79f4d61"}, + {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:43571f785b86afd02b3855c5ac8e86ec921b760298d6f82ff2a61daf5a35330b"}, + {file = "multidict-6.6.3-cp310-cp310-win32.whl", hash = "sha256:20c5a0c3c13a15fd5ea86c42311859f970070e4e24de5a550e99d7c271d76318"}, + {file = "multidict-6.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:ab0a34a007704c625e25a9116c6770b4d3617a071c8a7c30cd338dfbadfe6485"}, + {file = "multidict-6.6.3-cp310-cp310-win_arm64.whl", hash = "sha256:769841d70ca8bdd140a715746199fc6473414bd02efd678d75681d2d6a8986c5"}, + {file = "multidict-6.6.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:18f4eba0cbac3546b8ae31e0bbc55b02c801ae3cbaf80c247fcdd89b456ff58c"}, + {file = "multidict-6.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef43b5dd842382329e4797c46f10748d8c2b6e0614f46b4afe4aee9ac33159df"}, + {file = "multidict-6.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf9bd1fd5eec01494e0f2e8e446a74a85d5e49afb63d75a9934e4a5423dba21d"}, + {file = "multidict-6.6.3-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:5bd8d6f793a787153956cd35e24f60485bf0651c238e207b9a54f7458b16d539"}, + {file = "multidict-6.6.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1bf99b4daf908c73856bd87ee0a2499c3c9a3d19bb04b9c6025e66af3fd07462"}, + {file = "multidict-6.6.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b9e59946b49dafaf990fd9c17ceafa62976e8471a14952163d10a7a630413a9"}, + {file = "multidict-6.6.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e2db616467070d0533832d204c54eea6836a5e628f2cb1e6dfd8cd6ba7277cb7"}, + {file = "multidict-6.6.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7394888236621f61dcdd25189b2768ae5cc280f041029a5bcf1122ac63df79f9"}, + {file = "multidict-6.6.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f114d8478733ca7388e7c7e0ab34b72547476b97009d643644ac33d4d3fe1821"}, + {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cdf22e4db76d323bcdc733514bf732e9fb349707c98d341d40ebcc6e9318ef3d"}, + {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e995a34c3d44ab511bfc11aa26869b9d66c2d8c799fa0e74b28a473a692532d6"}, + {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:766a4a5996f54361d8d5a9050140aa5362fe48ce51c755a50c0bc3706460c430"}, + {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3893a0d7d28a7fe6ca7a1f760593bc13038d1d35daf52199d431b61d2660602b"}, + {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:934796c81ea996e61914ba58064920d6cad5d99140ac3167901eb932150e2e56"}, + {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9ed948328aec2072bc00f05d961ceadfd3e9bfc2966c1319aeaf7b7c21219183"}, + {file = "multidict-6.6.3-cp311-cp311-win32.whl", hash = "sha256:9f5b28c074c76afc3e4c610c488e3493976fe0e596dd3db6c8ddfbb0134dcac5"}, + {file = "multidict-6.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc7f6fbc61b1c16050a389c630da0b32fc6d4a3d191394ab78972bf5edc568c2"}, + {file = "multidict-6.6.3-cp311-cp311-win_arm64.whl", hash = "sha256:d4e47d8faffaae822fb5cba20937c048d4f734f43572e7079298a6c39fb172cb"}, + {file = "multidict-6.6.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:056bebbeda16b2e38642d75e9e5310c484b7c24e3841dc0fb943206a72ec89d6"}, + {file = "multidict-6.6.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e5f481cccb3c5c5e5de5d00b5141dc589c1047e60d07e85bbd7dea3d4580d63f"}, + {file = "multidict-6.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:10bea2ee839a759ee368b5a6e47787f399b41e70cf0c20d90dfaf4158dfb4e55"}, + {file = "multidict-6.6.3-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:2334cfb0fa9549d6ce2c21af2bfbcd3ac4ec3646b1b1581c88e3e2b1779ec92b"}, + {file = "multidict-6.6.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8fee016722550a2276ca2cb5bb624480e0ed2bd49125b2b73b7010b9090e888"}, + {file = "multidict-6.6.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5511cb35f5c50a2db21047c875eb42f308c5583edf96bd8ebf7d770a9d68f6d"}, + {file = "multidict-6.6.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:712b348f7f449948e0a6c4564a21c7db965af900973a67db432d724619b3c680"}, + {file = "multidict-6.6.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e4e15d2138ee2694e038e33b7c3da70e6b0ad8868b9f8094a72e1414aeda9c1a"}, + {file = "multidict-6.6.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8df25594989aebff8a130f7899fa03cbfcc5d2b5f4a461cf2518236fe6f15961"}, + {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:159ca68bfd284a8860f8d8112cf0521113bffd9c17568579e4d13d1f1dc76b65"}, + {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e098c17856a8c9ade81b4810888c5ad1914099657226283cab3062c0540b0643"}, + {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:67c92ed673049dec52d7ed39f8cf9ebbadf5032c774058b4406d18c8f8fe7063"}, + {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:bd0578596e3a835ef451784053cfd327d607fc39ea1a14812139339a18a0dbc3"}, + {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:346055630a2df2115cd23ae271910b4cae40f4e336773550dca4889b12916e75"}, + {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:555ff55a359302b79de97e0468e9ee80637b0de1fce77721639f7cd9440b3a10"}, + {file = "multidict-6.6.3-cp312-cp312-win32.whl", hash = "sha256:73ab034fb8d58ff85c2bcbadc470efc3fafeea8affcf8722855fb94557f14cc5"}, + {file = "multidict-6.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:04cbcce84f63b9af41bad04a54d4cc4e60e90c35b9e6ccb130be2d75b71f8c17"}, + {file = "multidict-6.6.3-cp312-cp312-win_arm64.whl", hash = "sha256:0f1130b896ecb52d2a1e615260f3ea2af55fa7dc3d7c3003ba0c3121a759b18b"}, + {file = "multidict-6.6.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:540d3c06d48507357a7d57721e5094b4f7093399a0106c211f33540fdc374d55"}, + {file = "multidict-6.6.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9c19cea2a690f04247d43f366d03e4eb110a0dc4cd1bbeee4d445435428ed35b"}, + {file = "multidict-6.6.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7af039820cfd00effec86bda5d8debef711a3e86a1d3772e85bea0f243a4bd65"}, + {file = "multidict-6.6.3-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:500b84f51654fdc3944e936f2922114349bf8fdcac77c3092b03449f0e5bc2b3"}, + {file = "multidict-6.6.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3fc723ab8a5c5ed6c50418e9bfcd8e6dceba6c271cee6728a10a4ed8561520c"}, + {file = "multidict-6.6.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:94c47ea3ade005b5976789baaed66d4de4480d0a0bf31cef6edaa41c1e7b56a6"}, + {file = "multidict-6.6.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dbc7cf464cc6d67e83e136c9f55726da3a30176f020a36ead246eceed87f1cd8"}, + {file = "multidict-6.6.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:900eb9f9da25ada070f8ee4a23f884e0ee66fe4e1a38c3af644256a508ad81ca"}, + {file = "multidict-6.6.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c6df517cf177da5d47ab15407143a89cd1a23f8b335f3a28d57e8b0a3dbb884"}, + {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4ef421045f13879e21c994b36e728d8e7d126c91a64b9185810ab51d474f27e7"}, + {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6c1e61bb4f80895c081790b6b09fa49e13566df8fbff817da3f85b3a8192e36b"}, + {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e5e8523bb12d7623cd8300dbd91b9e439a46a028cd078ca695eb66ba31adee3c"}, + {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:ef58340cc896219e4e653dade08fea5c55c6df41bcc68122e3be3e9d873d9a7b"}, + {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc9dc435ec8699e7b602b94fe0cd4703e69273a01cbc34409af29e7820f777f1"}, + {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9e864486ef4ab07db5e9cb997bad2b681514158d6954dd1958dfb163b83d53e6"}, + {file = "multidict-6.6.3-cp313-cp313-win32.whl", hash = "sha256:5633a82fba8e841bc5c5c06b16e21529573cd654f67fd833650a215520a6210e"}, + {file = "multidict-6.6.3-cp313-cp313-win_amd64.whl", hash = "sha256:e93089c1570a4ad54c3714a12c2cef549dc9d58e97bcded193d928649cab78e9"}, + {file = "multidict-6.6.3-cp313-cp313-win_arm64.whl", hash = "sha256:c60b401f192e79caec61f166da9c924e9f8bc65548d4246842df91651e83d600"}, + {file = "multidict-6.6.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:02fd8f32d403a6ff13864b0851f1f523d4c988051eea0471d4f1fd8010f11134"}, + {file = "multidict-6.6.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f3aa090106b1543f3f87b2041eef3c156c8da2aed90c63a2fbed62d875c49c37"}, + {file = "multidict-6.6.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e924fb978615a5e33ff644cc42e6aa241effcf4f3322c09d4f8cebde95aff5f8"}, + {file = "multidict-6.6.3-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:b9fe5a0e57c6dbd0e2ce81ca66272282c32cd11d31658ee9553849d91289e1c1"}, + {file = "multidict-6.6.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b24576f208793ebae00280c59927c3b7c2a3b1655e443a25f753c4611bc1c373"}, + {file = "multidict-6.6.3-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:135631cb6c58eac37d7ac0df380294fecdc026b28837fa07c02e459c7fb9c54e"}, + {file = "multidict-6.6.3-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:274d416b0df887aef98f19f21578653982cfb8a05b4e187d4a17103322eeaf8f"}, + {file = "multidict-6.6.3-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e252017a817fad7ce05cafbe5711ed40faeb580e63b16755a3a24e66fa1d87c0"}, + {file = "multidict-6.6.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e4cc8d848cd4fe1cdee28c13ea79ab0ed37fc2e89dd77bac86a2e7959a8c3bc"}, + {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9e236a7094b9c4c1b7585f6b9cca34b9d833cf079f7e4c49e6a4a6ec9bfdc68f"}, + {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:e0cb0ab69915c55627c933f0b555a943d98ba71b4d1c57bc0d0a66e2567c7471"}, + {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:81ef2f64593aba09c5212a3d0f8c906a0d38d710a011f2f42759704d4557d3f2"}, + {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:b9cbc60010de3562545fa198bfc6d3825df430ea96d2cc509c39bd71e2e7d648"}, + {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:70d974eaaa37211390cd02ef93b7e938de564bbffa866f0b08d07e5e65da783d"}, + {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3713303e4a6663c6d01d648a68f2848701001f3390a030edaaf3fc949c90bf7c"}, + {file = "multidict-6.6.3-cp313-cp313t-win32.whl", hash = "sha256:639ecc9fe7cd73f2495f62c213e964843826f44505a3e5d82805aa85cac6f89e"}, + {file = "multidict-6.6.3-cp313-cp313t-win_amd64.whl", hash = "sha256:9f97e181f344a0ef3881b573d31de8542cc0dbc559ec68c8f8b5ce2c2e91646d"}, + {file = "multidict-6.6.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ce8b7693da41a3c4fde5871c738a81490cea5496c671d74374c8ab889e1834fb"}, + {file = "multidict-6.6.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c8161b5a7778d3137ea2ee7ae8a08cce0010de3b00ac671c5ebddeaa17cefd22"}, + {file = "multidict-6.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1328201ee930f069961ae707d59c6627ac92e351ed5b92397cf534d1336ce557"}, + {file = "multidict-6.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b1db4d2093d6b235de76932febf9d50766cf49a5692277b2c28a501c9637f616"}, + {file = "multidict-6.6.3-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53becb01dd8ebd19d1724bebe369cfa87e4e7f29abbbe5c14c98ce4c383e16cd"}, + {file = "multidict-6.6.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41bb9d1d4c303886e2d85bade86e59885112a7f4277af5ad47ab919a2251f306"}, + {file = "multidict-6.6.3-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:775b464d31dac90f23192af9c291dc9f423101857e33e9ebf0020a10bfcf4144"}, + {file = "multidict-6.6.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d04d01f0a913202205a598246cf77826fe3baa5a63e9f6ccf1ab0601cf56eca0"}, + {file = "multidict-6.6.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d25594d3b38a2e6cabfdcafef339f754ca6e81fbbdb6650ad773ea9775af35ab"}, + {file = "multidict-6.6.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:35712f1748d409e0707b165bf49f9f17f9e28ae85470c41615778f8d4f7d9609"}, + {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1c8082e5814b662de8589d6a06c17e77940d5539080cbab9fe6794b5241b76d9"}, + {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:61af8a4b771f1d4d000b3168c12c3120ccf7284502a94aa58c68a81f5afac090"}, + {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:448e4a9afccbf297577f2eaa586f07067441e7b63c8362a3540ba5a38dc0f14a"}, + {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:233ad16999afc2bbd3e534ad8dbe685ef8ee49a37dbc2cdc9514e57b6d589ced"}, + {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:bb933c891cd4da6bdcc9733d048e994e22e1883287ff7540c2a0f3b117605092"}, + {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:37b09ca60998e87734699e88c2363abfd457ed18cfbf88e4009a4e83788e63ed"}, + {file = "multidict-6.6.3-cp39-cp39-win32.whl", hash = "sha256:f54cb79d26d0cd420637d184af38f0668558f3c4bbe22ab7ad830e67249f2e0b"}, + {file = "multidict-6.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:295adc9c0551e5d5214b45cf29ca23dbc28c2d197a9c30d51aed9e037cb7c578"}, + {file = "multidict-6.6.3-cp39-cp39-win_arm64.whl", hash = "sha256:15332783596f227db50fb261c2c251a58ac3873c457f3a550a95d5c0aa3c770d"}, + {file = "multidict-6.6.3-py3-none-any.whl", hash = "sha256:8db10f29c7541fc5da4defd8cd697e1ca429db743fa716325f236079b96f775a"}, + {file = "multidict-6.6.3.tar.gz", hash = "sha256:798a9eb12dab0a6c2e29c1de6f3468af5cb2da6053a20dfa3344907eed0937cc"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, + {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, +] + +[[package]] +name = "nostr-sdk" +version = "0.43.0" +description = "Nostr protocol implementation, Relay, RelayPool, high-level client library, NWC client and more." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "nostr_sdk-0.43.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1eff16fac045598472807bee311f3002b0c771beb65e4d8f8e35643db549e9de"}, + {file = "nostr_sdk-0.43.0-cp39-abi3-macosx_11_0_x86_64.whl", hash = "sha256:9434a29a0b6251256f00d7d5040e99678ecedce69c4e1ce43c9303cfd615c53e"}, + {file = "nostr_sdk-0.43.0-cp39-abi3-manylinux_2_17_aarch64.whl", hash = "sha256:dd1af754e8a034d4bb3480d16c8960efe24331a3263886b30b3fec61b8ae5439"}, + {file = "nostr_sdk-0.43.0-cp39-abi3-manylinux_2_17_armv7l.whl", hash = "sha256:b2fbcda409fd1e90ad5a1b59b2b22e61c136a93e1366cc5474e2b1278b692a81"}, + {file = "nostr_sdk-0.43.0-cp39-abi3-manylinux_2_17_i686.whl", hash = "sha256:379566a5b1e742751a9f220636e37d48ba298009a7931086200917315ec02cd9"}, + {file = "nostr_sdk-0.43.0-cp39-abi3-manylinux_2_17_x86_64.whl", hash = "sha256:f0cc358274462d66f81464b5deca6c85ee6837ea54474bcc09fbc09fec522d66"}, + {file = "nostr_sdk-0.43.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:910f025b280866199539ccbcc5ec68354b12e939f15340bf532db9c18257ca22"}, + {file = "nostr_sdk-0.43.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:a25887e6e5936a6ece76f0aae3ba402689b021b3c496736c8803aabc23195483"}, + {file = "nostr_sdk-0.43.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:7dd2af2ce071e5f52cf48aaf61630b15a1690e0294913b2f45eff0dd03510d9b"}, + {file = "nostr_sdk-0.43.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:c2f7ad6a983e6fe325e276c6e2be07f1a4424e9ac09f61fce792fceb5f92613e"}, + {file = "nostr_sdk-0.43.0-cp39-abi3-win32.whl", hash = "sha256:da45c976f170a3367b9d1764fd40cf0c6915c9ba36c2c18048cca8577aef10bc"}, + {file = "nostr_sdk-0.43.0-cp39-abi3-win_amd64.whl", hash = "sha256:6e9670d0c83e90e337a67cd0f60cee626f9f49b9e941016083c4c2b7e2e7c11b"}, + {file = "nostr_sdk-0.43.0-cp39-abi3-win_arm64.whl", hash = "sha256:f97a756ed3a90ee903560183505f6c35653c1ace4894525d2944d84c1c685718"}, +] + +[[package]] +name = "orjson" +version = "3.11.1" +description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "orjson-3.11.1-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:92d771c492b64119456afb50f2dff3e03a2db8b5af0eba32c5932d306f970532"}, + {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0085ef83a4141c2ed23bfec5fecbfdb1e95dd42fc8e8c76057bdeeec1608ea65"}, + {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5caf7f13f2e1b4e137060aed892d4541d07dabc3f29e6d891e2383c7ed483440"}, + {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f716bcc166524eddfcf9f13f8209ac19a7f27b05cf591e883419079d98c8c99d"}, + {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:507d6012fab05465d8bf21f5d7f4635ba4b6d60132874e349beff12fb51af7fe"}, + {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1545083b0931f754c80fd2422a73d83bea7a6d1b6de104a5f2c8dd3d64c291e"}, + {file = "orjson-3.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e217ce3bad76351e1eb29ebe5ca630326f45cd2141f62620107a229909501a3"}, + {file = "orjson-3.11.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06ef26e009304bda4df42e4afe518994cde6f89b4b04c0ff24021064f83f4fbb"}, + {file = "orjson-3.11.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ba49683b87bea3ae1489a88e766e767d4f423a669a61270b6d6a7ead1c33bd65"}, + {file = "orjson-3.11.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5072488fcc5cbcda2ece966d248e43ea1d222e19dd4c56d3f82747777f24d864"}, + {file = "orjson-3.11.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f58ae2bcd119226fe4aa934b5880fe57b8e97b69e51d5d91c88a89477a307016"}, + {file = "orjson-3.11.1-cp310-cp310-win32.whl", hash = "sha256:6723be919c07906781b9c63cc52dc7d2fb101336c99dd7e85d3531d73fb493f7"}, + {file = "orjson-3.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:5fd44d69ddfdfb4e8d0d83f09d27a4db34930fba153fbf79f8d4ae8b47914e04"}, + {file = "orjson-3.11.1-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:15e2a57ce3b57c1a36acffcc02e823afefceee0a532180c2568c62213c98e3ef"}, + {file = "orjson-3.11.1-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:17040a83ecaa130474af05bbb59a13cfeb2157d76385556041f945da936b1afd"}, + {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a68f23f09e5626cc0867a96cf618f68b91acb4753d33a80bf16111fd7f9928c"}, + {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47e07528bb6ccbd6e32a55e330979048b59bfc5518b47c89bc7ab9e3de15174a"}, + {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3807cce72bf40a9d251d689cbec28d2efd27e0f6673709f948f971afd52cb09"}, + {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b2dc7e88da4ca201c940f5e6127998d9e89aa64264292334dad62854bc7fc27"}, + {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3091dad33ac9e67c0a550cfff8ad5be156e2614d6f5d2a9247df0627751a1495"}, + {file = "orjson-3.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ed0fce2307843b79a0c83de49f65b86197f1e2310de07af9db2a1a77a61ce4c"}, + {file = "orjson-3.11.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5a31e84782a18c30abd56774c0cfa7b9884589f4d37d9acabfa0504dad59bb9d"}, + {file = "orjson-3.11.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:26b6c821abf1ae515fbb8e140a2406c9f9004f3e52acb780b3dee9bfffddbd84"}, + {file = "orjson-3.11.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f857b3d134b36a8436f1e24dcb525b6b945108b30746c1b0b556200b5cb76d39"}, + {file = "orjson-3.11.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df146f2a14116ce80f7da669785fcb411406d8e80136558b0ecda4c924b9ac55"}, + {file = "orjson-3.11.1-cp311-cp311-win32.whl", hash = "sha256:d777c57c1f86855fe5492b973f1012be776e0398571f7cc3970e9a58ecf4dc17"}, + {file = "orjson-3.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:e9a5fd589951f02ec2fcb8d69339258bbf74b41b104c556e6d4420ea5e059313"}, + {file = "orjson-3.11.1-cp311-cp311-win_arm64.whl", hash = "sha256:4cddbe41ee04fddad35d75b9cf3e3736ad0b80588280766156b94783167777af"}, + {file = "orjson-3.11.1-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2b7c8be96db3a977367250c6367793a3c5851a6ca4263f92f0b48d00702f9910"}, + {file = "orjson-3.11.1-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:72e18088f567bd4a45db5e3196677d9ed1605e356e500c8e32dd6e303167a13d"}, + {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d346e2ae1ce17888f7040b65a5a4a0c9734cb20ffbd228728661e020b4c8b3a5"}, + {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4bda5426ebb02ceb806a7d7ec9ba9ee5e0c93fca62375151a7b1c00bc634d06b"}, + {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10506cebe908542c4f024861102673db534fd2e03eb9b95b30d94438fa220abf"}, + {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45202ee3f5494644e064c41abd1320497fb92fd31fc73af708708af664ac3b56"}, + {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5adaf01b92e0402a9ac5c3ebe04effe2bbb115f0914a0a53d34ea239a746289"}, + {file = "orjson-3.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6162a1a757a1f1f4a94bc6ffac834a3602e04ad5db022dd8395a54ed9dd51c81"}, + {file = "orjson-3.11.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:78404206977c9f946613d3f916727c189d43193e708d760ea5d4b2087d6b0968"}, + {file = "orjson-3.11.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:db48f8e81072e26df6cdb0e9fff808c28597c6ac20a13d595756cf9ba1fed48a"}, + {file = "orjson-3.11.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0c1e394e67ced6bb16fea7054d99fbdd99a539cf4d446d40378d4c06e0a8548d"}, + {file = "orjson-3.11.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e7a840752c93d4eecd1378e9bb465c3703e127b58f675cd5c620f361b6cf57a4"}, + {file = "orjson-3.11.1-cp312-cp312-win32.whl", hash = "sha256:4537b0e09f45d2b74cb69c7f39ca1e62c24c0488d6bf01cd24673c74cd9596bf"}, + {file = "orjson-3.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:dbee6b050062540ae404530cacec1bf25e56e8d87d8d9b610b935afeb6725cae"}, + {file = "orjson-3.11.1-cp312-cp312-win_arm64.whl", hash = "sha256:f55e557d4248322d87c4673e085c7634039ff04b47bfc823b87149ae12bef60d"}, + {file = "orjson-3.11.1-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:53cfefe4af059e65aabe9683f76b9c88bf34b4341a77d329227c2424e0e59b0e"}, + {file = "orjson-3.11.1-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:93d5abed5a6f9e1b6f9b5bf6ed4423c11932b5447c2f7281d3b64e0f26c6d064"}, + {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbf06642f3db2966df504944cdd0eb68ca2717f0353bb20b20acd78109374a6"}, + {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dddf4e78747fa7f2188273f84562017a3c4f0824485b78372513c1681ea7a894"}, + {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa3fe8653c9f57f0e16f008e43626485b6723b84b2f741f54d1258095b655912"}, + {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6334d2382aff975a61f6f4d1c3daf39368b887c7de08f7c16c58f485dcf7adb2"}, + {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a3d0855b643f259ee0cb76fe3df4c04483354409a520a902b067c674842eb6b8"}, + {file = "orjson-3.11.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0eacdfeefd0a79987926476eb16e0245546bedeb8febbbbcf4b653e79257a8e4"}, + {file = "orjson-3.11.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0ed07faf9e4873518c60480325dcbc16d17c59a165532cccfb409b4cdbaeff24"}, + {file = "orjson-3.11.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d6d308dd578ae3658f62bb9eba54801533225823cd3248c902be1ebc79b5e014"}, + {file = "orjson-3.11.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c4aa13ca959ba6b15c0a98d3d204b850f9dc36c08c9ce422ffb024eb30d6e058"}, + {file = "orjson-3.11.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:be3d0653322abc9b68e5bcdaee6cfd58fcbe9973740ab222b87f4d687232ab1f"}, + {file = "orjson-3.11.1-cp313-cp313-win32.whl", hash = "sha256:4dd34e7e2518de8d7834268846f8cab7204364f427c56fb2251e098da86f5092"}, + {file = "orjson-3.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:d6895d32032b6362540e6d0694b19130bb4f2ad04694002dce7d8af588ca5f77"}, + {file = "orjson-3.11.1-cp313-cp313-win_arm64.whl", hash = "sha256:bb7c36d5d3570fcbb01d24fa447a21a7fe5a41141fd88e78f7994053cc4e28f4"}, + {file = "orjson-3.11.1-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7b71ef394327b3d0b39f6ea7ade2ecda2731a56c6a7cbf0d6a7301203b92a89b"}, + {file = "orjson-3.11.1-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:77c0fe28ed659b62273995244ae2aa430e432c71f86e4573ab16caa2f2e3ca5e"}, + {file = "orjson-3.11.1-cp314-cp314-manylinux_2_34_aarch64.whl", hash = "sha256:1495692f1f1ba2467df429343388a0ed259382835922e124c0cfdd56b3d1f727"}, + {file = "orjson-3.11.1-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:08c6a762fca63ca4dc04f66c48ea5d2428db55839fec996890e1bfaf057b658c"}, + {file = "orjson-3.11.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e26794fe3976810b2c01fda29bd9ac7c91a3c1284b29cc9a383989f7b614037"}, + {file = "orjson-3.11.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4b4b4f8f0b1d3ef8dc73e55363a0ffe012a42f4e2f1a140bf559698dca39b3fa"}, + {file = "orjson-3.11.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:848be553ea35aa89bfefbed2e27c8a41244c862956ab8ba00dc0b27e84fd58de"}, + {file = "orjson-3.11.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c964c29711a4b1df52f8d9966f015402a6cf87753a406c1c4405c407dd66fd45"}, + {file = "orjson-3.11.1-cp314-cp314-win32.whl", hash = "sha256:33aada2e6b6bc9c540d396528b91e666cedb383740fee6e6a917f561b390ecb1"}, + {file = "orjson-3.11.1-cp314-cp314-win_amd64.whl", hash = "sha256:68e10fd804e44e36188b9952543e3fa22f5aa8394da1b5283ca2b423735c06e8"}, + {file = "orjson-3.11.1-cp314-cp314-win_arm64.whl", hash = "sha256:f3cf6c07f8b32127d836be8e1c55d4f34843f7df346536da768e9f73f22078a1"}, + {file = "orjson-3.11.1-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3d593a9e0bccf2c7401ae53625b519a7ad7aa555b1c82c0042b322762dc8af4e"}, + {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0baad413c498fc1eef568504f11ea46bc71f94b845c075e437da1e2b85b4fb86"}, + {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:22cf17ae1dae3f9b5f37bfcdba002ed22c98bbdb70306e42dc18d8cc9b50399a"}, + {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e855c1e97208133ce88b3ef6663c9a82ddf1d09390cd0856a1638deee0390c3c"}, + {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5861c5f7acff10599132854c70ab10abf72aebf7c627ae13575e5f20b1ab8fe"}, + {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1e6415c5b5ff3a616a6dafad7b6ec303a9fc625e9313c8e1268fb1370a63dcb"}, + {file = "orjson-3.11.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:912579642f5d7a4a84d93c5eed8daf0aa34e1f2d3f4dc6571a8e418703f5701e"}, + {file = "orjson-3.11.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2092e1d3b33f64e129ff8271642afddc43763c81f2c30823b4a4a4a5f2ea5b55"}, + {file = "orjson-3.11.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:b8ac64caba1add2c04e9cd4782d4d0c4d6c554b7a3369bdec1eed7854c98db7b"}, + {file = "orjson-3.11.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:23196b826ebc85c43f8e27bee0ab33c5fb13a29ea47fb4fcd6ebb1e660eb0252"}, + {file = "orjson-3.11.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f2d3364cfad43003f1e3d564a069c8866237cca30f9c914b26ed2740b596ed00"}, + {file = "orjson-3.11.1-cp39-cp39-win32.whl", hash = "sha256:20b0dca94ea4ebe4628330de50975b35817a3f52954c1efb6d5d0498a3bbe581"}, + {file = "orjson-3.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:200c3ad7ed8b5d31d49143265dfebd33420c4b61934ead16833b5cd2c3d241be"}, + {file = "orjson-3.11.1.tar.gz", hash = "sha256:48d82770a5fd88778063604c566f9c7c71820270c9cc9338d25147cbf34afd96"}, +] + +[[package]] +name = "packageurl-python" +version = "0.17.5" +description = "A purl aka. Package URL parser and builder" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "packageurl_python-0.17.5-py3-none-any.whl", hash = "sha256:f0e55452ab37b5c192c443de1458e3f3b4d8ac27f747df6e8c48adeab081d321"}, + {file = "packageurl_python-0.17.5.tar.gz", hash = "sha256:a7be3f3ba70d705f738ace9bf6124f31920245a49fa69d4b416da7037dd2de61"}, +] + +[package.extras] +build = ["setuptools", "wheel"] +lint = ["black", "isort", "mypy"] +sqlalchemy = ["sqlalchemy (>=2.0.0)"] +test = ["pytest"] + +[[package]] +name = "packaging" +version = "25.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "pgpy" +version = "0.6.0" +description = "Pretty Good Privacy for Python" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "PGPy-0.6.0.tar.gz", hash = "sha256:279c2e353f4c3a319f00bd9bd582456e420f8a3ac6de2b4e9731444746828383"}, +] + +[package.dependencies] +cryptography = ">=3.3.2" +pyasn1 = "*" + +[[package]] +name = "pillow" +version = "10.4.0" +description = "Python Imaging Library (Fork)" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"}, + {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"}, + {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"}, + {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"}, + {file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"}, + {file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"}, + {file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"}, + {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"}, + {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"}, + {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"}, + {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"}, + {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"}, + {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"}, + {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"}, + {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"}, + {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"}, + {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"}, + {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"}, + {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"}, + {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"}, + {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"}, + {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"}, + {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"}, + {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"}, + {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"}, + {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"}, + {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"}, + {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"}, + {file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736"}, + {file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd"}, + {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84"}, + {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0"}, + {file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e"}, + {file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab"}, + {file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d"}, + {file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c"}, + {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1"}, + {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df"}, + {file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef"}, + {file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5"}, + {file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3"}, + {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] +fpx = ["olefile"] +mic = ["olefile"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +typing = ["typing-extensions ; python_version < \"3.10\""] +xmp = ["defusedxml"] + +[[package]] +name = "pip" +version = "25.2" +description = "The PyPA recommended tool for installing Python packages." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pip-25.2-py3-none-any.whl", hash = "sha256:6d67a2b4e7f14d8b31b8b52648866fa717f45a1eb70e83002f4331d07e953717"}, + {file = "pip-25.2.tar.gz", hash = "sha256:578283f006390f85bb6282dffb876454593d637f5d1be494b5202ce4877e71f2"}, +] + +[[package]] +name = "pip-api" +version = "0.0.34" +description = "An unofficial, importable pip API" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pip_api-0.0.34-py3-none-any.whl", hash = "sha256:8b2d7d7c37f2447373aa2cf8b1f60a2f2b27a84e1e9e0294a3f6ef10eb3ba6bb"}, + {file = "pip_api-0.0.34.tar.gz", hash = "sha256:9b75e958f14c5a2614bae415f2adf7eeb54d50a2cfbe7e24fd4826471bac3625"}, +] + +[package.dependencies] +pip = "*" + +[[package]] +name = "pip-audit" +version = "2.9.0" +description = "A tool for scanning Python environments for known vulnerabilities" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pip_audit-2.9.0-py3-none-any.whl", hash = "sha256:348b16e60895749a0839875d7cc27ebd692e1584ebe5d5cb145941c8e25a80bd"}, + {file = "pip_audit-2.9.0.tar.gz", hash = "sha256:0b998410b58339d7a231e5aa004326a294e4c7c6295289cdc9d5e1ef07b1f44d"}, +] + +[package.dependencies] +CacheControl = {version = ">=0.13.0", extras = ["filecache"]} +cyclonedx-python-lib = ">=5,<10" +packaging = ">=23.0.0" +pip-api = ">=0.0.28" +pip-requirements-parser = ">=32.0.0" +platformdirs = ">=4.2.0" +requests = ">=2.31.0" +rich = ">=12.4" +toml = ">=0.10" + +[package.extras] +dev = ["build", "pip-audit[doc,lint,test]"] +doc = ["pdoc"] +lint = ["interrogate (>=1.6,<2.0)", "mypy", "ruff (>=0.9,<1.0)", "types-requests", "types-toml"] +test = ["coverage[toml] (>=7.0,!=7.3.3,<8.0)", "pretend", "pytest", "pytest-cov"] + +[[package]] +name = "pip-requirements-parser" +version = "32.0.1" +description = "pip requirements parser - a mostly correct pip requirements parsing library because it uses pip's own code." +optional = false +python-versions = ">=3.6.0" +groups = ["dev"] +files = [ + {file = "pip-requirements-parser-32.0.1.tar.gz", hash = "sha256:b4fa3a7a0be38243123cf9d1f3518da10c51bdb165a2b2985566247f9155a7d3"}, + {file = "pip_requirements_parser-32.0.1-py3-none-any.whl", hash = "sha256:4659bc2a667783e7a15d190f6fccf8b2486685b6dba4c19c3876314769c57526"}, +] + +[package.dependencies] +packaging = "*" +pyparsing = "*" + +[package.extras] +docs = ["Sphinx (>=3.3.1)", "doc8 (>=0.8.1)", "sphinx-rtd-theme (>=0.5.0)"] +testing = ["aboutcode-toolkit (>=6.0.0)", "black", "pytest (>=6,!=7.0.0)", "pytest-xdist (>=2)"] + +[[package]] +name = "platformdirs" +version = "4.3.8" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4"}, + {file = "platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.14.1)"] + +[[package]] +name = "pluggy" +version = "1.6.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["coverage", "pytest", "pytest-benchmark"] + +[[package]] +name = "portalocker" +version = "3.2.0" +description = "Wraps the portalocker recipe for easy usage" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "portalocker-3.2.0-py3-none-any.whl", hash = "sha256:3cdc5f565312224bc570c49337bd21428bba0ef363bbcf58b9ef4a9f11779968"}, + {file = "portalocker-3.2.0.tar.gz", hash = "sha256:1f3002956a54a8c3730586c5c77bf18fae4149e07eaf1c29fc3faf4d5a3f89ac"}, +] + +[package.dependencies] +pywin32 = {version = ">=226", markers = "platform_system == \"Windows\""} + +[package.extras] +docs = ["portalocker[tests]"] +redis = ["redis"] +tests = ["coverage-conditional-plugin (>=0.9.0)", "portalocker[redis]", "pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "pytest-rerunfailures (>=15.0)", "pytest-timeout (>=2.1.0)", "sphinx (>=6.0.0)", "types-pywin32 (>=310.0.0.20250429)", "types-redis"] + +[[package]] +name = "propcache" +version = "0.3.2" +description = "Accelerated property cache" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770"}, + {file = "propcache-0.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3"}, + {file = "propcache-0.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3def3da3ac3ce41562d85db655d18ebac740cb3fa4367f11a52b3da9d03a5cc3"}, + {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bec58347a5a6cebf239daba9bda37dffec5b8d2ce004d9fe4edef3d2815137e"}, + {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55ffda449a507e9fbd4aca1a7d9aa6753b07d6166140e5a18d2ac9bc49eac220"}, + {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a67fb39229a8a8491dd42f864e5e263155e729c2e7ff723d6e25f596b1e8cb"}, + {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da1cf97b92b51253d5b68cf5a2b9e0dafca095e36b7f2da335e27dc6172a614"}, + {file = "propcache-0.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f559e127134b07425134b4065be45b166183fdcb433cb6c24c8e4149056ad50"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aff2e4e06435d61f11a428360a932138d0ec288b0a31dd9bd78d200bd4a2b339"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4927842833830942a5d0a56e6f4839bc484785b8e1ce8d287359794818633ba0"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6107ddd08b02654a30fb8ad7a132021759d750a82578b94cd55ee2772b6ebea2"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:70bd8b9cd6b519e12859c99f3fc9a93f375ebd22a50296c3a295028bea73b9e7"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2183111651d710d3097338dd1893fcf09c9f54e27ff1a8795495a16a469cc90b"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fb075ad271405dcad8e2a7ffc9a750a3bf70e533bd86e89f0603e607b93aa64c"}, + {file = "propcache-0.3.2-cp310-cp310-win32.whl", hash = "sha256:404d70768080d3d3bdb41d0771037da19d8340d50b08e104ca0e7f9ce55fce70"}, + {file = "propcache-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:7435d766f978b4ede777002e6b3b6641dd229cd1da8d3d3106a45770365f9ad9"}, + {file = "propcache-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be"}, + {file = "propcache-0.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f"}, + {file = "propcache-0.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9"}, + {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf"}, + {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9"}, + {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66"}, + {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df"}, + {file = "propcache-0.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e"}, + {file = "propcache-0.3.2-cp311-cp311-win32.whl", hash = "sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897"}, + {file = "propcache-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39"}, + {file = "propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10"}, + {file = "propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154"}, + {file = "propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615"}, + {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db"}, + {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1"}, + {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c"}, + {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67"}, + {file = "propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1"}, + {file = "propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1"}, + {file = "propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c"}, + {file = "propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945"}, + {file = "propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252"}, + {file = "propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f"}, + {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33"}, + {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e"}, + {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1"}, + {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3"}, + {file = "propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43"}, + {file = "propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02"}, + {file = "propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05"}, + {file = "propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b"}, + {file = "propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0"}, + {file = "propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e"}, + {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28"}, + {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a"}, + {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c"}, + {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725"}, + {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330"}, + {file = "propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394"}, + {file = "propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198"}, + {file = "propcache-0.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a7fad897f14d92086d6b03fdd2eb844777b0c4d7ec5e3bac0fbae2ab0602bbe5"}, + {file = "propcache-0.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1f43837d4ca000243fd7fd6301947d7cb93360d03cd08369969450cc6b2ce3b4"}, + {file = "propcache-0.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:261df2e9474a5949c46e962065d88eb9b96ce0f2bd30e9d3136bcde84befd8f2"}, + {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e514326b79e51f0a177daab1052bc164d9d9e54133797a3a58d24c9c87a3fe6d"}, + {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4a996adb6904f85894570301939afeee65f072b4fd265ed7e569e8d9058e4ec"}, + {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76cace5d6b2a54e55b137669b30f31aa15977eeed390c7cbfb1dafa8dfe9a701"}, + {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31248e44b81d59d6addbb182c4720f90b44e1efdc19f58112a3c3a1615fb47ef"}, + {file = "propcache-0.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abb7fa19dbf88d3857363e0493b999b8011eea856b846305d8c0512dfdf8fbb1"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d81ac3ae39d38588ad0549e321e6f773a4e7cc68e7751524a22885d5bbadf886"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:cc2782eb0f7a16462285b6f8394bbbd0e1ee5f928034e941ffc444012224171b"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:db429c19a6c7e8a1c320e6a13c99799450f411b02251fb1b75e6217cf4a14fcb"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:21d8759141a9e00a681d35a1f160892a36fb6caa715ba0b832f7747da48fb6ea"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2ca6d378f09adb13837614ad2754fa8afaee330254f404299611bce41a8438cb"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:34a624af06c048946709f4278b4176470073deda88d91342665d95f7c6270fbe"}, + {file = "propcache-0.3.2-cp39-cp39-win32.whl", hash = "sha256:4ba3fef1c30f306b1c274ce0b8baaa2c3cdd91f645c48f06394068f37d3837a1"}, + {file = "propcache-0.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:7a2368eed65fc69a7a7a40b27f22e85e7627b74216f0846b04ba5c116e191ec9"}, + {file = "propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f"}, + {file = "propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168"}, +] + +[[package]] +name = "py-serializable" +version = "2.1.0" +description = "Library for serializing and deserializing Python Objects to and from JSON and XML." +optional = false +python-versions = "<4.0,>=3.8" +groups = ["dev"] +files = [ + {file = "py_serializable-2.1.0-py3-none-any.whl", hash = "sha256:b56d5d686b5a03ba4f4db5e769dc32336e142fc3bd4d68a8c25579ebb0a67304"}, + {file = "py_serializable-2.1.0.tar.gz", hash = "sha256:9d5db56154a867a9b897c0163b33a793c804c80cee984116d02d49e4578fc103"}, +] + +[package.dependencies] +defusedxml = ">=0.7.1,<0.8.0" + +[[package]] +name = "py-sr25519-bindings" +version = "0.2.2" +description = "Python bindings for schnorrkel RUST crate" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "py_sr25519_bindings-0.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd29a2ee1dfa55a3e17cf18fe0fa5f5749e0c49c9bd9c423a46e1cc242225447"}, + {file = "py_sr25519_bindings-0.2.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:58702966f1547e47bfbf70924eef881087bff969e2dca15953cdc95cb2abb4a2"}, + {file = "py_sr25519_bindings-0.2.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9b5b2cdf08be144f395508acebd5fa41c81dbee1364de75ff80fe0f1308fd969"}, + {file = "py_sr25519_bindings-0.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77f7f4b323c628242909228eaac78bf6376b39b8988704e7910e858c2017b487"}, + {file = "py_sr25519_bindings-0.2.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:58b1e28fc1c57f69d37556b8f3c51cdd84446f643729789b6c0ce19ce2726bd5"}, + {file = "py_sr25519_bindings-0.2.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:512185a3be65a893208e9c30d11948c8b405532756f3bcab16d1dbe5d8e3355e"}, + {file = "py_sr25519_bindings-0.2.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3e5bf9343f3708cfdf5228dbb1b8a093c64144bb9c4bd02cfb014fb2241dd965"}, + {file = "py_sr25519_bindings-0.2.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e9ac26fd6b8606796fcaee90fe277820efbe168490659d26295fd0fc7b37ee4a"}, + {file = "py_sr25519_bindings-0.2.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:297e29518a01a24b943333fc9fe5e7102cb7083f2d256270f42476bcf5ba666d"}, + {file = "py_sr25519_bindings-0.2.2-cp310-cp310-win32.whl", hash = "sha256:f1ab3c36d94dec25767e2a54a2fb0eb320fc0c3e1d7ea573288b961d432672ef"}, + {file = "py_sr25519_bindings-0.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:cc40a53600e68848658cf6046cd43ef2ec9f0c8c04ebf8ea3636dd58c1c25296"}, + {file = "py_sr25519_bindings-0.2.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c0931d8fd07e13131e652f3211c1f1c12b7a5153bed9217e4483b195515c76f"}, + {file = "py_sr25519_bindings-0.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:09657937b8f04c034622691c4753fcef0b3857939dbeff72590b7f5de336302d"}, + {file = "py_sr25519_bindings-0.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ca700354e8cc3d082426ca5cdc7dd34a05988adec4edc0cd42d31c4ba16fbc0"}, + {file = "py_sr25519_bindings-0.2.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ddb490e99d5646ba68f5308fed1b92efbc85470b1171a2b78e555b44a7073570"}, + {file = "py_sr25519_bindings-0.2.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8a479a7510f30d2912f552335cb83d321c0be83832a71cd0bcd190f6356a7bf"}, + {file = "py_sr25519_bindings-0.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab25059d290753202f160bb8a4fd3c789ab9663381ca564338015fd3b7625dde"}, + {file = "py_sr25519_bindings-0.2.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:315382f207430143cd748f805f13bf56f36fc66726303b491cd38ce78d8972e9"}, + {file = "py_sr25519_bindings-0.2.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1a65275421f30e3d563c6f3dec552060f1f85b7840ab8ecf1d48ced008d0ba5f"}, + {file = "py_sr25519_bindings-0.2.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1350c85bdc903105d8fdc7dd369b802bf2821c321fea8aa0929f7a7063437d81"}, + {file = "py_sr25519_bindings-0.2.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3a34fa18885345a0102c3ffbaa17a32cd67d28a60376158508d5ed7f96a478f7"}, + {file = "py_sr25519_bindings-0.2.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c63b0966b45870f0b1dfc2a366f1763f4a165f3aec2b02e7464cfb2c6ca09e94"}, + {file = "py_sr25519_bindings-0.2.2-cp311-cp311-win32.whl", hash = "sha256:7bf982a7d34f6eb0c7c42b7f59610a527e9b02654079fb78d7eb757c6bd79d9d"}, + {file = "py_sr25519_bindings-0.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:d9ee79ec4e722993da24385a8eb85d97878ef67d48d0e706c098c626d798c7bc"}, + {file = "py_sr25519_bindings-0.2.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f22542738ed98fac0d3da2479dd3f26c695594800877a4d8bb116c47e4fd4b7c"}, + {file = "py_sr25519_bindings-0.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b312b8ac7c8354d5cf1b9aad993bbafbd99cc97b6d246f246e76814f576ed809"}, + {file = "py_sr25519_bindings-0.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c70ff898fa46f380a535c843e3a1a9824d1849216067bbf28eb9ad225b92f0bb"}, + {file = "py_sr25519_bindings-0.2.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:292be23ad53d9f9dbf1703a2a341005629a8f93c57cfad254c8c1230ec7d3fe3"}, + {file = "py_sr25519_bindings-0.2.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:673b31e8f59bc1478814b011921073f8ad4e2c78a1d6580b3ddb1a9d7edc4392"}, + {file = "py_sr25519_bindings-0.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:849f77ab12210e8549e58d444e9199d9aba83a988e99ca8bef04dd53e81f9561"}, + {file = "py_sr25519_bindings-0.2.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf8c1d329275c41836aee5f8789ab14100dbdc2b6f3a0210fac2abb0f7507c24"}, + {file = "py_sr25519_bindings-0.2.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:48f053c5e8cb66125057b25223ef5ff57bb4383a82871d47089397317c5fd792"}, + {file = "py_sr25519_bindings-0.2.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fea3ce0ac6a26a52735bb48f8daafb82d17147f776bb6d9d3c330bd2ccffe20d"}, + {file = "py_sr25519_bindings-0.2.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f44a0a9cb155af6408e3f73833a935abc98934ce097b2ad07dd13e3a88f82cb8"}, + {file = "py_sr25519_bindings-0.2.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cc531500823ece8d6889082642e9ea06f2eaffd0ed43d65871cb4727429027c"}, + {file = "py_sr25519_bindings-0.2.2-cp312-cp312-win32.whl", hash = "sha256:840c3ec1fc8dde12421369afa9761943efe377a7bd55a97524587e8b5a6546c2"}, + {file = "py_sr25519_bindings-0.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:c3ee5fd07b2974ce147ac7546b18729d2eb4efebe8eaad178690aaca656487f3"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3bb2c5fba39a82880c43b0d75e87f4d4a2416717c5fa2122b22e02689c2120e3"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1393798a36f74482c53c254969ae8d92f6549767ef69575206eaaf629cbf2a64"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29b9ee2e2f8f36676fa2a72af5bdfe257d331b3d83e5a92b45bad2f25a5b975c"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4e932c33f6b660319c950c300c32ad2c0ba9642743a2e709a2fb886d32c28baf"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1fce13a3434c57af097b8b07b69e3821b1f10623754204112c14bd544bd961c1"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16501bd5b9a37623dbf48aa6b197c57c004f9125e190450e041289a8c3eceac7"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:beb12471fb76be707fc9213d39e5be4cf4add7e38e08bc1fbf7e786250977e00"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:55134f0ba34c27fbb8b489a338c6cb6a31465813f615ed93afbd67e844ef3aed"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:785521c868738a2345e3625ad9166ede228f63e9d3f0c7ff8e35f49d636bce04"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c8cab5620a4ef4cc69a314c9e9ac17af1c0d4d11e297fcefe5d71d827fd7ee21"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:15ae6f86f112c6b23d357b5a98a6cb493f5c2734fabff354a8198be9dea0e90e"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313-win32.whl", hash = "sha256:cba9efa48f48bf56e73a528005978b6f05cb2c847e21eb9645bbc6581619482f"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313-win_amd64.whl", hash = "sha256:9cdb4e0f231fd5824f73361a37a102871866d29752f96d88b1da958f1e5ff2d4"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1d436db7f48dabd4201bb1a88c66a6a3cd15a40e89a236ec1b8cb60037dc1a9"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a9b8c9a81f90dc330eabbdc3ec5f9fdf84a34cd37a1e660cbf5c5daec7b2d08f"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f496da3eb2d843bd12ccff871d22d086b08cfe95852ca91dcdbd91e350aca8d"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:862fa69f948cb3028051a71ce0d2d88cbe8b52723c782f0972d12f5f85a25637"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:1111597744d7993ce732f785e97e0d2e4f9554509d90ba4b0e99829dbf1c2e6d"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c4518b553335f70f18b8167eb2b7f533a66eb703f251d4d4b36c4a03d14cd75e"}, + {file = "py_sr25519_bindings-0.2.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c917a8f365450be06e051f8d8671c182057cdda42bd5f6883c5f537a2bac4f5a"}, + {file = "py_sr25519_bindings-0.2.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b8b2666d381416fb07336c6596a5554dd0e0f1ec50ff32bcc975ae29df79961"}, + {file = "py_sr25519_bindings-0.2.2-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5644353660fd9f97318d70fb7cf362f969a5ee572b61df8f18eda5fea80a6514"}, + {file = "py_sr25519_bindings-0.2.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0728fff2a29d4cc76c4cf22142cd2e2e8dc37745b213a866412980191e1260c"}, + {file = "py_sr25519_bindings-0.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b74c31e2960c4af5b709b562aaf610989af532aee771fcdf175533de60441607"}, + {file = "py_sr25519_bindings-0.2.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3d3c6836df2d67008e3f11080fb216e414cc924de256dd118e50a92cd334f143"}, + {file = "py_sr25519_bindings-0.2.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:dc5a57b67384244083b8d0831f9490dadca34e0543c1bf2f3a876aa4e7081961"}, + {file = "py_sr25519_bindings-0.2.2-cp37-cp37m-musllinux_1_2_armv7l.whl", hash = "sha256:ea139e7bf80ddc1c682db439825bec56baf745d643c146a783e9ddb737af266a"}, + {file = "py_sr25519_bindings-0.2.2-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:727f91cff7901db2d4e0f762dafd48c2b1086945b4903dcdd0a3eb65624c17c8"}, + {file = "py_sr25519_bindings-0.2.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0e4217f59936ae13fa4215838d2da59c130572408e3f29a9f7ca436924f4b356"}, + {file = "py_sr25519_bindings-0.2.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e6f2c026aa910cac7f16723b6b3e9736fe805e51b6ba41cfb4e25a4c0a6442"}, + {file = "py_sr25519_bindings-0.2.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:776d1a1f114b1f0553c9c8336545daaf20443d0b681c47c499377f69406f7a56"}, + {file = "py_sr25519_bindings-0.2.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:314893d4ea96877560bc12446956d61707ca46fb99040ffad751a0710a7aa87f"}, + {file = "py_sr25519_bindings-0.2.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:277e8ef38c9d899b1855fdcde07ae73a9917e06c46df556b8ca3216ae585b532"}, + {file = "py_sr25519_bindings-0.2.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:695e80ccdb710efba2f909235b18eaf230cf0b3f60e8d52a1c904eaeeff839ba"}, + {file = "py_sr25519_bindings-0.2.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2777013ff914bcc87e657657e99922fa48f3bb674734550989fb210fb3d878a2"}, + {file = "py_sr25519_bindings-0.2.2-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:30f1af9306fda911f296db29b4fff06197d3f38de5643b3d95862d3833db1e41"}, + {file = "py_sr25519_bindings-0.2.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:56eeafc92d3c66990ab97ff91c09b3295aea6dac9b64af0227750a8192aeaeec"}, + {file = "py_sr25519_bindings-0.2.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:f7126db740eb190cf1ba993e066f03c2914edaf08e6963d10bbdd740922c95e6"}, + {file = "py_sr25519_bindings-0.2.2-cp38-cp38-win32.whl", hash = "sha256:7b20210a0a0b39e3f0bcb7832a3df736eeea2fcc5776dba1ce5b0c050e489145"}, + {file = "py_sr25519_bindings-0.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:5329e2e54eb9850c2eb84d6a226bd98cdc3597535453eced920035e1e026dced"}, + {file = "py_sr25519_bindings-0.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b32743bba0a53225097120b212da88c14584022a357d7e91cf19ed0a3adad9f6"}, + {file = "py_sr25519_bindings-0.2.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd56849d9195693c6a8e7c48efe4256918b6afeec090915f3f8f883cdb8addda"}, + {file = "py_sr25519_bindings-0.2.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f46c87fd7a8e55c4fce272d4e34663d3c7c3ffee906826a2a16a1400027aa5b9"}, + {file = "py_sr25519_bindings-0.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ee25565a287690d6e48302f4584775622ce3329d2ab92fd3b0a4f063d4ca91f"}, + {file = "py_sr25519_bindings-0.2.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b1199dab44704aa34401428ca3170da5b7ffdc8c65208a2c75a3c1fe5298b20e"}, + {file = "py_sr25519_bindings-0.2.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702a28e8ead7d1d664bea22168158edcc0e3d36e5cc1a79c7373ab1636f89cc2"}, + {file = "py_sr25519_bindings-0.2.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:3de67c503155019c494e5887d1797f046afe1aeb99ee4b3cf86c15386330f034"}, + {file = "py_sr25519_bindings-0.2.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e1a48b295b562836d72dee7136c0503ea63cd89fec85d418b91ba040471c37ed"}, + {file = "py_sr25519_bindings-0.2.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:acebe18639616cd00ad0544d9bdaa73c545f00c4fc0d29b8a4e1e6c447f7a607"}, + {file = "py_sr25519_bindings-0.2.2-cp39-cp39-win32.whl", hash = "sha256:62e4bdd094589446a24dc1029cf2ef6c869e1f4fede04e17335bc92e60640fc5"}, + {file = "py_sr25519_bindings-0.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:0c2483031813f908da35c380196bc88410e2542482a5b4b51d265c6566de116c"}, + {file = "py_sr25519_bindings-0.2.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c9ee94a9fa1625f3192c89ecacc2bd012e09b57e6d2ad8ede027b31381609d3"}, + {file = "py_sr25519_bindings-0.2.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e4c95b3b6230faf2e89f6e5407d63a9d0d52385e6b7d42205570f5ee2f927940"}, + {file = "py_sr25519_bindings-0.2.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ab2b063129babc8f1d9fe6cf5c2d8cc434b6797c553440302da1fab987d74ab"}, + {file = "py_sr25519_bindings-0.2.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1bf93d46ab717089f4fac9b764ea4e7be9f4a45a62bd9919ef850ae8d2ae433"}, + {file = "py_sr25519_bindings-0.2.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5e927dd15d61e76fde3fa8bd6d776148ea987944fee1fe815fbc40c6a77f61ad"}, + {file = "py_sr25519_bindings-0.2.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:6584cf4c87fae9bdd64bc50dd786d9c805165bb6bc7a1ff545e77b29a78acb8d"}, + {file = "py_sr25519_bindings-0.2.2-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:a26b1add87dc6086463975aa1d889f39f90b0d22949d4de52e8a53e516bd2ac4"}, + {file = "py_sr25519_bindings-0.2.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:84cb2c645ce60a04688dedf61ed289d4fb716aef4129313814be1a2d47e268e7"}, + {file = "py_sr25519_bindings-0.2.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:76e660007dd415de22b1d99a884ee39cb6abf03f24377f58e4498533856c2bac"}, + {file = "py_sr25519_bindings-0.2.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d0afcb14cd493485175dc9bf8c57b8b37581bbb29f55b6e4f3ce1f803222488"}, + {file = "py_sr25519_bindings-0.2.2-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b5c5f9080e879badefff596361520b2d9de9d9c4be7c14b36a017d798c451e2"}, + {file = "py_sr25519_bindings-0.2.2-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a42353737c22a3fa425ac350f5fac74d5b2f9c3cdb8ad44dbb367bd7869774cc"}, + {file = "py_sr25519_bindings-0.2.2-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3ea3dc2c6a2a38b791114bd50021f10db2dd2a1d7a1a1aac0c7e80d885c0d3b5"}, + {file = "py_sr25519_bindings-0.2.2-pp38-pypy38_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:888d98a2d7736e0f269c8ab1f09dfac04af2d024b18c0485adc3615277f3442b"}, + {file = "py_sr25519_bindings-0.2.2-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:50976e9b22328df5696fcbfded27215a35225ee41e0b3f1b26a01ab00ad08143"}, + {file = "py_sr25519_bindings-0.2.2-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6449963cd6b300b224a1bc1fec77df012e30d609e54ccffe4f44f4563eab27c2"}, + {file = "py_sr25519_bindings-0.2.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:726346118fc2b785525945ee71ea1acf9be84c41e266c2345c93c7d4d6132cbc"}, + {file = "py_sr25519_bindings-0.2.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4dd5cfe48faafa7e112a021284663db8b64efd9b2225e69906f0bf7f3159a3ce"}, + {file = "py_sr25519_bindings-0.2.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:85432a949143d7a20e452b4c89d5f0ad9a0162e1ce5a904fc157fe204cbe5ded"}, + {file = "py_sr25519_bindings-0.2.2-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:04a2f2eac269bb2f9bf30c795990211cd8d4cfdd28eafbd73b2dfc77a9ef940f"}, + {file = "py_sr25519_bindings-0.2.2-pp39-pypy39_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:bc7ecd25700a664d835cc9db5f6a4f65fef62a395762487c8c2a661566316e8f"}, + {file = "py_sr25519_bindings-0.2.2-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:9efc5526c0eb74c2f8df809c47e22d62febc31db8f38b5c6b1253e810e0ed71f"}, + {file = "py_sr25519_bindings-0.2.2-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:daa74fdd7bac2d97fbbbbb1ca40a0c02102220d09cfa9695cbde8d2cbedfadb7"}, + {file = "py_sr25519_bindings-0.2.2.tar.gz", hash = "sha256:192d65d3bc43c6f4121a0732e1f6eb6ad869897ca26368ba032e96a82b3b7606"}, +] + +[[package]] +name = "pyasn1" +version = "0.6.1" +description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"}, + {file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"}, +] + +[[package]] +name = "pycairo" +version = "1.28.0" +description = "Python interface for cairo" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"gui-gtk\"" +files = [ + {file = "pycairo-1.28.0-cp310-cp310-win32.whl", hash = "sha256:53e6dbc98456f789965dad49ef89ce2c62f9a10fc96c8d084e14da0ffb73d8a6"}, + {file = "pycairo-1.28.0-cp310-cp310-win_amd64.whl", hash = "sha256:c8ab91a75025f984bc327ada335c787efb61c929ea0512063793cb36cee503d4"}, + {file = "pycairo-1.28.0-cp310-cp310-win_arm64.whl", hash = "sha256:e955328c1a5147bf71ee94e206413ce15e12630296a79788fcd246c80e5337b8"}, + {file = "pycairo-1.28.0-cp311-cp311-win32.whl", hash = "sha256:0fee15f5d72b13ba5fd065860312493dc1bca6ff2dce200ee9d704e11c94e60a"}, + {file = "pycairo-1.28.0-cp311-cp311-win_amd64.whl", hash = "sha256:6339979bfec8b58a06476094a9a5c104bd5a99932ddaff16ca0d9203d2f4482c"}, + {file = "pycairo-1.28.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6ae15392e28ebfc0b35d8dc05d395d3b6be4bad9ad4caecf0fa12c8e7150225"}, + {file = "pycairo-1.28.0-cp312-cp312-win32.whl", hash = "sha256:c00cfbb7f30eb7ca1d48886712932e2d91e8835a8496f4e423878296ceba573e"}, + {file = "pycairo-1.28.0-cp312-cp312-win_amd64.whl", hash = "sha256:d50d190f5033992b55050b9f337ee42a45c3568445d5e5d7987bab96c278d8a6"}, + {file = "pycairo-1.28.0-cp312-cp312-win_arm64.whl", hash = "sha256:957e0340ee1c279d197d4f7cfa96f6d8b48e453eec711fca999748d752468ff4"}, + {file = "pycairo-1.28.0-cp313-cp313-win32.whl", hash = "sha256:d13352429d8a08a1cb3607767d23d2fb32e4c4f9faa642155383980ec1478c24"}, + {file = "pycairo-1.28.0-cp313-cp313-win_amd64.whl", hash = "sha256:082aef6b3a9dcc328fa648d38ed6b0a31c863e903ead57dd184b2e5f86790140"}, + {file = "pycairo-1.28.0-cp313-cp313-win_arm64.whl", hash = "sha256:026afd53b75291917a7412d9fe46dcfbaa0c028febd46ff1132d44a53ac2c8b6"}, + {file = "pycairo-1.28.0-cp314-cp314-win32.whl", hash = "sha256:d0ab30585f536101ad6f09052fc3895e2a437ba57531ea07223d0e076248025d"}, + {file = "pycairo-1.28.0-cp314-cp314-win_amd64.whl", hash = "sha256:94f2ed204999ab95a0671a0fa948ffbb9f3d6fb8731fe787917f6d022d9c1c0f"}, + {file = "pycairo-1.28.0-cp39-cp39-win32.whl", hash = "sha256:3ed16d48b8a79cc584cb1cb0ad62dfb265f2dda6d6a19ef5aab181693e19c83c"}, + {file = "pycairo-1.28.0-cp39-cp39-win_amd64.whl", hash = "sha256:da0d1e6d4842eed4d52779222c6e43d254244a486ca9fdab14e30042fd5bdf28"}, + {file = "pycairo-1.28.0-cp39-cp39-win_arm64.whl", hash = "sha256:458877513eb2125513122e8aa9c938630e94bb0574f94f4fb5ab55eb23d6e9ac"}, + {file = "pycairo-1.28.0.tar.gz", hash = "sha256:26ec5c6126781eb167089a123919f87baa2740da2cca9098be8b3a6b91cc5fbc"}, +] + +[[package]] +name = "pycparser" +version = "2.22" +description = "C parser in Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, +] + +[[package]] +name = "pycryptodome" +version = "3.23.0" +description = "Cryptographic library for Python" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main"] +files = [ + {file = "pycryptodome-3.23.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a176b79c49af27d7f6c12e4b178b0824626f40a7b9fed08f712291b6d54bf566"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:573a0b3017e06f2cffd27d92ef22e46aa3be87a2d317a5abf7cc0e84e321bd75"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:63dad881b99ca653302b2c7191998dd677226222a3f2ea79999aa51ce695f720"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-win32.whl", hash = "sha256:b34e8e11d97889df57166eda1e1ddd7676da5fcd4d71a0062a760e75060514b4"}, + {file = "pycryptodome-3.23.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7ac1080a8da569bde76c0a104589c4f414b8ba296c0b3738cf39a466a9fb1818"}, + {file = "pycryptodome-3.23.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6fe8258e2039eceb74dfec66b3672552b6b7d2c235b2dfecc05d16b8921649a8"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39"}, + {file = "pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27"}, + {file = "pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c"}, + {file = "pycryptodome-3.23.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:350ebc1eba1da729b35ab7627a833a1a355ee4e852d8ba0447fafe7b14504d56"}, + {file = "pycryptodome-3.23.0-pp27-pypy_73-win32.whl", hash = "sha256:93837e379a3e5fd2bb00302a47aee9fdf7940d83595be3915752c74033d17ca7"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:865d83c906b0fc6a59b510deceee656b6bc1c4fa0d82176e2b77e97a420a996a"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89d4d56153efc4d81defe8b65fd0821ef8b2d5ddf8ed19df31ba2f00872b8002"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3f2d0aaf8080bda0587d58fc9fe4766e012441e2eed4269a77de6aea981c8be"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64093fc334c1eccfd3933c134c4457c34eaca235eeae49d69449dc4728079339"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ce64e84a962b63a47a592690bdc16a7eaf709d2c2697ababf24a0def566899a6"}, + {file = "pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef"}, +] + +[[package]] +name = "pydantic" +version = "2.11.7" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b"}, + {file = "pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db"}, +] + +[package.dependencies] +annotated-types = ">=0.6.0" +pydantic-core = "2.33.2" +typing-extensions = ">=4.12.2" +typing-inspection = ">=0.4.0" + +[package.extras] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"}, + {file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b"}, + {file = "pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22"}, + {file = "pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640"}, + {file = "pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7"}, + {file = "pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65"}, + {file = "pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc"}, + {file = "pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab"}, + {file = "pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f"}, + {file = "pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d"}, + {file = "pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e"}, + {file = "pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27"}, + {file = "pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pygments" +version = "2.19.2" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, + {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pygobject" +version = "3.52.3" +description = "Python bindings for GObject Introspection" +optional = true +python-versions = "<4.0,>=3.9" +groups = ["main"] +markers = "extra == \"gui-gtk\"" +files = [ + {file = "pygobject-3.52.3.tar.gz", hash = "sha256:00e427d291e957462a8fad659a9f9c8be776ff82a8b76bdf402f1eaeec086d82"}, +] + +[package.dependencies] +pycairo = ">=1.16" + +[[package]] +name = "pyjwt" +version = "2.10.1" +description = "JSON Web Token implementation in Python" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, + {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, +] + +[package.extras] +crypto = ["cryptography (>=3.4.0)"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] + +[[package]] +name = "pynacl" +version = "1.5.0" +description = "Python binding to the Networking and Cryptography (NaCl) library" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858"}, + {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b"}, + {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff"}, + {file = "PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"}, + {file = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93"}, + {file = "PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba"}, +] + +[package.dependencies] +cffi = ">=1.4.1" + +[package.extras] +docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] +tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] + +[[package]] +name = "pyotp" +version = "2.9.0" +description = "Python One Time Password Library" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "pyotp-2.9.0-py3-none-any.whl", hash = "sha256:81c2e5865b8ac55e825b0358e496e1d9387c811e85bb40e71a3b29b288963612"}, + {file = "pyotp-2.9.0.tar.gz", hash = "sha256:346b6642e0dbdde3b4ff5a930b664ca82abfa116356ed48cc42c7d6590d36f63"}, +] + +[package.extras] +test = ["coverage", "mypy", "ruff", "wheel"] + +[[package]] +name = "pyparsing" +version = "3.2.3" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf"}, + {file = "pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pyperclip" +version = "1.9.0" +description = "A cross-platform clipboard module for Python. (Only handles plain text for now.)" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "pyperclip-1.9.0.tar.gz", hash = "sha256:b7de0142ddc81bfc5c7507eea19da920b92252b548b96186caf94a5e2527d310"}, +] + +[[package]] +name = "pytest" +version = "8.4.1" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7"}, + {file = "pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c"}, +] + +[package.dependencies] +colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} +iniconfig = ">=1" +packaging = ">=20" +pluggy = ">=1.5,<2" +pygments = ">=2.7.2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-xdist" +version = "3.8.0" +description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88"}, + {file = "pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1"}, +] + +[package.dependencies] +execnet = ">=2.1" +pytest = ">=7.0.0" + +[package.extras] +psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["dev"] +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-multipart" +version = "0.0.20" +description = "A streaming multipart parser for Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104"}, + {file = "python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13"}, +] + +[[package]] +name = "pythonnet" +version = "3.0.5" +description = ".NET and Mono integration for Python" +optional = true +python-versions = "<3.14,>=3.7" +groups = ["main"] +markers = "extra == \"gui-win\"" +files = [ + {file = "pythonnet-3.0.5-py3-none-any.whl", hash = "sha256:f6702d694d5d5b163c9f3f5cc34e0bed8d6857150237fae411fefb883a656d20"}, + {file = "pythonnet-3.0.5.tar.gz", hash = "sha256:48e43ca463941b3608b32b4e236db92d8d40db4c58a75ace902985f76dac21cf"}, +] + +[package.dependencies] +clr_loader = ">=0.2.7,<0.3.0" + +[[package]] +name = "pywin32" +version = "311" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +groups = ["main"] +markers = "platform_system == \"Windows\"" +files = [ + {file = "pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3"}, + {file = "pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b"}, + {file = "pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b"}, + {file = "pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151"}, + {file = "pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503"}, + {file = "pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2"}, + {file = "pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31"}, + {file = "pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067"}, + {file = "pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852"}, + {file = "pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d"}, + {file = "pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d"}, + {file = "pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a"}, + {file = "pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee"}, + {file = "pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87"}, + {file = "pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42"}, + {file = "pywin32-311-cp38-cp38-win32.whl", hash = "sha256:6c6f2969607b5023b0d9ce2541f8d2cbb01c4f46bc87456017cf63b73f1e2d8c"}, + {file = "pywin32-311-cp38-cp38-win_amd64.whl", hash = "sha256:c8015b09fb9a5e188f83b7b04de91ddca4658cee2ae6f3bc483f0b21a77ef6cd"}, + {file = "pywin32-311-cp39-cp39-win32.whl", hash = "sha256:aba8f82d551a942cb20d4a83413ccbac30790b50efb89a75e4f586ac0bb8056b"}, + {file = "pywin32-311-cp39-cp39-win_amd64.whl", hash = "sha256:e0c4cfb0621281fe40387df582097fd796e80430597cb9944f0ae70447bacd91"}, + {file = "pywin32-311-cp39-cp39-win_arm64.whl", hash = "sha256:62ea666235135fee79bb154e695f3ff67370afefd71bd7fea7512fc70ef31e3d"}, +] + +[[package]] +name = "qrcode" +version = "8.2" +description = "QR Code image generator" +optional = false +python-versions = "<4.0,>=3.9" +groups = ["main"] +files = [ + {file = "qrcode-8.2-py3-none-any.whl", hash = "sha256:16e64e0716c14960108e85d853062c9e8bba5ca8252c0b4d0231b9df4060ff4f"}, + {file = "qrcode-8.2.tar.gz", hash = "sha256:35c3f2a4172b33136ab9f6b3ef1c00260dd2f66f858f24d88418a015f446506c"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} + +[package.extras] +all = ["pillow (>=9.1.0)", "pypng"] +pil = ["pillow (>=9.1.0)"] +png = ["pypng"] + +[[package]] +name = "requests" +version = "2.32.4" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"}, + {file = "requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset_normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "rich" +version = "14.1.0" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.8.0" +groups = ["main", "dev"] +files = [ + {file = "rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f"}, + {file = "rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "rubicon-objc" +version = "0.5.2" +description = "A bridge between an Objective C runtime environment and Python." +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"gui-mac\"" +files = [ + {file = "rubicon_objc-0.5.2-py3-none-any.whl", hash = "sha256:829b253c579e51fc34f4bb6587c34806e78960dcc1eb24e62b38141a1fe02b39"}, + {file = "rubicon_objc-0.5.2.tar.gz", hash = "sha256:1180593935f6a8a39c23b5f4b7baa24aedf9f7285e80804a1d9d6b50a50572f5"}, +] + +[package.extras] +dev = ["pre-commit (==4.2.0)", "pytest (==8.4.1)", "setuptools_scm (==8.3.1)", "tox (==4.28.4)"] +docs = ["furo (==2025.7.19)", "pyenchant (==3.2.2)", "sphinx (==8.2.3)", "sphinx-autobuild (==2024.10.3)", "sphinx-copybutton (==0.5.2)", "sphinx_tabs (==3.4.7)", "sphinxcontrib-spelling (==8.0.1)"] + +[[package]] +name = "shellingham" +version = "1.5.4" +description = "Tool to Detect Surrounding Shell" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, +] + +[[package]] +name = "six" +version = "1.17.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main", "dev"] +files = [ + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, +] + +[[package]] +name = "slowapi" +version = "0.1.9" +description = "A rate limiting extension for Starlette and Fastapi" +optional = false +python-versions = ">=3.7,<4.0" +groups = ["main"] +files = [ + {file = "slowapi-0.1.9-py3-none-any.whl", hash = "sha256:cfad116cfb84ad9d763ee155c1e5c5cbf00b0d47399a769b227865f5df576e36"}, + {file = "slowapi-0.1.9.tar.gz", hash = "sha256:639192d0f1ca01b1c6d95bf6c71d794c3a9ee189855337b4821f7f457dddad77"}, +] + +[package.dependencies] +limits = ">=2.3" + +[package.extras] +redis = ["redis (>=3.4.1,<4.0.0)"] + +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, + {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, +] + +[[package]] +name = "starlette" +version = "0.47.2" +description = "The little ASGI library that shines." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "starlette-0.47.2-py3-none-any.whl", hash = "sha256:c5847e96134e5c5371ee9fac6fdf1a67336d5815e09eb2a01fdb57a351ef915b"}, + {file = "starlette-0.47.2.tar.gz", hash = "sha256:6ae9aa5db235e4846decc1e7b79c4f346adf41e9777aebeb49dfd09bbd7023d8"}, +] + +[package.dependencies] +anyio = ">=3.6.2,<5" +typing-extensions = {version = ">=4.10.0", markers = "python_version < \"3.13\""} + +[package.extras] +full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"] + +[[package]] +name = "termcolor" +version = "3.1.0" +description = "ANSI color formatting for output in terminal" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "termcolor-3.1.0-py3-none-any.whl", hash = "sha256:591dd26b5c2ce03b9e43f391264626557873ce1d379019786f99b0c2bee140aa"}, + {file = "termcolor-3.1.0.tar.gz", hash = "sha256:6a6dd7fbee581909eeec6a756cff1d7f7c376063b14e4a298dc4980309e55970"}, +] + +[package.extras] +tests = ["pytest", "pytest-cov"] + +[[package]] +name = "toga-cocoa" +version = "0.5.2" +description = "A Cocoa (macOS) backend for the Toga widget toolkit." +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"gui-mac\"" +files = [ + {file = "toga_cocoa-0.5.2-py3-none-any.whl", hash = "sha256:a4d5d1546bf92372a6fb1b450164735fb107b2ee69d15bf87421fec3c78465f9"}, + {file = "toga_cocoa-0.5.2.tar.gz", hash = "sha256:dd8e1e29eff53c2e4cbe3ded9ea037716062b65f82b9cac478a82e15ba0a2750"}, +] + +[package.dependencies] +fonttools = ">=4.42.1,<5.0.0" +rubicon-objc = ">=0.5.1,<0.6.0" +toga-core = "0.5.2" + +[[package]] +name = "toga-core" +version = "0.5.2" +description = "A Python native, OS native GUI toolkit." +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "toga_core-0.5.2-py3-none-any.whl", hash = "sha256:e872cebd2d899e9138f73393e8cd834a55a057aa269608ff7314a853ab33cb4e"}, + {file = "toga_core-0.5.2.tar.gz", hash = "sha256:bdd3760146b74c8d315cb901392c2b645ab3e5d4cd90114f3e36e0e7dad3d6d1"}, +] +markers = {main = "extra == \"gui\" or extra == \"gui-gtk\" or extra == \"gui-win\" or extra == \"gui-mac\""} + +[package.dependencies] +travertino = "0.5.2" + +[package.extras] +dev = ["Pillow (==11.3.0)", "coverage-conditional-plugin (==0.9.0)", "coverage[toml] (==7.9.2)", "pre-commit (==4.2.0)", "pytest (==8.4.1)", "pytest-asyncio (==1.0.0)", "pytest-freezer (==0.4.9)", "pytest-xdist (==3.8.0)", "setuptools-scm (==8.3.1)", "tox (==4.27.0)", "typing-extensions (==4.12.2) ; python_version < \"3.10\""] +docs = ["Pillow (==11.3.0)", "furo (==2024.8.6)", "pyenchant (==3.2.2)", "sphinx (==8.2.3)", "sphinx-autobuild (==2024.10.3)", "sphinx-copybutton (==0.5.2)", "sphinx-csv-filter (==0.4.2)", "sphinx-toolbox (==4.0.0)", "sphinx_tabs (==3.4.5)", "sphinxcontrib-spelling (==8.0.1)"] + +[[package]] +name = "toga-dummy" +version = "0.5.2" +description = "A dummy testing backend for the Toga widget toolkit." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "toga_dummy-0.5.2-py3-none-any.whl", hash = "sha256:44ac143a53ea83ab784467279a91173d55e257a769a44993d2f3f54a0c5379df"}, + {file = "toga_dummy-0.5.2.tar.gz", hash = "sha256:93683f47579f3abc54cb0dec8260cb1f23491732e3c7077eac7a86957a67a91c"}, +] + +[package.dependencies] +toga-core = "0.5.2" + +[[package]] +name = "toga-gtk" +version = "0.5.2" +description = "A GTK backend for the Toga widget toolkit." +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"gui-gtk\"" +files = [ + {file = "toga_gtk-0.5.2-py3-none-any.whl", hash = "sha256:15b346ac1a2584de5effe5e73a3888f055c68c93300aeb111db9d64186b31646"}, + {file = "toga_gtk-0.5.2.tar.gz", hash = "sha256:9212db774dd5f47820d2242bb09c9f44e12e87e3db49ccb967016c6bb311139b"}, +] + +[package.dependencies] +pycairo = ">=1.17.0" +pygobject = ">=3.50.0" +toga-core = "0.5.2" + +[[package]] +name = "toga-winforms" +version = "0.5.2" +description = "A Windows backend for the Toga widget toolkit using the WinForms API." +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"gui-win\"" +files = [ + {file = "toga_winforms-0.5.2-py3-none-any.whl", hash = "sha256:83181309f204bcc4a34709d23fdfd68467ae8ecc39c906d13c661cb9a0ef581b"}, + {file = "toga_winforms-0.5.2.tar.gz", hash = "sha256:7e65ee9a31db6588c41c01cc49c12df1b2019581410be6ba7c685e7ac75f7c4a"}, +] + +[package.dependencies] +pillow = ">=10.0.0" +pythonnet = ">=3.0.0" +toga-core = "0.5.2" + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["dev"] +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] + +[[package]] +name = "tomli" +version = "2.2.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, +] +markers = {dev = "python_version == \"3.10\""} + +[[package]] +name = "travertino" +version = "0.5.2" +description = "A set of constants and base classes for describing user interface layouts." +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "travertino-0.5.2-py3-none-any.whl", hash = "sha256:fd69ac3b14f2847e4c972198588b8a86ca3b437aaa0c8ce7259bbe5dab17aff1"}, + {file = "travertino-0.5.2.tar.gz", hash = "sha256:5afcc673e14e16c3c04c0e3fe387062633e6bc88e87bc0bbd214a04b4dfbbcd4"}, +] +markers = {main = "extra == \"gui\" or extra == \"gui-gtk\" or extra == \"gui-win\" or extra == \"gui-mac\""} + +[package.extras] +dev = ["coverage-conditional-plugin (==0.9.0)", "coverage[toml] (==7.9.2)", "pytest (==8.4.1)", "tox (==4.27.0)", "typing-extensions (==4.12.2) ; python_version < \"3.10\""] + +[[package]] +name = "typer" +version = "0.16.0" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855"}, + {file = "typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b"}, +] + +[package.dependencies] +click = ">=8.0.0" +rich = ">=10.11.0" +shellingham = ">=1.3.0" +typing-extensions = ">=3.7.4.3" + +[[package]] +name = "typing-extensions" +version = "4.14.1" +description = "Backported and Experimental Type Hints for Python 3.9+" +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76"}, + {file = "typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36"}, +] +markers = {dev = "python_version == \"3.10\""} + +[[package]] +name = "typing-inspection" +version = "0.4.1" +description = "Runtime typing introspection tools" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51"}, + {file = "typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28"}, +] + +[package.dependencies] +typing-extensions = ">=4.12.0" + +[[package]] +name = "urllib3" +version = "2.5.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, + {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "uvicorn" +version = "0.35.0" +description = "The lightning-fast ASGI server." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "uvicorn-0.35.0-py3-none-any.whl", hash = "sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a"}, + {file = "uvicorn-0.35.0.tar.gz", hash = "sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01"}, +] + +[package.dependencies] +click = ">=7.0" +h11 = ">=0.8" +typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} + +[package.extras] +standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"] + +[[package]] +name = "websocket-client" +version = "1.7.0" +description = "WebSocket client for Python with low level API options" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "websocket-client-1.7.0.tar.gz", hash = "sha256:10e511ea3a8c744631d3bd77e61eb17ed09304c413ad42cf6ddfa4c7787e8fe6"}, + {file = "websocket_client-1.7.0-py3-none-any.whl", hash = "sha256:f4c3d22fec12a2461427a29957ff07d35098ee2d976d3ba244e688b8b4057588"}, +] + +[package.extras] +docs = ["Sphinx (>=6.0)", "sphinx-rtd-theme (>=1.1.0)"] +optional = ["python-socks", "wsaccel"] +test = ["websockets"] + +[[package]] +name = "websockets" +version = "15.0.1" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c"}, + {file = "websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256"}, + {file = "websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf"}, + {file = "websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85"}, + {file = "websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597"}, + {file = "websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9"}, + {file = "websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4"}, + {file = "websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa"}, + {file = "websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880"}, + {file = "websockets-15.0.1-cp39-cp39-win32.whl", hash = "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411"}, + {file = "websockets-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123"}, + {file = "websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f"}, + {file = "websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee"}, +] + +[[package]] +name = "wrapt" +version = "1.17.2" +description = "Module for decorators, wrappers and monkey patching." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984"}, + {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22"}, + {file = "wrapt-1.17.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:80dd7db6a7cb57ffbc279c4394246414ec99537ae81ffd702443335a61dbf3a7"}, + {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a6e821770cf99cc586d33833b2ff32faebdbe886bd6322395606cf55153246c"}, + {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b60fb58b90c6d63779cb0c0c54eeb38941bae3ecf7a73c764c52c88c2dcb9d72"}, + {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b870b5df5b71d8c3359d21be8f0d6c485fa0ebdb6477dda51a1ea54a9b558061"}, + {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4011d137b9955791f9084749cba9a367c68d50ab8d11d64c50ba1688c9b457f2"}, + {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1473400e5b2733e58b396a04eb7f35f541e1fb976d0c0724d0223dd607e0f74c"}, + {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3cedbfa9c940fdad3e6e941db7138e26ce8aad38ab5fe9dcfadfed9db7a54e62"}, + {file = "wrapt-1.17.2-cp310-cp310-win32.whl", hash = "sha256:582530701bff1dec6779efa00c516496968edd851fba224fbd86e46cc6b73563"}, + {file = "wrapt-1.17.2-cp310-cp310-win_amd64.whl", hash = "sha256:58705da316756681ad3c9c73fd15499aa4d8c69f9fd38dc8a35e06c12468582f"}, + {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58"}, + {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda"}, + {file = "wrapt-1.17.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9abc77a4ce4c6f2a3168ff34b1da9b0f311a8f1cfd694ec96b0603dff1c79438"}, + {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b929ac182f5ace000d459c59c2c9c33047e20e935f8e39371fa6e3b85d56f4a"}, + {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f09b286faeff3c750a879d336fb6d8713206fc97af3adc14def0cdd349df6000"}, + {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7ed2d9d039bd41e889f6fb9364554052ca21ce823580f6a07c4ec245c1f5d6"}, + {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:129a150f5c445165ff941fc02ee27df65940fcb8a22a61828b1853c98763a64b"}, + {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1fb5699e4464afe5c7e65fa51d4f99e0b2eadcc176e4aa33600a3df7801d6662"}, + {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9a2bce789a5ea90e51a02dfcc39e31b7f1e662bc3317979aa7e5538e3a034f72"}, + {file = "wrapt-1.17.2-cp311-cp311-win32.whl", hash = "sha256:4afd5814270fdf6380616b321fd31435a462019d834f83c8611a0ce7484c7317"}, + {file = "wrapt-1.17.2-cp311-cp311-win_amd64.whl", hash = "sha256:acc130bc0375999da18e3d19e5a86403667ac0c4042a094fefb7eec8ebac7cf3"}, + {file = "wrapt-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925"}, + {file = "wrapt-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392"}, + {file = "wrapt-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40"}, + {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d"}, + {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b"}, + {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98"}, + {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82"}, + {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae"}, + {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9"}, + {file = "wrapt-1.17.2-cp312-cp312-win32.whl", hash = "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9"}, + {file = "wrapt-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991"}, + {file = "wrapt-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125"}, + {file = "wrapt-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998"}, + {file = "wrapt-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5"}, + {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8"}, + {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6"}, + {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc"}, + {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2"}, + {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b"}, + {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504"}, + {file = "wrapt-1.17.2-cp313-cp313-win32.whl", hash = "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a"}, + {file = "wrapt-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845"}, + {file = "wrapt-1.17.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192"}, + {file = "wrapt-1.17.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b"}, + {file = "wrapt-1.17.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0"}, + {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306"}, + {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb"}, + {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681"}, + {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6"}, + {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6"}, + {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f"}, + {file = "wrapt-1.17.2-cp313-cp313t-win32.whl", hash = "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555"}, + {file = "wrapt-1.17.2-cp313-cp313t-win_amd64.whl", hash = "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c"}, + {file = "wrapt-1.17.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5c803c401ea1c1c18de70a06a6f79fcc9c5acfc79133e9869e730ad7f8ad8ef9"}, + {file = "wrapt-1.17.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f917c1180fdb8623c2b75a99192f4025e412597c50b2ac870f156de8fb101119"}, + {file = "wrapt-1.17.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ecc840861360ba9d176d413a5489b9a0aff6d6303d7e733e2c4623cfa26904a6"}, + {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb87745b2e6dc56361bfde481d5a378dc314b252a98d7dd19a651a3fa58f24a9"}, + {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58455b79ec2661c3600e65c0a716955adc2410f7383755d537584b0de41b1d8a"}, + {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4e42a40a5e164cbfdb7b386c966a588b1047558a990981ace551ed7e12ca9c2"}, + {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:91bd7d1773e64019f9288b7a5101f3ae50d3d8e6b1de7edee9c2ccc1d32f0c0a"}, + {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:bb90fb8bda722a1b9d48ac1e6c38f923ea757b3baf8ebd0c82e09c5c1a0e7a04"}, + {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:08e7ce672e35efa54c5024936e559469436f8b8096253404faeb54d2a878416f"}, + {file = "wrapt-1.17.2-cp38-cp38-win32.whl", hash = "sha256:410a92fefd2e0e10d26210e1dfb4a876ddaf8439ef60d6434f21ef8d87efc5b7"}, + {file = "wrapt-1.17.2-cp38-cp38-win_amd64.whl", hash = "sha256:95c658736ec15602da0ed73f312d410117723914a5c91a14ee4cdd72f1d790b3"}, + {file = "wrapt-1.17.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99039fa9e6306880572915728d7f6c24a86ec57b0a83f6b2491e1d8ab0235b9a"}, + {file = "wrapt-1.17.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2696993ee1eebd20b8e4ee4356483c4cb696066ddc24bd70bcbb80fa56ff9061"}, + {file = "wrapt-1.17.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:612dff5db80beef9e649c6d803a8d50c409082f1fedc9dbcdfde2983b2025b82"}, + {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62c2caa1585c82b3f7a7ab56afef7b3602021d6da34fbc1cf234ff139fed3cd9"}, + {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c958bcfd59bacc2d0249dcfe575e71da54f9dcf4a8bdf89c4cb9a68a1170d73f"}, + {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc78a84e2dfbc27afe4b2bd7c80c8db9bca75cc5b85df52bfe634596a1da846b"}, + {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ba0f0eb61ef00ea10e00eb53a9129501f52385c44853dbd6c4ad3f403603083f"}, + {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1e1fe0e6ab7775fd842bc39e86f6dcfc4507ab0ffe206093e76d61cde37225c8"}, + {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c86563182421896d73858e08e1db93afdd2b947a70064b813d515d66549e15f9"}, + {file = "wrapt-1.17.2-cp39-cp39-win32.whl", hash = "sha256:f393cda562f79828f38a819f4788641ac7c4085f30f1ce1a68672baa686482bb"}, + {file = "wrapt-1.17.2-cp39-cp39-win_amd64.whl", hash = "sha256:36ccae62f64235cf8ddb682073a60519426fdd4725524ae38874adf72b5f2aeb"}, + {file = "wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8"}, + {file = "wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3"}, +] + +[[package]] +name = "yarl" +version = "1.20.1" +description = "Yet another URL library" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "yarl-1.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4"}, + {file = "yarl-1.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a"}, + {file = "yarl-1.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c869f2651cc77465f6cd01d938d91a11d9ea5d798738c1dc077f3de0b5e5fed"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62915e6688eb4d180d93840cda4110995ad50c459bf931b8b3775b37c264af1e"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:41ebd28167bc6af8abb97fec1a399f412eec5fd61a3ccbe2305a18b84fb4ca73"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21242b4288a6d56f04ea193adde174b7e347ac46ce6bc84989ff7c1b1ecea84e"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bea21cdae6c7eb02ba02a475f37463abfe0a01f5d7200121b03e605d6a0439f8"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f8a891e4a22a89f5dde7862994485e19db246b70bb288d3ce73a34422e55b23"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd803820d44c8853a109a34e3660e5a61beae12970da479cf44aa2954019bf70"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b982fa7f74c80d5c0c7b5b38f908971e513380a10fecea528091405f519b9ebb"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:33f29ecfe0330c570d997bcf1afd304377f2e48f61447f37e846a6058a4d33b2"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:835ab2cfc74d5eb4a6a528c57f05688099da41cf4957cf08cad38647e4a83b30"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:46b5e0ccf1943a9a6e766b2c2b8c732c55b34e28be57d8daa2b3c1d1d4009309"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:df47c55f7d74127d1b11251fe6397d84afdde0d53b90bedb46a23c0e534f9d24"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76d12524d05841276b0e22573f28d5fbcb67589836772ae9244d90dd7d66aa13"}, + {file = "yarl-1.20.1-cp310-cp310-win32.whl", hash = "sha256:6c4fbf6b02d70e512d7ade4b1f998f237137f1417ab07ec06358ea04f69134f8"}, + {file = "yarl-1.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:aef6c4d69554d44b7f9d923245f8ad9a707d971e6209d51279196d8e8fe1ae16"}, + {file = "yarl-1.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e"}, + {file = "yarl-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b"}, + {file = "yarl-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e"}, + {file = "yarl-1.20.1-cp311-cp311-win32.whl", hash = "sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773"}, + {file = "yarl-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e"}, + {file = "yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9"}, + {file = "yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a"}, + {file = "yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004"}, + {file = "yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5"}, + {file = "yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698"}, + {file = "yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a"}, + {file = "yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3"}, + {file = "yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1"}, + {file = "yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7"}, + {file = "yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c"}, + {file = "yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d"}, + {file = "yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf"}, + {file = "yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e"}, + {file = "yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d"}, + {file = "yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f"}, + {file = "yarl-1.20.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e42ba79e2efb6845ebab49c7bf20306c4edf74a0b20fc6b2ccdd1a219d12fad3"}, + {file = "yarl-1.20.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:41493b9b7c312ac448b7f0a42a089dffe1d6e6e981a2d76205801a023ed26a2b"}, + {file = "yarl-1.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f5a5928ff5eb13408c62a968ac90d43f8322fd56d87008b8f9dabf3c0f6ee983"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30c41ad5d717b3961b2dd785593b67d386b73feca30522048d37298fee981805"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:59febc3969b0781682b469d4aca1a5cab7505a4f7b85acf6db01fa500fa3f6ba"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d2b6fb3622b7e5bf7a6e5b679a69326b4279e805ed1699d749739a61d242449e"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:749d73611db8d26a6281086f859ea7ec08f9c4c56cec864e52028c8b328db723"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9427925776096e664c39e131447aa20ec738bdd77c049c48ea5200db2237e000"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff70f32aa316393eaf8222d518ce9118148eddb8a53073c2403863b41033eed5"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c7ddf7a09f38667aea38801da8b8d6bfe81df767d9dfc8c88eb45827b195cd1c"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:57edc88517d7fc62b174fcfb2e939fbc486a68315d648d7e74d07fac42cec240"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:dab096ce479d5894d62c26ff4f699ec9072269d514b4edd630a393223f45a0ee"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:14a85f3bd2d7bb255be7183e5d7d6e70add151a98edf56a770d6140f5d5f4010"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2c89b5c792685dd9cd3fa9761c1b9f46fc240c2a3265483acc1565769996a3f8"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:69e9b141de5511021942a6866990aea6d111c9042235de90e08f94cf972ca03d"}, + {file = "yarl-1.20.1-cp39-cp39-win32.whl", hash = "sha256:b5f307337819cdfdbb40193cad84978a029f847b0a357fbe49f712063cfc4f06"}, + {file = "yarl-1.20.1-cp39-cp39-win_amd64.whl", hash = "sha256:eae7bfe2069f9c1c5b05fc7fe5d612e5bbc089a39309904ee8b829e322dcad00"}, + {file = "yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77"}, + {file = "yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac"}, +] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" +propcache = ">=0.2.1" + +[extras] +gui = ["pillow", "toga-core"] +gui-gtk = ["toga-gtk"] +gui-mac = ["toga-cocoa"] +gui-win = ["toga-winforms"] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.10,<3.13" +content-hash = "9cdc15f624271aab6d58e5f945c0e99878079da7c3f5a397b0753166c06f9612" diff --git a/pyproject.toml b/pyproject.toml index 28115bbc..5f8b39c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,12 +1,63 @@ -[project] +[tool.poetry] name = "seedpass" version = "0.1.0" +description = "Deterministic password manager with a BeeWare GUI" +authors = [] -[build-system] -requires = ["setuptools>=61", "wheel"] -build-backend = "setuptools.build_meta" +[tool.poetry.dependencies] +python = ">=3.10,<3.13" +colorama = ">=0.4.6" +termcolor = ">=1.1.0" +cryptography = ">=40.0.2" +bip-utils = ">=2.5.0" +bech32 = "1.2.0" +coincurve = ">=18.0.0" +mnemonic = "*" +aiohttp = ">=3.12.15" +bcrypt = "*" +portalocker = ">=2.8" +nostr-sdk = ">=0.43" +websocket-client = "1.7.0" +websockets = ">=15.0.0" +tomli = "*" +pgpy = "0.6.0" +pyotp = ">=2.8.0" +pyperclip = "*" +qrcode = ">=8.2" +typer = ">=0.12.3" +fastapi = ">=0.116.0" +uvicorn = ">=0.35.0" +httpx = ">=0.28.1" +requests = ">=2.32" +python-multipart = ">=0.0.20" +orjson = "*" +argon2-cffi = "*" +PyJWT = ">=2.8.0" +slowapi = "^0.1.9" +toga-core = { version = ">=0.5.2", optional = true } +pillow = { version = "*", optional = true } +toga-gtk = { version = ">=0.5.2", optional = true } +toga-winforms = { version = ">=0.5.2", optional = true } +toga-cocoa = { version = ">=0.5.2", optional = true } -[project.scripts] +[tool.poetry.extras] +gui = ["toga-core", "pillow"] +gui-gtk = ["toga-gtk"] +gui-win = ["toga-winforms"] +gui-mac = ["toga-cocoa"] + +[tool.poetry.group.dev.dependencies] +pytest = "^8.2" +coverage = "^7.5" +black = "^24.3" +pip-audit = "^2.7" +pytest-xdist = "^3.5" +hypothesis = "^6.98" +freezegun = "^1.5" +toga-dummy = ">=0.5.2" +Pillow = "^10.4" + +[tool.poetry.scripts] seedpass = "seedpass.cli:app" seedpass-gui = "seedpass_gui.app:main" @@ -15,10 +66,15 @@ python_version = "3.11" strict = true mypy_path = "src" +[tool.briefcase] +project_name = "SeedPass" +bundle = "io.seedpass" +version = "0.1.0" + [tool.briefcase.app.seedpass-gui] formal-name = "SeedPass" description = "Deterministic password manager with a BeeWare GUI" -sources = ["src"] +sources = ["src/seedpass_gui"] requires = [ "toga-core>=0.5.2", "colorama>=0.4.6", @@ -28,7 +84,7 @@ requires = [ "bech32==1.2.0", "coincurve>=18.0.0", "mnemonic", - "aiohttp>=3.12.14", + "aiohttp>=3.12.15", "bcrypt", "portalocker>=2.8", "nostr-sdk>=0.43", @@ -44,8 +100,14 @@ requires = [ "uvicorn>=0.35.0", "httpx>=0.28.1", "requests>=2.32", - "python-multipart", + "python-multipart>=0.0.20", "orjson", "argon2-cffi", ] icon = "logo/png/SeedPass-Logo-24.png" +license = { file = "LICENSE" } + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + diff --git a/pytest.ini b/pytest.ini index 25e1f5c2..70fcd4fb 100644 --- a/pytest.ini +++ b/pytest.ini @@ -3,7 +3,7 @@ addopts = -n auto log_cli = true log_cli_level = WARNING log_level = WARNING -testpaths = src/tests +testpaths = src/tests tests markers = network: tests that require network connectivity stress: long running stress tests diff --git a/requirements.lock b/requirements.lock index 2962cf13..24efcbff 100644 --- a/requirements.lock +++ b/requirements.lock @@ -1,70 +1,1978 @@ -aiohappyeyeballs==2.6.1 -aiohttp==3.12.14 -aiosignal==1.4.0 -attrs==25.3.0 -argon2-cffi==23.1.0 -base58==2.1.1 -bcrypt==4.3.0 -bech32==1.2.0 -bip-utils==2.9.3 -cbor2==5.6.5 -certifi==2025.6.15 -cffi==1.17.1 -charset-normalizer==3.4.2 -click==8.2.1 -coincurve==21.0.0 -colorama==0.4.6 -coverage==7.9.1 -crcmod==1.7 -cryptography==45.0.4 -ecdsa==0.19.1 -ed25519-blake2b==1.4.1 -execnet==2.1.1 -fastapi==0.116.1 -frozenlist==1.7.0 -glob2==0.7 -hypothesis==6.135.20 -idna==3.10 -iniconfig==2.1.0 -ipaddress==1.0.23 -junit-xml==1.9 -mnemonic==0.21 -monero==1.1.1 -multidict==6.6.3 -mutmut==2.4.4 -nostr-sdk==0.43.0 -orjson==3.10.18 -packaging==25.0 -parso==0.8.4 -pgpy==0.6.0 -pluggy==1.6.0 -pony==0.7.19 -portalocker==3.2.0 -propcache==0.3.2 -py-sr25519-bindings==0.2.2 -pycoin==0.92.20241201 -pycparser==2.22 -pycryptodome==3.23.0 -pycryptodomex==3.23.0 -pyperclip==1.9.0 -Pygments==2.19.2 -PyNaCl==1.5.0 -PySocks==1.7.1 -pytest==8.4.1 -pytest-cov==6.2.1 -pytest-xdist==3.8.0 -requests==2.32.4 -six==1.17.0 -sortedcontainers==2.4.0 -termcolor==3.1.0 -toml==0.10.2 -tomli==2.2.1 -urllib3==2.5.0 -uvicorn==0.35.0 -starlette==0.47.2 -httpx==0.28.1 -varint==1.0.2 -websocket-client==1.7.0 -websockets==15.0.1 -yarl==1.20.1 -typer==0.12.3 +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile --generate-hashes --output-file=requirements.lock src/requirements.txt +# +aiohappyeyeballs==2.6.1 \ + --hash=sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558 \ + --hash=sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8 + # via aiohttp +aiohttp==3.12.15 \ + --hash=sha256:010cc9bbd06db80fe234d9003f67e97a10fe003bfbedb40da7d71c1008eda0fe \ + --hash=sha256:049ec0360f939cd164ecbfd2873eaa432613d5e77d6b04535e3d1fbae5a9e645 \ + --hash=sha256:098e92835b8119b54c693f2f88a1dec690e20798ca5f5fe5f0520245253ee0af \ + --hash=sha256:0a146708808c9b7a988a4af3821379e379e0f0e5e466ca31a73dbdd0325b0263 \ + --hash=sha256:0a23918fedc05806966a2438489dcffccbdf83e921a1170773b6178d04ade142 \ + --hash=sha256:0c643f4d75adea39e92c0f01b3fb83d57abdec8c9279b3078b68a3a52b3933b6 \ + --hash=sha256:1004e67962efabbaf3f03b11b4c43b834081c9e3f9b32b16a7d97d4708a9abe6 \ + --hash=sha256:14954a2988feae3987f1eb49c706bff39947605f4b6fa4027c1d75743723eb09 \ + --hash=sha256:1a649001580bdb37c6fdb1bebbd7e3bc688e8ec2b5c6f52edbb664662b17dc84 \ + --hash=sha256:2776c7ec89c54a47029940177e75c8c07c29c66f73464784971d6a81904ce9d1 \ + --hash=sha256:2abbb216a1d3a2fe86dbd2edce20cdc5e9ad0be6378455b05ec7f77361b3ab50 \ + --hash=sha256:2c7d81a277fa78b2203ab626ced1487420e8c11a8e373707ab72d189fcdad20a \ + --hash=sha256:2ce13fcfb0bb2f259fb42106cdc63fa5515fb85b7e87177267d89a771a660b79 \ + --hash=sha256:2e5a495cb1be69dae4b08f35a6c4579c539e9b5706f606632102c0f855bcba7c \ + --hash=sha256:2ee8a8ac39ce45f3e55663891d4b1d15598c157b4d494a4613e704c8b43112cd \ + --hash=sha256:3b6f0af863cf17e6222b1735a756d664159e58855da99cfe965134a3ff63b0b0 \ + --hash=sha256:3bdd6e17e16e1dbd3db74d7f989e8af29c4d2e025f9828e6ef45fbdee158ec75 \ + --hash=sha256:3beb14f053222b391bf9cf92ae82e0171067cc9c8f52453a0f1ec7c37df12a77 \ + --hash=sha256:3c5092ce14361a73086b90c6efb3948ffa5be2f5b6fbcf52e8d8c8b8848bb97c \ + --hash=sha256:3ead1c00f8521a5c9070fcb88f02967b1d8a0544e6d85c253f6968b785e1a2ab \ + --hash=sha256:3eae49032c29d356b94eee45a3f39fdf4b0814b397638c2f718e96cfadf4c4e4 \ + --hash=sha256:3f9d7c55b41ed687b9d7165b17672340187f87a773c98236c987f08c858145a9 \ + --hash=sha256:40b3fee496a47c3b4a39a731954c06f0bd9bd3e8258c059a4beb76ac23f8e421 \ + --hash=sha256:421da6fd326460517873274875c6c5a18ff225b40da2616083c5a34a7570b685 \ + --hash=sha256:4420cf9d179ec8dfe4be10e7d0fe47d6d606485512ea2265b0d8c5113372771b \ + --hash=sha256:46749be6e89cd78d6068cdf7da51dbcfa4321147ab8e4116ee6678d9a056a0cf \ + --hash=sha256:47f6b962246f0a774fbd3b6b7be25d59b06fdb2f164cf2513097998fc6a29693 \ + --hash=sha256:4c39e87afe48aa3e814cac5f535bc6199180a53e38d3f51c5e2530f5aa4ec58c \ + --hash=sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2 \ + --hash=sha256:5015082477abeafad7203757ae44299a610e89ee82a1503e3d4184e6bafdd519 \ + --hash=sha256:5346b93e62ab51ee2a9d68e8f73c7cf96ffb73568a23e683f931e52450e4148d \ + --hash=sha256:536ad7234747a37e50e7b6794ea868833d5220b49c92806ae2d7e8a9d6b5de02 \ + --hash=sha256:56822ff5ddfd1b745534e658faba944012346184fbfe732e0d6134b744516eea \ + --hash=sha256:57d16590a351dfc914670bd72530fd78344b885a00b250e992faea565b7fdc05 \ + --hash=sha256:5fa5d9eb82ce98959fc1031c28198b431b4d9396894f385cb63f1e2f3f20ca6b \ + --hash=sha256:6404dfc8cdde35c69aaa489bb3542fb86ef215fc70277c892be8af540e5e21c0 \ + --hash=sha256:6443cca89553b7a5485331bc9bedb2342b08d073fa10b8c7d1c60579c4a7b9bd \ + --hash=sha256:691d203c2bdf4f4637792efbbcdcd157ae11e55eaeb5e9c360c1206fb03d4d98 \ + --hash=sha256:6990ef617f14450bc6b34941dba4f12d5613cbf4e33805932f853fbd1cf18bfb \ + --hash=sha256:6c5f40ec615e5264f44b4282ee27628cea221fcad52f27405b80abb346d9f3f8 \ + --hash=sha256:6d86a2fbdd14192e2f234a92d3b494dd4457e683ba07e5905a0b3ee25389ac9f \ + --hash=sha256:74bdd8c864b36c3673741023343565d95bfbd778ffe1eb4d412c135a28a8dc89 \ + --hash=sha256:74dad41b3458dbb0511e760fb355bb0b6689e0630de8a22b1b62a98777136e16 \ + --hash=sha256:760fb7db442f284996e39cf9915a94492e1896baac44f06ae551974907922b64 \ + --hash=sha256:79b26fe467219add81d5e47b4a4ba0f2394e8b7c7c3198ed36609f9ba161aecb \ + --hash=sha256:7c7dd29c7b5bda137464dc9bfc738d7ceea46ff70309859ffde8c022e9b08ba7 \ + --hash=sha256:7fbc8a7c410bb3ad5d595bb7118147dfbb6449d862cc1125cf8867cb337e8728 \ + --hash=sha256:802d3868f5776e28f7bf69d349c26fc0efadb81676d0afa88ed00d98a26340b7 \ + --hash=sha256:83603f881e11f0f710f8e2327817c82e79431ec976448839f3cd05d7afe8f830 \ + --hash=sha256:8466151554b593909d30a0a125d638b4e5f3836e5aecde85b66b80ded1cb5b0d \ + --hash=sha256:86ceded4e78a992f835209e236617bffae649371c4a50d5e5a3987f237db84b8 \ + --hash=sha256:894261472691d6fe76ebb7fcf2e5870a2ac284c7406ddc95823c8598a1390f0d \ + --hash=sha256:8e995e1abc4ed2a454c731385bf4082be06f875822adc4c6d9eaadf96e20d406 \ + --hash=sha256:8faa08fcc2e411f7ab91d1541d9d597d3a90e9004180edb2072238c085eac8c2 \ + --hash=sha256:9b2af240143dd2765e0fb661fd0361a1b469cab235039ea57663cda087250ea9 \ + --hash=sha256:9f922ffd05034d439dde1c77a20461cf4a1b0831e6caa26151fe7aa8aaebc315 \ + --hash=sha256:a041e7e2612041a6ddf1c6a33b883be6a421247c7afd47e885969ee4cc58bd8d \ + --hash=sha256:aaa2234bb60c4dbf82893e934d8ee8dea30446f0647e024074237a56a08c01bd \ + --hash=sha256:ac77f709a2cde2cc71257ab2d8c74dd157c67a0558a0d2799d5d571b4c63d44d \ + --hash=sha256:ad702e57dc385cae679c39d318def49aef754455f237499d5b99bea4ef582e51 \ + --hash=sha256:b2acbbfff69019d9014508c4ba0401822e8bae5a5fdc3b6814285b71231b60f3 \ + --hash=sha256:b390ef5f62bb508a9d67cb3bba9b8356e23b3996da7062f1a57ce1a79d2b3d34 \ + --hash=sha256:b52dcf013b57464b6d1e51b627adfd69a8053e84b7103a7cd49c030f9ca44461 \ + --hash=sha256:b5b7fe4972d48a4da367043b8e023fb70a04d1490aa7d68800e465d1b97e493b \ + --hash=sha256:b6fc902bff74d9b1879ad55f5404153e2b33a82e72a95c89cec5eb6cc9e92fbc \ + --hash=sha256:b7011a70b56facde58d6d26da4fec3280cc8e2a78c714c96b7a01a87930a9530 \ + --hash=sha256:b761bac1192ef24e16706d761aefcb581438b34b13a2f069a6d343ec8fb693a5 \ + --hash=sha256:b784d6ed757f27574dca1c336f968f4e81130b27595e458e69457e6878251f5d \ + --hash=sha256:b97752ff12cc12f46a9b20327104448042fce5c33a624f88c18f66f9368091c7 \ + --hash=sha256:bc4fbc61bb3548d3b482f9ac7ddd0f18c67e4225aaa4e8552b9f1ac7e6bda9e5 \ + --hash=sha256:bc9a0f6569ff990e0bbd75506c8d8fe7214c8f6579cca32f0546e54372a3bb54 \ + --hash=sha256:bd44d5936ab3193c617bfd6c9a7d8d1085a8dc8c3f44d5f1dcf554d17d04cf7d \ + --hash=sha256:ced339d7c9b5030abad5854aa5413a77565e5b6e6248ff927d3e174baf3badf7 \ + --hash=sha256:d3ce17ce0220383a0f9ea07175eeaa6aa13ae5a41f30bc61d84df17f0e9b1117 \ + --hash=sha256:d5f1b4ce5bc528a6ee38dbf5f39bbf11dd127048726323b72b8e85769319ffc4 \ + --hash=sha256:d849b0901b50f2185874b9a232f38e26b9b3d4810095a7572eacea939132d4e1 \ + --hash=sha256:db71ce547012a5420a39c1b744d485cfb823564d01d5d20805977f5ea1345676 \ + --hash=sha256:e153e8adacfe2af562861b72f8bc47f8a5c08e010ac94eebbe33dc21d677cd5b \ + --hash=sha256:edd533a07da85baa4b423ee8839e3e91681c7bfa19b04260a469ee94b778bf6d \ + --hash=sha256:f0adb4177fa748072546fb650d9bd7398caaf0e15b370ed3317280b13f4083b0 \ + --hash=sha256:f0fa751efb11a541f57db59c1dd821bec09031e01452b2b6217319b3a1f34f3d \ + --hash=sha256:f2800614cd560287be05e33a679638e586a2d7401f4ddf99e304d98878c29444 \ + --hash=sha256:f813c3e9032331024de2eb2e32a88d86afb69291fbc37a3a3ae81cc9917fb3d0 \ + --hash=sha256:fc49c4de44977aa8601a00edbf157e9a421f227aa7eb477d9e3df48343311065 \ + --hash=sha256:fd736ed420f4db2b8148b52b46b88ed038d0354255f9a73196b7bbce3ea97545 \ + --hash=sha256:fe086edf38b2222328cdf89af0dde2439ee173b8ad7cb659b4e4c6f385b2be3d + # via -r src/requirements.txt +aiosignal==1.4.0 \ + --hash=sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e \ + --hash=sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7 + # via aiohttp +annotated-types==0.7.0 \ + --hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \ + --hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89 + # via pydantic +anyio==4.9.0 \ + --hash=sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028 \ + --hash=sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c + # via + # httpx + # starlette +argon2-cffi==25.1.0 \ + --hash=sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1 \ + --hash=sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741 + # via -r src/requirements.txt +argon2-cffi-bindings==25.1.0 \ + --hash=sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99 \ + --hash=sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6 \ + --hash=sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d \ + --hash=sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44 \ + --hash=sha256:3c6702abc36bf3ccba3f802b799505def420a1b7039862014a65db3205967f5a \ + --hash=sha256:3d3f05610594151994ca9ccb3c771115bdb4daef161976a266f0dd8aa9996b8f \ + --hash=sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2 \ + --hash=sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690 \ + --hash=sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584 \ + --hash=sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e \ + --hash=sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0 \ + --hash=sha256:84a461d4d84ae1295871329b346a97f68eade8c53b6ed9a7ca2d7467f3c8ff6f \ + --hash=sha256:87c33a52407e4c41f3b70a9c2d3f6056d88b10dad7695be708c5021673f55623 \ + --hash=sha256:8b8efee945193e667a396cbc7b4fb7d357297d6234d30a489905d96caabde56b \ + --hash=sha256:a1c70058c6ab1e352304ac7e3b52554daadacd8d453c1752e547c76e9c99ac44 \ + --hash=sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98 \ + --hash=sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500 \ + --hash=sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94 \ + --hash=sha256:b55aec3565b65f56455eebc9b9f34130440404f27fe21c3b375bf1ea4d8fbae6 \ + --hash=sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d \ + --hash=sha256:ba92837e4a9aa6a508c8d2d7883ed5a8f6c308c89a4790e1e447a220deb79a85 \ + --hash=sha256:c4f9665de60b1b0e99bcd6be4f17d90339698ce954cfd8d9cf4f91c995165a92 \ + --hash=sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d \ + --hash=sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a \ + --hash=sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520 \ + --hash=sha256:e2fd3bfbff3c5d74fef31a722f729bf93500910db650c925c2d6ef879a7e51cb + # via argon2-cffi +attrs==25.3.0 \ + --hash=sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3 \ + --hash=sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b + # via + # aiohttp + # hypothesis +bcrypt==4.3.0 \ + --hash=sha256:0042b2e342e9ae3d2ed22727c1262f76cc4f345683b5c1715f0250cf4277294f \ + --hash=sha256:0142b2cb84a009f8452c8c5a33ace5e3dfec4159e7735f5afe9a4d50a8ea722d \ + --hash=sha256:08bacc884fd302b611226c01014eca277d48f0a05187666bca23aac0dad6fe24 \ + --hash=sha256:0d3efb1157edebfd9128e4e46e2ac1a64e0c1fe46fb023158a407c7892b0f8c3 \ + --hash=sha256:0e30e5e67aed0187a1764911af023043b4542e70a7461ad20e837e94d23e1d6c \ + --hash=sha256:107d53b5c67e0bbc3f03ebf5b030e0403d24dda980f8e244795335ba7b4a027d \ + --hash=sha256:12fa6ce40cde3f0b899729dbd7d5e8811cb892d31b6f7d0334a1f37748b789fd \ + --hash=sha256:17a854d9a7a476a89dcef6c8bd119ad23e0f82557afbd2c442777a16408e614f \ + --hash=sha256:191354ebfe305e84f344c5964c7cd5f924a3bfc5d405c75ad07f232b6dffb49f \ + --hash=sha256:2ef6630e0ec01376f59a006dc72918b1bf436c3b571b80fa1968d775fa02fe7d \ + --hash=sha256:3004df1b323d10021fda07a813fd33e0fd57bef0e9a480bb143877f6cba996fe \ + --hash=sha256:335a420cfd63fc5bc27308e929bee231c15c85cc4c496610ffb17923abf7f231 \ + --hash=sha256:33752b1ba962ee793fa2b6321404bf20011fe45b9afd2a842139de3011898fef \ + --hash=sha256:3a3fd2204178b6d2adcf09cb4f6426ffef54762577a7c9b54c159008cb288c18 \ + --hash=sha256:3b8d62290ebefd49ee0b3ce7500f5dbdcf13b81402c05f6dafab9a1e1b27212f \ + --hash=sha256:3e36506d001e93bffe59754397572f21bb5dc7c83f54454c990c74a468cd589e \ + --hash=sha256:41261d64150858eeb5ff43c753c4b216991e0ae16614a308a15d909503617732 \ + --hash=sha256:50e6e80a4bfd23a25f5c05b90167c19030cf9f87930f7cb2eacb99f45d1c3304 \ + --hash=sha256:531457e5c839d8caea9b589a1bcfe3756b0547d7814e9ce3d437f17da75c32b0 \ + --hash=sha256:55a935b8e9a1d2def0626c4269db3fcd26728cbff1e84f0341465c31c4ee56d8 \ + --hash=sha256:57967b7a28d855313a963aaea51bf6df89f833db4320da458e5b3c5ab6d4c938 \ + --hash=sha256:584027857bc2843772114717a7490a37f68da563b3620f78a849bcb54dc11e62 \ + --hash=sha256:59e1aa0e2cd871b08ca146ed08445038f42ff75968c7ae50d2fdd7860ade2180 \ + --hash=sha256:5bd3cca1f2aa5dbcf39e2aa13dd094ea181f48959e1071265de49cc2b82525af \ + --hash=sha256:5c1949bf259a388863ced887c7861da1df681cb2388645766c89fdfd9004c669 \ + --hash=sha256:62f26585e8b219cdc909b6a0069efc5e4267e25d4a3770a364ac58024f62a761 \ + --hash=sha256:67a561c4d9fb9465ec866177e7aebcad08fe23aaf6fbd692a6fab69088abfc51 \ + --hash=sha256:6fb1fd3ab08c0cbc6826a2e0447610c6f09e983a281b919ed721ad32236b8b23 \ + --hash=sha256:74a8d21a09f5e025a9a23e7c0fd2c7fe8e7503e4d356c0a2c1486ba010619f09 \ + --hash=sha256:79e70b8342a33b52b55d93b3a59223a844962bef479f6a0ea318ebbcadf71505 \ + --hash=sha256:7a4be4cbf241afee43f1c3969b9103a41b40bcb3a3f467ab19f891d9bc4642e4 \ + --hash=sha256:7c03296b85cb87db865d91da79bf63d5609284fc0cab9472fdd8367bbd830753 \ + --hash=sha256:842d08d75d9fe9fb94b18b071090220697f9f184d4547179b60734846461ed59 \ + --hash=sha256:864f8f19adbe13b7de11ba15d85d4a428c7e2f344bac110f667676a0ff84924b \ + --hash=sha256:97eea7408db3a5bcce4a55d13245ab3fa566e23b4c67cd227062bb49e26c585d \ + --hash=sha256:a839320bf27d474e52ef8cb16449bb2ce0ba03ca9f44daba6d93fa1d8828e48a \ + --hash=sha256:afe327968aaf13fc143a56a3360cb27d4ad0345e34da12c7290f1b00b8fe9a8b \ + --hash=sha256:b4d4e57f0a63fd0b358eb765063ff661328f69a04494427265950c71b992a39a \ + --hash=sha256:b6354d3760fcd31994a14c89659dee887f1351a06e5dac3c1142307172a79f90 \ + --hash=sha256:b693dbb82b3c27a1604a3dff5bfc5418a7e6a781bb795288141e5f80cf3a3492 \ + --hash=sha256:bdc6a24e754a555d7316fa4774e64c6c3997d27ed2d1964d55920c7c227bc4ce \ + --hash=sha256:beeefe437218a65322fbd0069eb437e7c98137e08f22c4660ac2dc795c31f8bb \ + --hash=sha256:c5eeac541cefd0bb887a371ef73c62c3cd78535e4887b310626036a7c0a817bb \ + --hash=sha256:c950d682f0952bafcceaf709761da0a32a942272fad381081b51096ffa46cea1 \ + --hash=sha256:d9af79d322e735b1fc33404b5765108ae0ff232d4b54666d46730f8ac1a43676 \ + --hash=sha256:e53e074b120f2877a35cc6c736b8eb161377caae8925c17688bd46ba56daaa5b \ + --hash=sha256:e965a9c1e9a393b8005031ff52583cedc15b7884fce7deb8b0346388837d6cfe \ + --hash=sha256:f01e060f14b6b57bbb72fc5b4a83ac21c443c9a2ee708e04a10e9192f90a6281 \ + --hash=sha256:f1e3ffa1365e8702dc48c8b360fef8d7afeca482809c5e45e653af82ccd088c1 \ + --hash=sha256:f6746e6fec103fcd509b96bacdfdaa2fbde9a553245dbada284435173a6f1aef \ + --hash=sha256:f81b0ed2639568bf14749112298f9e4e2b28853dab50a8b357e31798686a036d + # via -r src/requirements.txt +bech32==1.2.0 \ + --hash=sha256:7d6db8214603bd7871fcfa6c0826ef68b85b0abd90fa21c285a9c5e21d2bd899 \ + --hash=sha256:990dc8e5a5e4feabbdf55207b5315fdd9b73db40be294a19b3752cde9e79d981 + # via -r src/requirements.txt +bip-utils==2.9.3 \ + --hash=sha256:72a8c95484b57e92311b0b2a3d5195b0ce4395c19a0b157d4a289e8b1300f48a \ + --hash=sha256:ee26b8417a576c7f89b847da37316db01a5cece1994c1609d37fbeefb91ad45e + # via -r src/requirements.txt +cbor2==5.6.5 \ + --hash=sha256:3038523b8fc7de312bb9cdcbbbd599987e64307c4db357cd2030c472a6c7d468 \ + --hash=sha256:34cf5ab0dc310c3d0196caa6ae062dc09f6c242e2544bea01691fe60c0230596 \ + --hash=sha256:37096663a5a1c46a776aea44906cbe5fa3952f29f50f349179c00525d321c862 \ + --hash=sha256:38886c41bebcd7dca57739439455bce759f1e4c551b511f618b8e9c1295b431b \ + --hash=sha256:3d1a18b3a58dcd9b40ab55c726160d4a6b74868f2a35b71f9e726268b46dc6a2 \ + --hash=sha256:4586a4f65546243096e56a3f18f29d60752ee9204722377021b3119a03ed99ff \ + --hash=sha256:47261f54a024839ec649b950013c4de5b5f521afe592a2688eebbe22430df1dc \ + --hash=sha256:54c72a3207bb2d4480c2c39dad12d7971ce0853a99e3f9b8d559ce6eac84f66f \ + --hash=sha256:559dcf0d897260a9e95e7b43556a62253e84550b77147a1ad4d2c389a2a30192 \ + --hash=sha256:5b856fda4c50c5bc73ed3664e64211fa4f015970ed7a15a4d6361bd48462feaf \ + --hash=sha256:5ce13a27ef8fddf643fc17a753fe34aa72b251d03c23da6a560c005dc171085b \ + --hash=sha256:5cff06464b8f4ca6eb9abcba67bda8f8334a058abc01005c8e616728c387ad32 \ + --hash=sha256:61ceb77e6aa25c11c814d4fe8ec9e3bac0094a1f5bd8a2a8c95694596ea01e08 \ + --hash=sha256:66dd25dd919cddb0b36f97f9ccfa51947882f064729e65e6bef17c28535dc459 \ + --hash=sha256:6797b824b26a30794f2b169c0575301ca9b74ae99064e71d16e6ba0c9057de51 \ + --hash=sha256:6e14a1bf6269d25e02ef1d4008e0ce8880aa271d7c6b4c329dba48645764f60e \ + --hash=sha256:73b9647eed1493097db6aad61e03d8f1252080ee041a1755de18000dd2c05f37 \ + --hash=sha256:7488aec919f8408f9987a3a32760bd385d8628b23a35477917aa3923ff6ad45f \ + --hash=sha256:7f6d69f38f7d788b04c09ef2b06747536624b452b3c8b371ab78ad43b0296fab \ + --hash=sha256:824f202b556fc204e2e9a67d6d6d624e150fbd791278ccfee24e68caec578afd \ + --hash=sha256:863e0983989d56d5071270790e7ed8ddbda88c9e5288efdb759aba2efee670bc \ + --hash=sha256:87026fc838370d69f23ed8572939bd71cea2b3f6c8f8bb8283f573374b4d7f33 \ + --hash=sha256:8f747b7a9aaa58881a0c5b4cd4a9b8fb27eca984ed261a769b61de1f6b5bd1e6 \ + --hash=sha256:90bfa36944caccec963e6ab7e01e64e31cc6664535dc06e6295ee3937c999cbb \ + --hash=sha256:93676af02bd9a0b4a62c17c5b20f8e9c37b5019b1a24db70a2ee6cb770423568 \ + --hash=sha256:94885903105eec66d7efb55f4ce9884fdc5a4d51f3bd75b6fedc68c5c251511b \ + --hash=sha256:97a7e409b864fecf68b2ace8978eb5df1738799a333ec3ea2b9597bfcdd6d7d2 \ + --hash=sha256:a34ee99e86b17444ecbe96d54d909dd1a20e2da9f814ae91b8b71cf1ee2a95e4 \ + --hash=sha256:a3ac50485cf67dfaab170a3e7b527630e93cb0a6af8cdaa403054215dff93adf \ + --hash=sha256:a83b76367d1c3e69facbcb8cdf65ed6948678e72f433137b41d27458aa2a40cb \ + --hash=sha256:a88f029522aec5425fc2f941b3df90da7688b6756bd3f0472ab886d21208acbd \ + --hash=sha256:a8947c102cac79d049eadbd5e2ffb8189952890df7cbc3ee262bbc2f95b011a9 \ + --hash=sha256:ae2b49226224e92851c333b91d83292ec62eba53a19c68a79890ce35f1230d70 \ + --hash=sha256:b682820677ee1dbba45f7da11898d2720f92e06be36acec290867d5ebf3d7e09 \ + --hash=sha256:b9d15b638539b68aa5d5eacc56099b4543a38b2d2c896055dccf7e83d24b7955 \ + --hash=sha256:e16c4a87fc999b4926f5c8f6c696b0d251b4745bc40f6c5aee51d69b30b15ca2 \ + --hash=sha256:e25c2aebc9db99af7190e2261168cdde8ed3d639ca06868e4f477cf3a228a8e9 \ + --hash=sha256:f0d0a9c5aabd48ecb17acf56004a7542a0b8d8212be52f3102b8218284bd881e \ + --hash=sha256:f2764804ffb6553283fc4afb10a280715905a4cea4d6dc7c90d3e89c4a93bc8d \ + --hash=sha256:f4c7dbcdc59ea7f5a745d3e30ee5e6b6ff5ce7ac244aa3de6786391b10027bb3 \ + --hash=sha256:f91e6d74fa6917df31f8757fdd0e154203b0dd0609ec53eb957016a2b474896a \ + --hash=sha256:fa61a02995f3a996c03884cf1a0b5733f88cbfd7fa0e34944bf678d4227ee712 \ + --hash=sha256:fde21ac1cf29336a31615a2c469a9cb03cf0add3ae480672d4d38cda467d07fc \ + --hash=sha256:fe11c2eb518c882cfbeed456e7a552e544893c17db66fe5d3230dbeaca6b615c + # via bip-utils +certifi==2025.8.3 \ + --hash=sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407 \ + --hash=sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5 + # via + # httpcore + # httpx + # requests +cffi==1.17.1 \ + --hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \ + --hash=sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2 \ + --hash=sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1 \ + --hash=sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15 \ + --hash=sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36 \ + --hash=sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824 \ + --hash=sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8 \ + --hash=sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36 \ + --hash=sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17 \ + --hash=sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf \ + --hash=sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc \ + --hash=sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3 \ + --hash=sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed \ + --hash=sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702 \ + --hash=sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1 \ + --hash=sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8 \ + --hash=sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903 \ + --hash=sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6 \ + --hash=sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d \ + --hash=sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b \ + --hash=sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e \ + --hash=sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be \ + --hash=sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c \ + --hash=sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683 \ + --hash=sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9 \ + --hash=sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c \ + --hash=sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8 \ + --hash=sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1 \ + --hash=sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4 \ + --hash=sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655 \ + --hash=sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67 \ + --hash=sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595 \ + --hash=sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0 \ + --hash=sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65 \ + --hash=sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41 \ + --hash=sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6 \ + --hash=sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401 \ + --hash=sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6 \ + --hash=sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3 \ + --hash=sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16 \ + --hash=sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93 \ + --hash=sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e \ + --hash=sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4 \ + --hash=sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964 \ + --hash=sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c \ + --hash=sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576 \ + --hash=sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0 \ + --hash=sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3 \ + --hash=sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662 \ + --hash=sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3 \ + --hash=sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff \ + --hash=sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5 \ + --hash=sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd \ + --hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \ + --hash=sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5 \ + --hash=sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14 \ + --hash=sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d \ + --hash=sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9 \ + --hash=sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7 \ + --hash=sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382 \ + --hash=sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a \ + --hash=sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e \ + --hash=sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a \ + --hash=sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4 \ + --hash=sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99 \ + --hash=sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87 \ + --hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b + # via + # argon2-cffi-bindings + # cryptography + # pynacl +charset-normalizer==3.4.2 \ + --hash=sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4 \ + --hash=sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45 \ + --hash=sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7 \ + --hash=sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0 \ + --hash=sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7 \ + --hash=sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d \ + --hash=sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d \ + --hash=sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0 \ + --hash=sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184 \ + --hash=sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db \ + --hash=sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b \ + --hash=sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64 \ + --hash=sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b \ + --hash=sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8 \ + --hash=sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff \ + --hash=sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344 \ + --hash=sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58 \ + --hash=sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e \ + --hash=sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471 \ + --hash=sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148 \ + --hash=sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a \ + --hash=sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836 \ + --hash=sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e \ + --hash=sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63 \ + --hash=sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c \ + --hash=sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1 \ + --hash=sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01 \ + --hash=sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366 \ + --hash=sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58 \ + --hash=sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5 \ + --hash=sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c \ + --hash=sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2 \ + --hash=sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a \ + --hash=sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597 \ + --hash=sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b \ + --hash=sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5 \ + --hash=sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb \ + --hash=sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f \ + --hash=sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0 \ + --hash=sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941 \ + --hash=sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0 \ + --hash=sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86 \ + --hash=sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7 \ + --hash=sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7 \ + --hash=sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455 \ + --hash=sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6 \ + --hash=sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4 \ + --hash=sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0 \ + --hash=sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3 \ + --hash=sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1 \ + --hash=sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6 \ + --hash=sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981 \ + --hash=sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c \ + --hash=sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980 \ + --hash=sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645 \ + --hash=sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7 \ + --hash=sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12 \ + --hash=sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa \ + --hash=sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd \ + --hash=sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef \ + --hash=sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f \ + --hash=sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2 \ + --hash=sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d \ + --hash=sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5 \ + --hash=sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02 \ + --hash=sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3 \ + --hash=sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd \ + --hash=sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e \ + --hash=sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214 \ + --hash=sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd \ + --hash=sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a \ + --hash=sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c \ + --hash=sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681 \ + --hash=sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba \ + --hash=sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f \ + --hash=sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a \ + --hash=sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28 \ + --hash=sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691 \ + --hash=sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82 \ + --hash=sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a \ + --hash=sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027 \ + --hash=sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7 \ + --hash=sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518 \ + --hash=sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf \ + --hash=sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b \ + --hash=sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9 \ + --hash=sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544 \ + --hash=sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da \ + --hash=sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509 \ + --hash=sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f \ + --hash=sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a \ + --hash=sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f + # via requests +click==8.2.1 \ + --hash=sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202 \ + --hash=sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b + # via + # mutmut + # typer + # uvicorn +coincurve==21.0.0 \ + --hash=sha256:05d7e255a697b3475d7ae7640d3bdef3d5bc98ce9ce08dd387f780696606c33b \ + --hash=sha256:070e060d0d57b496e68e48b39d5e3245681376d122827cb8e09f33669ff8cf1b \ + --hash=sha256:07cda058d9394bea30d57a92fdc18ee3ca6b5bc8ef776a479a2ffec917105836 \ + --hash=sha256:154467858d23c48f9e5ab380433bc2625027b50617400e2984cc16f5799ab601 \ + --hash=sha256:1a1e7ee73bc1b3bcf14c7b0d1f44e6485785d3b53ef7b16173c36d3cefa57f93 \ + --hash=sha256:1b04778b75339c6e46deb9ae3bcfc2250fbe48d1324153e4310fc4996e135715 \ + --hash=sha256:1cb1cd19fb0be22e68ecb60ad950b41f18b9b02eebeffaac9391dc31f74f08f2 \ + --hash=sha256:3bcd538af097b3914ec3cb654262e72e224f95f2e9c1eb7fbd75d843ae4e528e \ + --hash=sha256:3fb03e3a388a93d31ed56a442bdec7983ea404490e21e12af76fb1dbf097082a \ + --hash=sha256:45b6a5e6b5536e1f46f729829d99ce1f8f847308d339e8880fe7fa1646935c10 \ + --hash=sha256:4d2bf350ced38b73db9efa1ff8fd16a67a1cb35abb2dda50d89661b531f03fd3 \ + --hash=sha256:5001de8324c35eee95f34e011a5c3b4e7d9ae9ca4a862a93b2c89b3f467f511b \ + --hash=sha256:500e5e38cd4cbc4ea8a5c631ce843b1d52ef19ac41128568214d150f75f1f387 \ + --hash=sha256:530b58ed570895612ef510e28df5e8a33204b03baefb5c986e22811fa09622ef \ + --hash=sha256:54d9500c56d5499375e579c3917472ffcf804c3584dd79052a79974280985c74 \ + --hash=sha256:54de1cac75182de9f71ce41415faafcaf788303e21cbd0188064e268d61625e5 \ + --hash=sha256:5828cd08eab928db899238874d1aab12fa1236f30fe095a3b7e26a5fc81df0a3 \ + --hash=sha256:5a366c314df7217e3357bb8c7d2cda540b0bce180705f7a0ce2d1d9e28f62ad4 \ + --hash=sha256:5a9b49789ff86f3cf86cfc8ff8c6c43bac2607720ec638e8ba471fa7e8765bd2 \ + --hash=sha256:5dd7b66b83b143f3ad3861a68fc0279167a0bae44fe3931547400b7a200e90b1 \ + --hash=sha256:65ec42cab9c60d587fb6275c71f0ebc580625c377a894c4818fb2a2b583a184b \ + --hash=sha256:669ab5db393637824b226de058bb7ea0cb9a0236e1842d7b22f74d4a8a1f1ff1 \ + --hash=sha256:6df44b4e3b7acdc1453ade52a52e3f8a5b53ecdd5a06bd200f1ec4b4e250f7d9 \ + --hash=sha256:6ec8e859464116a3c90168cd2bd7439527d4b4b5e328b42e3c8e0475f9b0bf71 \ + --hash=sha256:773917f075ec4b94a7a742637d303a3a082616a115c36568eb6c873a8d950d18 \ + --hash=sha256:78dbe439e8cb22389956a4f2f2312813b4bd0531a0b691d4f8e868c7b366555d \ + --hash=sha256:87597cf30dfc05fa74218810776efacf8816813ab9fa6ea1490f94e9f8b15e77 \ + --hash=sha256:88c1e3f6df2f2fbe18152c789a18659ee0429dc604fc77530370c9442395f681 \ + --hash=sha256:8b37ce4265a82bebf0e796e21a769e56fdbf8420411ccbe3fafee4ed75b6a6e5 \ + --hash=sha256:8efcbdcd50cc219989a2662e6c6552f455efc000a15dd6ab3ebf4f9b187f41a3 \ + --hash=sha256:9070804d7c71badfe4f0bf19b728cfe7c70c12e733938ead6b1db37920b745c0 \ + --hash=sha256:986727bba6cf0c5670990358dc6af9a54f8d3e257979b992a9dbd50dd82fa0dc \ + --hash=sha256:997607a952913c6a4bebe86815f458e77a42467b7a75353ccdc16c3336726880 \ + --hash=sha256:9df5ceb5de603b9caf270629996710cf5ed1d43346887bc3895a11258644b65b \ + --hash=sha256:ad05952b6edc593a874df61f1bc79db99d716ec48ba4302d699e14a419fe6f51 \ + --hash=sha256:ad6445f0bb61b3a4404d87a857ddb2a74a642cd4d00810237641aab4d6b1a42f \ + --hash=sha256:b4d0bb5340bcac695731bef51c3e0126f252453e2d1ae7fa1486d90eff978bf6 \ + --hash=sha256:b85b49e192d2ca1a906a7b978bacb55d4dcb297cc2900fbbd9b9180d50878779 \ + --hash=sha256:b992d1b1dac85d7f542d9acbcf245667438839484d7f2b032fd032256bcd778e \ + --hash=sha256:bb82ba677fc7600a3bf200edc98f4f9604c317b18c7b3f0a10784b42686e3a53 \ + --hash=sha256:bcc0831f07cb75b91c35c13b1362e7b9dc76c376b27d01ff577bec52005e22a8 \ + --hash=sha256:c1c584059de61ed16c658e7eae87ee488e81438897dae8fabeec55ef408af474 \ + --hash=sha256:cf67332cc647ef52ef371679c76000f096843ae266ae6df5e81906eb6463186b \ + --hash=sha256:cfdd0938f284fb147aa1723a69f8794273ec673b10856b6e6f5f63fcc99d0c2e \ + --hash=sha256:d09ba4fd9d26b00b06645fcd768c5ad44832a1fa847ebe8fb44970d3204c3cb7 \ + --hash=sha256:d3f017f1491491f3f2c49e5d2d3a471a872d75117bfcb804d1167061c94bd347 \ + --hash=sha256:d4210b35c922b2b36c987a48c0b110ab20e490a2d6a92464ca654cb09e739fcc \ + --hash=sha256:ef81ca24511a808ad0ebdb8fdaf9c5c87f12f935b3d117acccc6520ad671bcce \ + --hash=sha256:f57f07c44d14d939bed289cdeaba4acb986bba9f729a796b6a341eab1661eedc \ + --hash=sha256:f60ad56113f08e8c540bb89f4f35f44d434311433195ffff22893ccfa335070c \ + --hash=sha256:f920af756a98edd738c0cfa431e81e3109aeec6ffd6dffb5ed4f5b5a37aacba8 + # via + # -r src/requirements.txt + # bip-utils +colorama==0.4.6 \ + --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ + --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 + # via -r src/requirements.txt +coverage[toml]==7.10.1 \ + --hash=sha256:042125c89cf74a074984002e165d61fe0e31c7bd40ebb4bbebf07939b5924613 \ + --hash=sha256:083442ecf97d434f0cb3b3e3676584443182653da08b42e965326ba12d6b5f2a \ + --hash=sha256:1217a54cfd79be20512a67ca81c7da3f2163f51bbfd188aab91054df012154f5 \ + --hash=sha256:166d89c57e877e93d8827dac32cedae6b0277ca684c6511497311249f35a280c \ + --hash=sha256:1a108dd78ed185020f66f131c60078f3fae3f61646c28c8bb4edd3fa121fc7fc \ + --hash=sha256:1aadfb06a30c62c2eb82322171fe1f7c288c80ca4156d46af0ca039052814bab \ + --hash=sha256:1c4f679c6b573a5257af6012f167a45be4c749c9925fd44d5178fd641ad8bf72 \ + --hash=sha256:1c86eb388bbd609d15560e7cc0eb936c102b6f43f31cf3e58b4fd9afe28e1372 \ + --hash=sha256:1e0c768b0f9ac5839dac5cf88992a4bb459e488ee8a1f8489af4cb33b1af00f1 \ + --hash=sha256:21eb7d8b45d3700e7c2936a736f732794c47615a20f739f4133d5230a6512a88 \ + --hash=sha256:2348631f049e884839553b9974f0821d39241c6ffb01a418efce434f7eba0fe7 \ + --hash=sha256:283005bb4d98ae33e45f2861cd2cde6a21878661c9ad49697f6951b358a0379b \ + --hash=sha256:2b225a06d227f23f386fdc0eab471506d9e644be699424814acc7d114595495f \ + --hash=sha256:320d86da829b012982b414c7cdda65f5d358d63f764e0e4e54b33097646f39a3 \ + --hash=sha256:37b69226001d8b7de7126cad7366b0778d36777e4d788c66991455ba817c5b41 \ + --hash=sha256:3a7a4d74cb0f5e3334f9aa26af7016ddb94fb4bfa11b4a573d8e98ecba8c34f1 \ + --hash=sha256:3beb76e20b28046989300c4ea81bf690df84ee98ade4dc0bbbf774a28eb98440 \ + --hash=sha256:3e31dfb8271937cab9425f19259b1b1d1f556790e98eb266009e7a61d337b6d4 \ + --hash=sha256:3e59d00830da411a1feef6ac828b90bbf74c9b6a8e87b8ca37964925bba76dbe \ + --hash=sha256:4072b31361b0d6d23f750c524f694e1a417c1220a30d3ef02741eed28520c48e \ + --hash=sha256:40f9a38676f9c073bf4b9194707aa1eb97dca0e22cc3766d83879d72500132c7 \ + --hash=sha256:47ab6dbbc31a14c5486420c2c1077fcae692097f673cf5be9ddbec8cdaa4cdbc \ + --hash=sha256:47c91f32ba4ac46f1e224a7ebf3f98b4b24335bad16137737fe71a5961a0665c \ + --hash=sha256:4fcfe294f95b44e4754da5b58be750396f2b1caca8f9a0e78588e3ef85f8b8be \ + --hash=sha256:5121d8cf0eacb16133501455d216bb5f99899ae2f52d394fe45d59229e6611d0 \ + --hash=sha256:51f30da7a52c009667e02f125737229d7d8044ad84b79db454308033a7808ab2 \ + --hash=sha256:51fe93f3fe4f5d8483d51072fddc65e717a175490804e1942c975a68e04bf97a \ + --hash=sha256:57b6e8789cbefdef0667e4a94f8ffa40f9402cee5fc3b8e4274c894737890145 \ + --hash=sha256:590bdba9445df4763bdbebc928d8182f094c1f3947a8dc0fc82ef014dbdd8324 \ + --hash=sha256:5ba9a8770effec5baaaab1567be916c87d8eea0c9ad11253722d86874d885eca \ + --hash=sha256:607f82389f0ecafc565813aa201a5cade04f897603750028dd660fb01797265e \ + --hash=sha256:6b4ba0f488c1bdb6bd9ba81da50715a372119785458831c73428a8566253b86b \ + --hash=sha256:6b7dc7f0a75a7eaa4584e5843c873c561b12602439d2351ee28c7478186c4da4 \ + --hash=sha256:7092cc82382e634075cc0255b0b69cb7cada7c1f249070ace6a95cb0f13548ef \ + --hash=sha256:7718060dd4434cc719803a5e526838a5d66e4efa5dc46d2b25c21965a9c6fcc4 \ + --hash=sha256:780f750a25e7749d0af6b3631759c2c14f45de209f3faaa2398312d1c7a22759 \ + --hash=sha256:7f39edd52c23e5c7ed94e0e4bf088928029edf86ef10b95413e5ea670c5e92d7 \ + --hash=sha256:80b9ccd82e30038b61fc9a692a8dc4801504689651b281ed9109f10cc9fe8b4d \ + --hash=sha256:85b22a9cce00cb03156334da67eb86e29f22b5e93876d0dd6a98646bb8a74e53 \ + --hash=sha256:871ebe8143da284bd77b84a9136200bd638be253618765d21a1fce71006d94af \ + --hash=sha256:89ec0ffc215c590c732918c95cd02b55c7d0f569d76b90bb1a5e78aa340618e4 \ + --hash=sha256:924563481c27941229cb4e16eefacc35da28563e80791b3ddc5597b062a5c386 \ + --hash=sha256:97b6983a2f9c76d345ca395e843a049390b39652984e4a3b45b2442fa733992d \ + --hash=sha256:991196702d5e0b120a8fef2664e1b9c333a81d36d5f6bcf6b225c0cf8b0451a2 \ + --hash=sha256:998c4751dabf7d29b30594af416e4bf5091f11f92a8d88eb1512c7ba136d1ed7 \ + --hash=sha256:9b2df80cb6a2af86d300e70acb82e9b79dab2c1e6971e44b78dbfc1a1e736b53 \ + --hash=sha256:9d6f494c307e5cb9b1e052ec1a471060f1dea092c8116e642e7a23e79d9388ea \ + --hash=sha256:9eb245a8d8dd0ad73b4062135a251ec55086fbc2c42e0eb9725a9b553fba18a3 \ + --hash=sha256:a22c3bfe09f7a530e2c94c87ff7af867259c91bef87ed2089cd69b783af7b84e \ + --hash=sha256:aa309df995d020f3438407081b51ff527171cca6772b33cf8f85344b8b4b8770 \ + --hash=sha256:ab6e19b684981d0cd968906e293d5628e89faacb27977c92f3600b201926b994 \ + --hash=sha256:ac0c5bba938879c2fc0bc6c1b47311b5ad1212a9dcb8b40fe2c8110239b7faed \ + --hash=sha256:ae2b4856f29ddfe827106794f3589949a57da6f0d38ab01e24ec35107979ba57 \ + --hash=sha256:ae8e59e5f4fd85d6ad34c2bb9d74037b5b11be072b8b7e9986beb11f957573d4 \ + --hash=sha256:b2f22102197bcb1722691296f9e589f02b616f874e54a209284dd7b9294b0b7f \ + --hash=sha256:b45e2f9d5b0b5c1977cb4feb5f594be60eb121106f8900348e29331f553a726f \ + --hash=sha256:bc265a7945e8d08da28999ad02b544963f813a00f3ed0a7a0ce4165fd77629f8 \ + --hash=sha256:bed4a2341b33cd1a7d9ffc47df4a78ee61d3416d43b4adc9e18b7d266650b83e \ + --hash=sha256:c1a40c486041006b135759f59189385da7c66d239bad897c994e18fd1d0c128f \ + --hash=sha256:c36baa0ecde742784aa76c2b816466d3ea888d5297fda0edbac1bf48fa94688a \ + --hash=sha256:c4c746d11c8aba4b9f58ca8bfc6fbfd0da4efe7960ae5540d1a1b13655ee8892 \ + --hash=sha256:ca79146ee421b259f8131f153102220b84d1a5e6fb9c8aed13b3badfd1796de6 \ + --hash=sha256:cc452481e124a819ced0c25412ea2e144269ef2f2534b862d9f6a9dae4bda17b \ + --hash=sha256:cfb8b9d8855c8608f9747602a48ab525b1d320ecf0113994f6df23160af68262 \ + --hash=sha256:d12b15a8c3759e2bb580ffa423ae54be4f184cf23beffcbd641f4fe6e1584293 \ + --hash=sha256:d24fb3c0c8ff0d517c5ca5de7cf3994a4cd559cde0315201511dbfa7ab528894 \ + --hash=sha256:d4b0aab55ad60ead26159ff12b538c85fbab731a5e3411c642b46c3525863437 \ + --hash=sha256:d6a558c2725bfb6337bf57c1cd366c13798bfd3bfc9e3dd1f4a6f6fc95a4605f \ + --hash=sha256:d946a0c067aa88be4a593aad1236493313bafaa27e2a2080bfe88db827972f3c \ + --hash=sha256:dc60ddd483c556590da1d9482a4518292eec36dd0e1e8496966759a1f282bcd0 \ + --hash=sha256:dcc93488c9ebd229be6ee1f0d9aad90da97b33ad7e2912f5495804d78a3cd6b7 \ + --hash=sha256:ddca1e4f5f4c67980533df01430184c19b5359900e080248bbf4ed6789584d8b \ + --hash=sha256:ddf2a63b91399a1c2f88f40bc1705d5a7777e31c7e9eb27c602280f477b582ba \ + --hash=sha256:df1c742ca6f46a6f6cbcaef9ac694dc2cb1260d30a6a2f5c68c5f5bcfee1cfd7 \ + --hash=sha256:e37c72eaccdd5ed1130c67a92ad38f5b2af66eeff7b0abe29534225db2ef7b18 \ + --hash=sha256:e58991a2b213417285ec866d3cd32db17a6a88061a985dbb7e8e8f13af429c47 \ + --hash=sha256:e6150d167f32f2a54690e572e0a4c90296fb000a18e9b26ab81a6489e24e78dd \ + --hash=sha256:e88dd71e4ecbc49d9d57d064117462c43f40a21a1383507811cf834a4a620651 \ + --hash=sha256:e8ab8e4c7ec7f8a55ac05b5b715a051d74eac62511c6d96d5bb79aaafa3b04cf \ + --hash=sha256:ebb08d0867c5a25dffa4823377292a0ffd7aaafb218b5d4e2e106378b1061e39 \ + --hash=sha256:ed3718c757c82d920f1c94089066225ca2ad7f00bb904cb72b1c39ebdd906ccb \ + --hash=sha256:ee6be07af68d9c4fca4027c70cea0c31a0f1bc9cb464ff3c84a1f916bf82e652 \ + --hash=sha256:efa23166da3fe2915f8ab452dde40319ac84dc357f635737174a08dbd912980c \ + --hash=sha256:f32a95a83c2e17422f67af922a89422cd24c6fa94041f083dd0bb4f6057d0bc7 \ + --hash=sha256:f7da31a1ba31f1c1d4d5044b7c5813878adae1f3af8f4052d679cc493c7328f4 \ + --hash=sha256:fa2a258aa6bf188eb9a8948f7102a83da7c430a0dce918dbd8b60ef8fcb772d7 \ + --hash=sha256:fc0e46d86905ddd16b85991f1f4919028092b4e511689bbdaff0876bd8aab3dd \ + --hash=sha256:fefe31d61d02a8b2c419700b1fade9784a43d726de26495f243b663cd9fe1513 + # via pytest-cov +crcmod==1.7 \ + --hash=sha256:dc7051a0db5f2bd48665a990d3ec1cc305a466a77358ca4492826f41f283601e + # via bip-utils +cryptography==45.0.5 \ + --hash=sha256:0027d566d65a38497bc37e0dd7c2f8ceda73597d2ac9ba93810204f56f52ebc7 \ + --hash=sha256:101ee65078f6dd3e5a028d4f19c07ffa4dd22cce6a20eaa160f8b5219911e7d8 \ + --hash=sha256:12e55281d993a793b0e883066f590c1ae1e802e3acb67f8b442e721e475e6463 \ + --hash=sha256:14d96584701a887763384f3c47f0ca7c1cce322aa1c31172680eb596b890ec30 \ + --hash=sha256:1e1da5accc0c750056c556a93c3e9cb828970206c68867712ca5805e46dc806f \ + --hash=sha256:206210d03c1193f4e1ff681d22885181d47efa1ab3018766a7b32a7b3d6e6afd \ + --hash=sha256:2089cc8f70a6e454601525e5bf2779e665d7865af002a5dec8d14e561002e135 \ + --hash=sha256:3a264aae5f7fbb089dbc01e0242d3b67dffe3e6292e1f5182122bdf58e65215d \ + --hash=sha256:3af26738f2db354aafe492fb3869e955b12b2ef2e16908c8b9cb928128d42c57 \ + --hash=sha256:3fcfbefc4a7f332dece7272a88e410f611e79458fab97b5efe14e54fe476f4fd \ + --hash=sha256:460f8c39ba66af7db0545a8c6f2eabcbc5a5528fc1cf6c3fa9a1e44cec33385e \ + --hash=sha256:57c816dfbd1659a367831baca4b775b2a5b43c003daf52e9d57e1d30bc2e1b0e \ + --hash=sha256:5aa1e32983d4443e310f726ee4b071ab7569f58eedfdd65e9675484a4eb67bd1 \ + --hash=sha256:6ff8728d8d890b3dda5765276d1bc6fb099252915a2cd3aff960c4c195745dd0 \ + --hash=sha256:7259038202a47fdecee7e62e0fd0b0738b6daa335354396c6ddebdbe1206af2a \ + --hash=sha256:72e76caa004ab63accdf26023fccd1d087f6d90ec6048ff33ad0445abf7f605a \ + --hash=sha256:7760c1c2e1a7084153a0f68fab76e754083b126a47d0117c9ed15e69e2103492 \ + --hash=sha256:8c4a6ff8a30e9e3d38ac0539e9a9e02540ab3f827a3394f8852432f6b0ea152e \ + --hash=sha256:9024beb59aca9d31d36fcdc1604dd9bbeed0a55bface9f1908df19178e2f116e \ + --hash=sha256:90cb0a7bb35959f37e23303b7eed0a32280510030daba3f7fdfbb65defde6a97 \ + --hash=sha256:91098f02ca81579c85f66df8a588c78f331ca19089763d733e34ad359f474174 \ + --hash=sha256:926c3ea71a6043921050eaa639137e13dbe7b4ab25800932a8498364fc1abec9 \ + --hash=sha256:982518cd64c54fcada9d7e5cf28eabd3ee76bd03ab18e08a48cad7e8b6f31b18 \ + --hash=sha256:9b4cf6318915dccfe218e69bbec417fdd7c7185aa7aab139a2c0beb7468c89f0 \ + --hash=sha256:ad0caded895a00261a5b4aa9af828baede54638754b51955a0ac75576b831b27 \ + --hash=sha256:b85980d1e345fe769cfc57c57db2b59cff5464ee0c045d52c0df087e926fbe63 \ + --hash=sha256:b8fa8b0a35a9982a3c60ec79905ba5bb090fc0b9addcfd3dc2dd04267e45f25e \ + --hash=sha256:b9e38e0a83cd51e07f5a48ff9691cae95a79bea28fe4ded168a8e5c6c77e819d \ + --hash=sha256:bd4c45986472694e5121084c6ebbd112aa919a25e783b87eb95953c9573906d6 \ + --hash=sha256:be97d3a19c16a9be00edf79dca949c8fa7eff621763666a145f9f9535a5d7f42 \ + --hash=sha256:c648025b6840fe62e57107e0a25f604db740e728bd67da4f6f060f03017d5097 \ + --hash=sha256:d05a38884db2ba215218745f0781775806bde4f32e07b135348355fe8e4991d9 \ + --hash=sha256:dd420e577921c8c2d31289536c386aaa30140b473835e97f83bc71ea9d2baf2d \ + --hash=sha256:e357286c1b76403dd384d938f93c46b2b058ed4dfcdce64a770f0537ed3feb6f \ + --hash=sha256:e6c00130ed423201c5bc5544c23359141660b07999ad82e34e7bb8f882bb78e0 \ + --hash=sha256:e74d30ec9c7cb2f404af331d5b4099a9b322a8a6b25c4632755c8757345baac5 \ + --hash=sha256:f3562c2f23c612f2e4a6964a61d942f891d29ee320edb62ff48ffb99f3de9ae8 + # via + # -r src/requirements.txt + # pgpy +deprecated==1.2.18 \ + --hash=sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d \ + --hash=sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec + # via limits +ecdsa==0.19.1 \ + --hash=sha256:30638e27cf77b7e15c4c4cc1973720149e1033827cfd00661ca5c8cc0cdb24c3 \ + --hash=sha256:478cba7b62555866fcb3bb3fe985e06decbdb68ef55713c4e5ab98c57d508e61 + # via bip-utils +ed25519-blake2b==1.4.1 \ + --hash=sha256:731e9f93cd1ac1a64649575f3519a99ffe0bb1e4cf7bf5f5f0be513a39df7363 + # via bip-utils +execnet==2.1.1 \ + --hash=sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc \ + --hash=sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3 + # via pytest-xdist +fastapi==0.116.1 \ + --hash=sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565 \ + --hash=sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143 + # via -r src/requirements.txt +freezegun==1.5.4 \ + --hash=sha256:798b9372fdd4d907f33e8b6a58bc64e682d9ffa8d494ce60f780197ee81faed1 \ + --hash=sha256:8bdd75c9d790f53d5a173d273064ccd7900984b36635be552befeedb0cd47b20 + # via -r src/requirements.txt +frozenlist==1.7.0 \ + --hash=sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f \ + --hash=sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b \ + --hash=sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949 \ + --hash=sha256:1073557c941395fdfcfac13eb2456cb8aad89f9de27bae29fabca8e563b12615 \ + --hash=sha256:1137b78384eebaf70560a36b7b229f752fb64d463d38d1304939984d5cb887b6 \ + --hash=sha256:15900082e886edb37480335d9d518cec978afc69ccbc30bd18610b7c1b22a718 \ + --hash=sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df \ + --hash=sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf \ + --hash=sha256:1e63344c4e929b1a01e29bc184bbb5fd82954869033765bfe8d65d09e336a677 \ + --hash=sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5 \ + --hash=sha256:1ed8d2fa095aae4bdc7fdd80351009a48d286635edffee66bf865e37a9125c50 \ + --hash=sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb \ + --hash=sha256:21884e23cffabb157a9dd7e353779077bf5b8f9a58e9b262c6caad2ef5f80a56 \ + --hash=sha256:24c34bea555fe42d9f928ba0a740c553088500377448febecaa82cc3e88aa1fa \ + --hash=sha256:284d233a8953d7b24f9159b8a3496fc1ddc00f4db99c324bd5fb5f22d8698ea7 \ + --hash=sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43 \ + --hash=sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f \ + --hash=sha256:2ea2a7369eb76de2217a842f22087913cdf75f63cf1307b9024ab82dfb525938 \ + --hash=sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c \ + --hash=sha256:34a69a85e34ff37791e94542065c8416c1afbf820b68f720452f636d5fb990cd \ + --hash=sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c \ + --hash=sha256:3789ebc19cb811163e70fe2bd354cea097254ce6e707ae42e56f45e31e96cb8e \ + --hash=sha256:387cbfdcde2f2353f19c2f66bbb52406d06ed77519ac7ee21be0232147c2592d \ + --hash=sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81 \ + --hash=sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e \ + --hash=sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657 \ + --hash=sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478 \ + --hash=sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2 \ + --hash=sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca \ + --hash=sha256:400ddd24ab4e55014bba442d917203c73b2846391dd42ca5e38ff52bb18c3c5e \ + --hash=sha256:41be2964bd4b15bf575e5daee5a5ce7ed3115320fb3c2b71fca05582ffa4dc9e \ + --hash=sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3 \ + --hash=sha256:43a82fce6769c70f2f5a06248b614a7d268080a9d20f7457ef10ecee5af82b63 \ + --hash=sha256:45a6f2fdbd10e074e8814eb98b05292f27bad7d1883afbe009d96abdcf3bc898 \ + --hash=sha256:46d84d49e00c9429238a7ce02dc0be8f6d7cd0cd405abd1bebdc991bf27c15bd \ + --hash=sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca \ + --hash=sha256:4a646531fa8d82c87fe4bb2e596f23173caec9185bfbca5d583b4ccfb95183e2 \ + --hash=sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104 \ + --hash=sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba \ + --hash=sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a \ + --hash=sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1 \ + --hash=sha256:61d1a5baeaac6c0798ff6edfaeaa00e0e412d49946c53fae8d4b8e8b3566c4ae \ + --hash=sha256:69cac419ac6a6baad202c85aaf467b65ac860ac2e7f2ac1686dc40dbb52f6577 \ + --hash=sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60 \ + --hash=sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee \ + --hash=sha256:6eb93efb8101ef39d32d50bce242c84bcbddb4f7e9febfa7b524532a239b4464 \ + --hash=sha256:716a9973a2cc963160394f701964fe25012600f3d311f60c790400b00e568b61 \ + --hash=sha256:72c1b0fe8fe451b34f12dce46445ddf14bd2a5bcad7e324987194dc8e3a74c86 \ + --hash=sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01 \ + --hash=sha256:74739ba8e4e38221d2c5c03d90a7e542cb8ad681915f4ca8f68d04f810ee0a87 \ + --hash=sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb \ + --hash=sha256:79b2ffbba483f4ed36a0f236ccb85fbb16e670c9238313709638167670ba235f \ + --hash=sha256:7d536ee086b23fecc36c2073c371572374ff50ef4db515e4e503925361c24f71 \ + --hash=sha256:7edf5c043c062462f09b6820de9854bf28cc6cc5b6714b383149745e287181a8 \ + --hash=sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d \ + --hash=sha256:836b42f472a0e006e02499cef9352ce8097f33df43baaba3e0a28a964c26c7d2 \ + --hash=sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00 \ + --hash=sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b \ + --hash=sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b \ + --hash=sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146 \ + --hash=sha256:960d67d0611f4c87da7e2ae2eacf7ea81a5be967861e0c63cf205215afbfac59 \ + --hash=sha256:974c5336e61d6e7eb1ea5b929cb645e882aadab0095c5a6974a111e6479f8878 \ + --hash=sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08 \ + --hash=sha256:9a19e85cc503d958abe5218953df722748d87172f71b73cf3c9257a91b999890 \ + --hash=sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e \ + --hash=sha256:9b35db7ce1cd71d36ba24f80f0c9e7cff73a28d7a74e91fe83e23d27c7828750 \ + --hash=sha256:9ccec739a99e4ccf664ea0775149f2749b8a6418eb5b8384b4dc0a7d15d304cb \ + --hash=sha256:a0fd1bad056a3600047fb9462cff4c5322cebc59ebf5d0a3725e0ee78955001d \ + --hash=sha256:a26f205c9ca5829cbf82bb2a84b5c36f7184c4316617d7ef1b271a56720d6b30 \ + --hash=sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3 \ + --hash=sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d \ + --hash=sha256:aa51e147a66b2d74de1e6e2cf5921890de6b0f4820b257465101d7f37b49fb5a \ + --hash=sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8 \ + --hash=sha256:ac64b6478722eeb7a3313d494f8342ef3478dff539d17002f849101b212ef97c \ + --hash=sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1 \ + --hash=sha256:af369aa35ee34f132fcfad5be45fbfcde0e3a5f6a1ec0712857f286b7d20cca9 \ + --hash=sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e \ + --hash=sha256:b3950f11058310008a87757f3eee16a8e1ca97979833239439586857bc25482e \ + --hash=sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384 \ + --hash=sha256:bcacfad3185a623fa11ea0e0634aac7b691aa925d50a440f39b458e41c561d98 \ + --hash=sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb \ + --hash=sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4 \ + --hash=sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65 \ + --hash=sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08 \ + --hash=sha256:c70db4a0ab5ab20878432c40563573229a7ed9241506181bba12f6b7d0dc41cb \ + --hash=sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43 \ + --hash=sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a \ + --hash=sha256:ce48b2fece5aeb45265bb7a58259f45027db0abff478e3077e12b05b17fb9da7 \ + --hash=sha256:cea3dbd15aea1341ea2de490574a4a37ca080b2ae24e4b4f4b51b9057b4c3630 \ + --hash=sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d \ + --hash=sha256:d50ac7627b3a1bd2dcef6f9da89a772694ec04d9a61b66cf87f7d9446b4a0c31 \ + --hash=sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d \ + --hash=sha256:dfcebf56f703cb2e346315431699f00db126d158455e513bd14089d992101e44 \ + --hash=sha256:e22b9a99741294b2571667c07d9f8cceec07cb92aae5ccda39ea1b6052ed4319 \ + --hash=sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e \ + --hash=sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025 \ + --hash=sha256:e793a9f01b3e8b5c0bc646fb59140ce0efcc580d22a3468d70766091beb81b35 \ + --hash=sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee \ + --hash=sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1 \ + --hash=sha256:f22dac33bb3ee8fe3e013aa7b91dc12f60d61d05b7fe32191ffa84c3aafe77bd \ + --hash=sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74 \ + --hash=sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b \ + --hash=sha256:f89f65d85774f1797239693cef07ad4c97fdd0639544bad9ac4b869782eb1981 \ + --hash=sha256:fe2365ae915a1fafd982c146754e1de6ab3478def8a59c86e1f7242d794f97d5 + # via + # aiohttp + # aiosignal +glob2==0.7 \ + --hash=sha256:85c3dbd07c8aa26d63d7aacee34fa86e9a91a3873bc30bf62ec46e531f92ab8c + # via mutmut +h11==0.16.0 \ + --hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \ + --hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86 + # via + # httpcore + # uvicorn +httpcore==1.0.9 \ + --hash=sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55 \ + --hash=sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8 + # via httpx +httpx==0.28.1 \ + --hash=sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc \ + --hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad + # via -r src/requirements.txt +hypothesis==6.136.7 \ + --hash=sha256:12a8b76a5c453f8478d6bb4b5450824856af571c5e7821604a15aeaafa9beefd \ + --hash=sha256:864c5cf7779adc58871ee51595bc724c496047c5bc45229e0baa950b103a73ea + # via -r src/requirements.txt +idna==3.10 \ + --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ + --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 + # via + # anyio + # httpx + # requests + # yarl +iniconfig==2.1.0 \ + --hash=sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7 \ + --hash=sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760 + # via pytest +junit-xml==1.9 \ + --hash=sha256:de16a051990d4e25a3982b2dd9e89d671067548718866416faec14d9de56db9f \ + --hash=sha256:ec5ca1a55aefdd76d28fcc0b135251d156c7106fa979686a4b48d62b761b4732 + # via mutmut +limits==5.4.0 \ + --hash=sha256:1afb03c0624cf004085532aa9524953f2565cf8b0a914e48dda89d172c13ceb7 \ + --hash=sha256:27ebf55118e3c9045f0dbc476f4559b26d42f4b043db670afb8963f36cf07fd9 + # via slowapi +markdown-it-py==3.0.0 \ + --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ + --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb + # via rich +mdurl==0.1.2 \ + --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ + --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba + # via markdown-it-py +mnemonic==0.21 \ + --hash=sha256:1fe496356820984f45559b1540c80ff10de448368929b9c60a2b55744cc88acf \ + --hash=sha256:72dc9de16ec5ef47287237b9b6943da11647a03fe7cf1f139fc3d7c4a7439288 + # via -r src/requirements.txt +multidict==6.6.3 \ + --hash=sha256:02fd8f32d403a6ff13864b0851f1f523d4c988051eea0471d4f1fd8010f11134 \ + --hash=sha256:04cbcce84f63b9af41bad04a54d4cc4e60e90c35b9e6ccb130be2d75b71f8c17 \ + --hash=sha256:056bebbeda16b2e38642d75e9e5310c484b7c24e3841dc0fb943206a72ec89d6 \ + --hash=sha256:05db2f66c9addb10cfa226e1acb363450fab2ff8a6df73c622fefe2f5af6d4e7 \ + --hash=sha256:0b9e59946b49dafaf990fd9c17ceafa62976e8471a14952163d10a7a630413a9 \ + --hash=sha256:0db58da8eafb514db832a1b44f8fa7906fdd102f7d982025f816a93ba45e3dcb \ + --hash=sha256:0f1130b896ecb52d2a1e615260f3ea2af55fa7dc3d7c3003ba0c3121a759b18b \ + --hash=sha256:10bea2ee839a759ee368b5a6e47787f399b41e70cf0c20d90dfaf4158dfb4e55 \ + --hash=sha256:12f4581d2930840295c461764b9a65732ec01250b46c6b2c510d7ee68872b140 \ + --hash=sha256:1328201ee930f069961ae707d59c6627ac92e351ed5b92397cf534d1336ce557 \ + --hash=sha256:135631cb6c58eac37d7ac0df380294fecdc026b28837fa07c02e459c7fb9c54e \ + --hash=sha256:14117a41c8fdb3ee19c743b1c027da0736fdb79584d61a766da53d399b71176c \ + --hash=sha256:15332783596f227db50fb261c2c251a58ac3873c457f3a550a95d5c0aa3c770d \ + --hash=sha256:159ca68bfd284a8860f8d8112cf0521113bffd9c17568579e4d13d1f1dc76b65 \ + --hash=sha256:18f4eba0cbac3546b8ae31e0bbc55b02c801ae3cbaf80c247fcdd89b456ff58c \ + --hash=sha256:1bf99b4daf908c73856bd87ee0a2499c3c9a3d19bb04b9c6025e66af3fd07462 \ + --hash=sha256:1c8082e5814b662de8589d6a06c17e77940d5539080cbab9fe6794b5241b76d9 \ + --hash=sha256:208b9b9757060b9faa6f11ab4bc52846e4f3c2fb8b14d5680c8aac80af3dc751 \ + --hash=sha256:20c5a0c3c13a15fd5ea86c42311859f970070e4e24de5a550e99d7c271d76318 \ + --hash=sha256:2334cfb0fa9549d6ce2c21af2bfbcd3ac4ec3646b1b1581c88e3e2b1779ec92b \ + --hash=sha256:233ad16999afc2bbd3e534ad8dbe685ef8ee49a37dbc2cdc9514e57b6d589ced \ + --hash=sha256:274d416b0df887aef98f19f21578653982cfb8a05b4e187d4a17103322eeaf8f \ + --hash=sha256:295adc9c0551e5d5214b45cf29ca23dbc28c2d197a9c30d51aed9e037cb7c578 \ + --hash=sha256:2e4cc8d848cd4fe1cdee28c13ea79ab0ed37fc2e89dd77bac86a2e7959a8c3bc \ + --hash=sha256:346055630a2df2115cd23ae271910b4cae40f4e336773550dca4889b12916e75 \ + --hash=sha256:35712f1748d409e0707b165bf49f9f17f9e28ae85470c41615778f8d4f7d9609 \ + --hash=sha256:3713303e4a6663c6d01d648a68f2848701001f3390a030edaaf3fc949c90bf7c \ + --hash=sha256:37b09ca60998e87734699e88c2363abfd457ed18cfbf88e4009a4e83788e63ed \ + --hash=sha256:3893a0d7d28a7fe6ca7a1f760593bc13038d1d35daf52199d431b61d2660602b \ + --hash=sha256:41bb9d1d4c303886e2d85bade86e59885112a7f4277af5ad47ab919a2251f306 \ + --hash=sha256:42ca5aa9329a63be8dc49040f63817d1ac980e02eeddba763a9ae5b4027b9c9c \ + --hash=sha256:43571f785b86afd02b3855c5ac8e86ec921b760298d6f82ff2a61daf5a35330b \ + --hash=sha256:448e4a9afccbf297577f2eaa586f07067441e7b63c8362a3540ba5a38dc0f14a \ + --hash=sha256:4ef421045f13879e21c994b36e728d8e7d126c91a64b9185810ab51d474f27e7 \ + --hash=sha256:500b84f51654fdc3944e936f2922114349bf8fdcac77c3092b03449f0e5bc2b3 \ + --hash=sha256:531e331a2ee53543ab32b16334e2deb26f4e6b9b28e41f8e0c87e99a6c8e2d69 \ + --hash=sha256:53becb01dd8ebd19d1724bebe369cfa87e4e7f29abbbe5c14c98ce4c383e16cd \ + --hash=sha256:540d3c06d48507357a7d57721e5094b4f7093399a0106c211f33540fdc374d55 \ + --hash=sha256:555ff55a359302b79de97e0468e9ee80637b0de1fce77721639f7cd9440b3a10 \ + --hash=sha256:5633a82fba8e841bc5c5c06b16e21529573cd654f67fd833650a215520a6210e \ + --hash=sha256:5bd8d6f793a787153956cd35e24f60485bf0651c238e207b9a54f7458b16d539 \ + --hash=sha256:61af8a4b771f1d4d000b3168c12c3120ccf7284502a94aa58c68a81f5afac090 \ + --hash=sha256:639ecc9fe7cd73f2495f62c213e964843826f44505a3e5d82805aa85cac6f89e \ + --hash=sha256:67c92ed673049dec52d7ed39f8cf9ebbadf5032c774058b4406d18c8f8fe7063 \ + --hash=sha256:68e9e12ed00e2089725669bdc88602b0b6f8d23c0c95e52b95f0bc69f7fe9b55 \ + --hash=sha256:6c1e61bb4f80895c081790b6b09fa49e13566df8fbff817da3f85b3a8192e36b \ + --hash=sha256:70b72e749a4f6e7ed8fb334fa8d8496384840319512746a5f42fa0aec79f4d61 \ + --hash=sha256:70d974eaaa37211390cd02ef93b7e938de564bbffa866f0b08d07e5e65da783d \ + --hash=sha256:712b348f7f449948e0a6c4564a21c7db965af900973a67db432d724619b3c680 \ + --hash=sha256:72d8815f2cd3cf3df0f83cac3f3ef801d908b2d90409ae28102e0553af85545a \ + --hash=sha256:7394888236621f61dcdd25189b2768ae5cc280f041029a5bcf1122ac63df79f9 \ + --hash=sha256:73ab034fb8d58ff85c2bcbadc470efc3fafeea8affcf8722855fb94557f14cc5 \ + --hash=sha256:766a4a5996f54361d8d5a9050140aa5362fe48ce51c755a50c0bc3706460c430 \ + --hash=sha256:769841d70ca8bdd140a715746199fc6473414bd02efd678d75681d2d6a8986c5 \ + --hash=sha256:775b464d31dac90f23192af9c291dc9f423101857e33e9ebf0020a10bfcf4144 \ + --hash=sha256:798a9eb12dab0a6c2e29c1de6f3468af5cb2da6053a20dfa3344907eed0937cc \ + --hash=sha256:7af039820cfd00effec86bda5d8debef711a3e86a1d3772e85bea0f243a4bd65 \ + --hash=sha256:7c6df517cf177da5d47ab15407143a89cd1a23f8b335f3a28d57e8b0a3dbb884 \ + --hash=sha256:81ef2f64593aba09c5212a3d0f8c906a0d38d710a011f2f42759704d4557d3f2 \ + --hash=sha256:877443eaaabcd0b74ff32ebeed6f6176c71850feb7d6a1d2db65945256ea535c \ + --hash=sha256:8db10f29c7541fc5da4defd8cd697e1ca429db743fa716325f236079b96f775a \ + --hash=sha256:8df25594989aebff8a130f7899fa03cbfcc5d2b5f4a461cf2518236fe6f15961 \ + --hash=sha256:900eb9f9da25ada070f8ee4a23f884e0ee66fe4e1a38c3af644256a508ad81ca \ + --hash=sha256:934796c81ea996e61914ba58064920d6cad5d99140ac3167901eb932150e2e56 \ + --hash=sha256:94c47ea3ade005b5976789baaed66d4de4480d0a0bf31cef6edaa41c1e7b56a6 \ + --hash=sha256:9c19cea2a690f04247d43f366d03e4eb110a0dc4cd1bbeee4d445435428ed35b \ + --hash=sha256:9e236a7094b9c4c1b7585f6b9cca34b9d833cf079f7e4c49e6a4a6ec9bfdc68f \ + --hash=sha256:9e864486ef4ab07db5e9cb997bad2b681514158d6954dd1958dfb163b83d53e6 \ + --hash=sha256:9ed948328aec2072bc00f05d961ceadfd3e9bfc2966c1319aeaf7b7c21219183 \ + --hash=sha256:9f5b28c074c76afc3e4c610c488e3493976fe0e596dd3db6c8ddfbb0134dcac5 \ + --hash=sha256:9f97e181f344a0ef3881b573d31de8542cc0dbc559ec68c8f8b5ce2c2e91646d \ + --hash=sha256:a2be5b7b35271f7fff1397204ba6708365e3d773579fe2a30625e16c4b4ce817 \ + --hash=sha256:ab0a34a007704c625e25a9116c6770b4d3617a071c8a7c30cd338dfbadfe6485 \ + --hash=sha256:acf6b97bd0884891af6a8b43d0f586ab2fcf8e717cbd47ab4bdddc09e20652d8 \ + --hash=sha256:b1db4d2093d6b235de76932febf9d50766cf49a5692277b2c28a501c9637f616 \ + --hash=sha256:b24576f208793ebae00280c59927c3b7c2a3b1655e443a25f753c4611bc1c373 \ + --hash=sha256:b8fee016722550a2276ca2cb5bb624480e0ed2bd49125b2b73b7010b9090e888 \ + --hash=sha256:b9cbc60010de3562545fa198bfc6d3825df430ea96d2cc509c39bd71e2e7d648 \ + --hash=sha256:b9fe5a0e57c6dbd0e2ce81ca66272282c32cd11d31658ee9553849d91289e1c1 \ + --hash=sha256:bb933c891cd4da6bdcc9733d048e994e22e1883287ff7540c2a0f3b117605092 \ + --hash=sha256:bc7f6fbc61b1c16050a389c630da0b32fc6d4a3d191394ab78972bf5edc568c2 \ + --hash=sha256:bd0578596e3a835ef451784053cfd327d607fc39ea1a14812139339a18a0dbc3 \ + --hash=sha256:bf9bd1fd5eec01494e0f2e8e446a74a85d5e49afb63d75a9934e4a5423dba21d \ + --hash=sha256:c60b401f192e79caec61f166da9c924e9f8bc65548d4246842df91651e83d600 \ + --hash=sha256:c8161b5a7778d3137ea2ee7ae8a08cce0010de3b00ac671c5ebddeaa17cefd22 \ + --hash=sha256:cdf22e4db76d323bcdc733514bf732e9fb349707c98d341d40ebcc6e9318ef3d \ + --hash=sha256:ce8b7693da41a3c4fde5871c738a81490cea5496c671d74374c8ab889e1834fb \ + --hash=sha256:d04d01f0a913202205a598246cf77826fe3baa5a63e9f6ccf1ab0601cf56eca0 \ + --hash=sha256:d25594d3b38a2e6cabfdcafef339f754ca6e81fbbdb6650ad773ea9775af35ab \ + --hash=sha256:d4e47d8faffaae822fb5cba20937c048d4f734f43572e7079298a6c39fb172cb \ + --hash=sha256:dbc7cf464cc6d67e83e136c9f55726da3a30176f020a36ead246eceed87f1cd8 \ + --hash=sha256:dd7793bab517e706c9ed9d7310b06c8672fd0aeee5781bfad612f56b8e0f7d14 \ + --hash=sha256:e098c17856a8c9ade81b4810888c5ad1914099657226283cab3062c0540b0643 \ + --hash=sha256:e0cb0ab69915c55627c933f0b555a943d98ba71b4d1c57bc0d0a66e2567c7471 \ + --hash=sha256:e252017a817fad7ce05cafbe5711ed40faeb580e63b16755a3a24e66fa1d87c0 \ + --hash=sha256:e2db616467070d0533832d204c54eea6836a5e628f2cb1e6dfd8cd6ba7277cb7 \ + --hash=sha256:e4e15d2138ee2694e038e33b7c3da70e6b0ad8868b9f8094a72e1414aeda9c1a \ + --hash=sha256:e5511cb35f5c50a2db21047c875eb42f308c5583edf96bd8ebf7d770a9d68f6d \ + --hash=sha256:e5e8523bb12d7623cd8300dbd91b9e439a46a028cd078ca695eb66ba31adee3c \ + --hash=sha256:e5f481cccb3c5c5e5de5d00b5141dc589c1047e60d07e85bbd7dea3d4580d63f \ + --hash=sha256:e924fb978615a5e33ff644cc42e6aa241effcf4f3322c09d4f8cebde95aff5f8 \ + --hash=sha256:e93089c1570a4ad54c3714a12c2cef549dc9d58e97bcded193d928649cab78e9 \ + --hash=sha256:e995a34c3d44ab511bfc11aa26869b9d66c2d8c799fa0e74b28a473a692532d6 \ + --hash=sha256:ef43b5dd842382329e4797c46f10748d8c2b6e0614f46b4afe4aee9ac33159df \ + --hash=sha256:ef58340cc896219e4e653dade08fea5c55c6df41bcc68122e3be3e9d873d9a7b \ + --hash=sha256:f114d8478733ca7388e7c7e0ab34b72547476b97009d643644ac33d4d3fe1821 \ + --hash=sha256:f3aa090106b1543f3f87b2041eef3c156c8da2aed90c63a2fbed62d875c49c37 \ + --hash=sha256:f3fc723ab8a5c5ed6c50418e9bfcd8e6dceba6c271cee6728a10a4ed8561520c \ + --hash=sha256:f54cb79d26d0cd420637d184af38f0668558f3c4bbe22ab7ad830e67249f2e0b \ + --hash=sha256:fc9dc435ec8699e7b602b94fe0cd4703e69273a01cbc34409af29e7820f777f1 + # via + # aiohttp + # yarl +mutmut==2.4.4 \ + --hash=sha256:babd1ac579a817f94d5b944af70f1c5fee5ed117775be0a13c99b96b96841b23 + # via -r src/requirements.txt +nostr-sdk==0.43.0 \ + --hash=sha256:1eff16fac045598472807bee311f3002b0c771beb65e4d8f8e35643db549e9de \ + --hash=sha256:379566a5b1e742751a9f220636e37d48ba298009a7931086200917315ec02cd9 \ + --hash=sha256:6e9670d0c83e90e337a67cd0f60cee626f9f49b9e941016083c4c2b7e2e7c11b \ + --hash=sha256:7dd2af2ce071e5f52cf48aaf61630b15a1690e0294913b2f45eff0dd03510d9b \ + --hash=sha256:910f025b280866199539ccbcc5ec68354b12e939f15340bf532db9c18257ca22 \ + --hash=sha256:9434a29a0b6251256f00d7d5040e99678ecedce69c4e1ce43c9303cfd615c53e \ + --hash=sha256:a25887e6e5936a6ece76f0aae3ba402689b021b3c496736c8803aabc23195483 \ + --hash=sha256:b2fbcda409fd1e90ad5a1b59b2b22e61c136a93e1366cc5474e2b1278b692a81 \ + --hash=sha256:c2f7ad6a983e6fe325e276c6e2be07f1a4424e9ac09f61fce792fceb5f92613e \ + --hash=sha256:da45c976f170a3367b9d1764fd40cf0c6915c9ba36c2c18048cca8577aef10bc \ + --hash=sha256:dd1af754e8a034d4bb3480d16c8960efe24331a3263886b30b3fec61b8ae5439 \ + --hash=sha256:f0cc358274462d66f81464b5deca6c85ee6837ea54474bcc09fbc09fec522d66 \ + --hash=sha256:f97a756ed3a90ee903560183505f6c35653c1ace4894525d2944d84c1c685718 + # via -r src/requirements.txt +orjson==3.11.1 \ + --hash=sha256:0085ef83a4141c2ed23bfec5fecbfdb1e95dd42fc8e8c76057bdeeec1608ea65 \ + --hash=sha256:06ef26e009304bda4df42e4afe518994cde6f89b4b04c0ff24021064f83f4fbb \ + --hash=sha256:08c6a762fca63ca4dc04f66c48ea5d2428db55839fec996890e1bfaf057b658c \ + --hash=sha256:0baad413c498fc1eef568504f11ea46bc71f94b845c075e437da1e2b85b4fb86 \ + --hash=sha256:0c1e394e67ced6bb16fea7054d99fbdd99a539cf4d446d40378d4c06e0a8548d \ + --hash=sha256:0eacdfeefd0a79987926476eb16e0245546bedeb8febbbbcf4b653e79257a8e4 \ + --hash=sha256:0ed07faf9e4873518c60480325dcbc16d17c59a165532cccfb409b4cdbaeff24 \ + --hash=sha256:0ed0fce2307843b79a0c83de49f65b86197f1e2310de07af9db2a1a77a61ce4c \ + --hash=sha256:10506cebe908542c4f024861102673db534fd2e03eb9b95b30d94438fa220abf \ + --hash=sha256:1495692f1f1ba2467df429343388a0ed259382835922e124c0cfdd56b3d1f727 \ + --hash=sha256:15e2a57ce3b57c1a36acffcc02e823afefceee0a532180c2568c62213c98e3ef \ + --hash=sha256:17040a83ecaa130474af05bbb59a13cfeb2157d76385556041f945da936b1afd \ + --hash=sha256:1a68f23f09e5626cc0867a96cf618f68b91acb4753d33a80bf16111fd7f9928c \ + --hash=sha256:200c3ad7ed8b5d31d49143265dfebd33420c4b61934ead16833b5cd2c3d241be \ + --hash=sha256:2092e1d3b33f64e129ff8271642afddc43763c81f2c30823b4a4a4a5f2ea5b55 \ + --hash=sha256:20b0dca94ea4ebe4628330de50975b35817a3f52954c1efb6d5d0498a3bbe581 \ + --hash=sha256:22cf17ae1dae3f9b5f37bfcdba002ed22c98bbdb70306e42dc18d8cc9b50399a \ + --hash=sha256:23196b826ebc85c43f8e27bee0ab33c5fb13a29ea47fb4fcd6ebb1e660eb0252 \ + --hash=sha256:26b6c821abf1ae515fbb8e140a2406c9f9004f3e52acb780b3dee9bfffddbd84 \ + --hash=sha256:2b7c8be96db3a977367250c6367793a3c5851a6ca4263f92f0b48d00702f9910 \ + --hash=sha256:3091dad33ac9e67c0a550cfff8ad5be156e2614d6f5d2a9247df0627751a1495 \ + --hash=sha256:33aada2e6b6bc9c540d396528b91e666cedb383740fee6e6a917f561b390ecb1 \ + --hash=sha256:3d593a9e0bccf2c7401ae53625b519a7ad7aa555b1c82c0042b322762dc8af4e \ + --hash=sha256:45202ee3f5494644e064c41abd1320497fb92fd31fc73af708708af664ac3b56 \ + --hash=sha256:4537b0e09f45d2b74cb69c7f39ca1e62c24c0488d6bf01cd24673c74cd9596bf \ + --hash=sha256:47e07528bb6ccbd6e32a55e330979048b59bfc5518b47c89bc7ab9e3de15174a \ + --hash=sha256:48d82770a5fd88778063604c566f9c7c71820270c9cc9338d25147cbf34afd96 \ + --hash=sha256:4b4b4f8f0b1d3ef8dc73e55363a0ffe012a42f4e2f1a140bf559698dca39b3fa \ + --hash=sha256:4bda5426ebb02ceb806a7d7ec9ba9ee5e0c93fca62375151a7b1c00bc634d06b \ + --hash=sha256:4cddbe41ee04fddad35d75b9cf3e3736ad0b80588280766156b94783167777af \ + --hash=sha256:4dd34e7e2518de8d7834268846f8cab7204364f427c56fb2251e098da86f5092 \ + --hash=sha256:5072488fcc5cbcda2ece966d248e43ea1d222e19dd4c56d3f82747777f24d864 \ + --hash=sha256:507d6012fab05465d8bf21f5d7f4635ba4b6d60132874e349beff12fb51af7fe \ + --hash=sha256:53cfefe4af059e65aabe9683f76b9c88bf34b4341a77d329227c2424e0e59b0e \ + --hash=sha256:5a31e84782a18c30abd56774c0cfa7b9884589f4d37d9acabfa0504dad59bb9d \ + --hash=sha256:5b2dc7e88da4ca201c940f5e6127998d9e89aa64264292334dad62854bc7fc27 \ + --hash=sha256:5caf7f13f2e1b4e137060aed892d4541d07dabc3f29e6d891e2383c7ed483440 \ + --hash=sha256:5dbf06642f3db2966df504944cdd0eb68ca2717f0353bb20b20acd78109374a6 \ + --hash=sha256:5fd44d69ddfdfb4e8d0d83f09d27a4db34930fba153fbf79f8d4ae8b47914e04 \ + --hash=sha256:6162a1a757a1f1f4a94bc6ffac834a3602e04ad5db022dd8395a54ed9dd51c81 \ + --hash=sha256:6334d2382aff975a61f6f4d1c3daf39368b887c7de08f7c16c58f485dcf7adb2 \ + --hash=sha256:6723be919c07906781b9c63cc52dc7d2fb101336c99dd7e85d3531d73fb493f7 \ + --hash=sha256:68e10fd804e44e36188b9952543e3fa22f5aa8394da1b5283ca2b423735c06e8 \ + --hash=sha256:72e18088f567bd4a45db5e3196677d9ed1605e356e500c8e32dd6e303167a13d \ + --hash=sha256:77c0fe28ed659b62273995244ae2aa430e432c71f86e4573ab16caa2f2e3ca5e \ + --hash=sha256:78404206977c9f946613d3f916727c189d43193e708d760ea5d4b2087d6b0968 \ + --hash=sha256:7b71ef394327b3d0b39f6ea7ade2ecda2731a56c6a7cbf0d6a7301203b92a89b \ + --hash=sha256:848be553ea35aa89bfefbed2e27c8a41244c862956ab8ba00dc0b27e84fd58de \ + --hash=sha256:912579642f5d7a4a84d93c5eed8daf0aa34e1f2d3f4dc6571a8e418703f5701e \ + --hash=sha256:92d771c492b64119456afb50f2dff3e03a2db8b5af0eba32c5932d306f970532 \ + --hash=sha256:93d5abed5a6f9e1b6f9b5bf6ed4423c11932b5447c2f7281d3b64e0f26c6d064 \ + --hash=sha256:9e217ce3bad76351e1eb29ebe5ca630326f45cd2141f62620107a229909501a3 \ + --hash=sha256:9e26794fe3976810b2c01fda29bd9ac7c91a3c1284b29cc9a383989f7b614037 \ + --hash=sha256:a3d0855b643f259ee0cb76fe3df4c04483354409a520a902b067c674842eb6b8 \ + --hash=sha256:b1545083b0931f754c80fd2422a73d83bea7a6d1b6de104a5f2c8dd3d64c291e \ + --hash=sha256:b1e6415c5b5ff3a616a6dafad7b6ec303a9fc625e9313c8e1268fb1370a63dcb \ + --hash=sha256:b5861c5f7acff10599132854c70ab10abf72aebf7c627ae13575e5f20b1ab8fe \ + --hash=sha256:b8ac64caba1add2c04e9cd4782d4d0c4d6c554b7a3369bdec1eed7854c98db7b \ + --hash=sha256:ba49683b87bea3ae1489a88e766e767d4f423a669a61270b6d6a7ead1c33bd65 \ + --hash=sha256:bb7c36d5d3570fcbb01d24fa447a21a7fe5a41141fd88e78f7994053cc4e28f4 \ + --hash=sha256:be3d0653322abc9b68e5bcdaee6cfd58fcbe9973740ab222b87f4d687232ab1f \ + --hash=sha256:c4aa13ca959ba6b15c0a98d3d204b850f9dc36c08c9ce422ffb024eb30d6e058 \ + --hash=sha256:c964c29711a4b1df52f8d9966f015402a6cf87753a406c1c4405c407dd66fd45 \ + --hash=sha256:d346e2ae1ce17888f7040b65a5a4a0c9734cb20ffbd228728661e020b4c8b3a5 \ + --hash=sha256:d6895d32032b6362540e6d0694b19130bb4f2ad04694002dce7d8af588ca5f77 \ + --hash=sha256:d6d308dd578ae3658f62bb9eba54801533225823cd3248c902be1ebc79b5e014 \ + --hash=sha256:d777c57c1f86855fe5492b973f1012be776e0398571f7cc3970e9a58ecf4dc17 \ + --hash=sha256:db48f8e81072e26df6cdb0e9fff808c28597c6ac20a13d595756cf9ba1fed48a \ + --hash=sha256:dbee6b050062540ae404530cacec1bf25e56e8d87d8d9b610b935afeb6725cae \ + --hash=sha256:dddf4e78747fa7f2188273f84562017a3c4f0824485b78372513c1681ea7a894 \ + --hash=sha256:df146f2a14116ce80f7da669785fcb411406d8e80136558b0ecda4c924b9ac55 \ + --hash=sha256:e5adaf01b92e0402a9ac5c3ebe04effe2bbb115f0914a0a53d34ea239a746289 \ + --hash=sha256:e7a840752c93d4eecd1378e9bb465c3703e127b58f675cd5c620f361b6cf57a4 \ + --hash=sha256:e855c1e97208133ce88b3ef6663c9a82ddf1d09390cd0856a1638deee0390c3c \ + --hash=sha256:e9a5fd589951f02ec2fcb8d69339258bbf74b41b104c556e6d4420ea5e059313 \ + --hash=sha256:f2d3364cfad43003f1e3d564a069c8866237cca30f9c914b26ed2740b596ed00 \ + --hash=sha256:f3807cce72bf40a9d251d689cbec28d2efd27e0f6673709f948f971afd52cb09 \ + --hash=sha256:f3cf6c07f8b32127d836be8e1c55d4f34843f7df346536da768e9f73f22078a1 \ + --hash=sha256:f55e557d4248322d87c4673e085c7634039ff04b47bfc823b87149ae12bef60d \ + --hash=sha256:f58ae2bcd119226fe4aa934b5880fe57b8e97b69e51d5d91c88a89477a307016 \ + --hash=sha256:f716bcc166524eddfcf9f13f8209ac19a7f27b05cf591e883419079d98c8c99d \ + --hash=sha256:f857b3d134b36a8436f1e24dcb525b6b945108b30746c1b0b556200b5cb76d39 \ + --hash=sha256:fa3fe8653c9f57f0e16f008e43626485b6723b84b2f741f54d1258095b655912 + # via -r src/requirements.txt +packaging==25.0 \ + --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \ + --hash=sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f + # via + # limits + # pytest +parso==0.8.4 \ + --hash=sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18 \ + --hash=sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d + # via mutmut +pgpy==0.6.0 \ + --hash=sha256:279c2e353f4c3a319f00bd9bd582456e420f8a3ac6de2b4e9731444746828383 + # via -r src/requirements.txt +pillow==11.3.0 \ + --hash=sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2 \ + --hash=sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214 \ + --hash=sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e \ + --hash=sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59 \ + --hash=sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50 \ + --hash=sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632 \ + --hash=sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06 \ + --hash=sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a \ + --hash=sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51 \ + --hash=sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced \ + --hash=sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f \ + --hash=sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12 \ + --hash=sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8 \ + --hash=sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6 \ + --hash=sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580 \ + --hash=sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f \ + --hash=sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac \ + --hash=sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860 \ + --hash=sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd \ + --hash=sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722 \ + --hash=sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8 \ + --hash=sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4 \ + --hash=sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673 \ + --hash=sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788 \ + --hash=sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542 \ + --hash=sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e \ + --hash=sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd \ + --hash=sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8 \ + --hash=sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523 \ + --hash=sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967 \ + --hash=sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809 \ + --hash=sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477 \ + --hash=sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027 \ + --hash=sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae \ + --hash=sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b \ + --hash=sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c \ + --hash=sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f \ + --hash=sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e \ + --hash=sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b \ + --hash=sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7 \ + --hash=sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27 \ + --hash=sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361 \ + --hash=sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae \ + --hash=sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d \ + --hash=sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc \ + --hash=sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58 \ + --hash=sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad \ + --hash=sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6 \ + --hash=sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024 \ + --hash=sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978 \ + --hash=sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb \ + --hash=sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d \ + --hash=sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0 \ + --hash=sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9 \ + --hash=sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f \ + --hash=sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874 \ + --hash=sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa \ + --hash=sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081 \ + --hash=sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149 \ + --hash=sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6 \ + --hash=sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d \ + --hash=sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd \ + --hash=sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f \ + --hash=sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c \ + --hash=sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31 \ + --hash=sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e \ + --hash=sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db \ + --hash=sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6 \ + --hash=sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f \ + --hash=sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494 \ + --hash=sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69 \ + --hash=sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94 \ + --hash=sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77 \ + --hash=sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d \ + --hash=sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7 \ + --hash=sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a \ + --hash=sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438 \ + --hash=sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288 \ + --hash=sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b \ + --hash=sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635 \ + --hash=sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3 \ + --hash=sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d \ + --hash=sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe \ + --hash=sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0 \ + --hash=sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe \ + --hash=sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a \ + --hash=sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805 \ + --hash=sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8 \ + --hash=sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36 \ + --hash=sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a \ + --hash=sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b \ + --hash=sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e \ + --hash=sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25 \ + --hash=sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12 \ + --hash=sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada \ + --hash=sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c \ + --hash=sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71 \ + --hash=sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d \ + --hash=sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c \ + --hash=sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6 \ + --hash=sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1 \ + --hash=sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50 \ + --hash=sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653 \ + --hash=sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c \ + --hash=sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4 \ + --hash=sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3 + # via -r src/requirements.txt +pluggy==1.6.0 \ + --hash=sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3 \ + --hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746 + # via + # pytest + # pytest-cov +pony==0.7.19 \ + --hash=sha256:5112b4cf40d3f24e93ae66dc5ab7dc6813388efa870e750928d60dc699873cf5 \ + --hash=sha256:f7f83b2981893e49f7f18e8def52ad8fa8f8e6c5f9583b9aaed62d4d85036a0f + # via mutmut +portalocker==3.2.0 \ + --hash=sha256:1f3002956a54a8c3730586c5c77bf18fae4149e07eaf1c29fc3faf4d5a3f89ac \ + --hash=sha256:3cdc5f565312224bc570c49337bd21428bba0ef363bbcf58b9ef4a9f11779968 + # via -r src/requirements.txt +propcache==0.3.2 \ + --hash=sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c \ + --hash=sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81 \ + --hash=sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f \ + --hash=sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6 \ + --hash=sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535 \ + --hash=sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be \ + --hash=sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba \ + --hash=sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3 \ + --hash=sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0 \ + --hash=sha256:1f43837d4ca000243fd7fd6301947d7cb93360d03cd08369969450cc6b2ce3b4 \ + --hash=sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168 \ + --hash=sha256:2183111651d710d3097338dd1893fcf09c9f54e27ff1a8795495a16a469cc90b \ + --hash=sha256:21d8759141a9e00a681d35a1f160892a36fb6caa715ba0b832f7747da48fb6ea \ + --hash=sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770 \ + --hash=sha256:261df2e9474a5949c46e962065d88eb9b96ce0f2bd30e9d3136bcde84befd8f2 \ + --hash=sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892 \ + --hash=sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154 \ + --hash=sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf \ + --hash=sha256:2ca6d378f09adb13837614ad2754fa8afaee330254f404299611bce41a8438cb \ + --hash=sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1 \ + --hash=sha256:31248e44b81d59d6addbb182c4720f90b44e1efdc19f58112a3c3a1615fb47ef \ + --hash=sha256:34a624af06c048946709f4278b4176470073deda88d91342665d95f7c6270fbe \ + --hash=sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897 \ + --hash=sha256:3def3da3ac3ce41562d85db655d18ebac740cb3fa4367f11a52b3da9d03a5cc3 \ + --hash=sha256:404d70768080d3d3bdb41d0771037da19d8340d50b08e104ca0e7f9ce55fce70 \ + --hash=sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330 \ + --hash=sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44 \ + --hash=sha256:4927842833830942a5d0a56e6f4839bc484785b8e1ce8d287359794818633ba0 \ + --hash=sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88 \ + --hash=sha256:4ba3fef1c30f306b1c274ce0b8baaa2c3cdd91f645c48f06394068f37d3837a1 \ + --hash=sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3 \ + --hash=sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43 \ + --hash=sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4 \ + --hash=sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1 \ + --hash=sha256:55ffda449a507e9fbd4aca1a7d9aa6753b07d6166140e5a18d2ac9bc49eac220 \ + --hash=sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7 \ + --hash=sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9 \ + --hash=sha256:5f559e127134b07425134b4065be45b166183fdcb433cb6c24c8e4149056ad50 \ + --hash=sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e \ + --hash=sha256:6107ddd08b02654a30fb8ad7a132021759d750a82578b94cd55ee2772b6ebea2 \ + --hash=sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66 \ + --hash=sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1 \ + --hash=sha256:64a67fb39229a8a8491dd42f864e5e263155e729c2e7ff723d6e25f596b1e8cb \ + --hash=sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe \ + --hash=sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c \ + --hash=sha256:70bd8b9cd6b519e12859c99f3fc9a93f375ebd22a50296c3a295028bea73b9e7 \ + --hash=sha256:7435d766f978b4ede777002e6b3b6641dd229cd1da8d3d3106a45770365f9ad9 \ + --hash=sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e \ + --hash=sha256:76cace5d6b2a54e55b137669b30f31aa15977eeed390c7cbfb1dafa8dfe9a701 \ + --hash=sha256:7a2368eed65fc69a7a7a40b27f22e85e7627b74216f0846b04ba5c116e191ec9 \ + --hash=sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8 \ + --hash=sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b \ + --hash=sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f \ + --hash=sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e \ + --hash=sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02 \ + --hash=sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e \ + --hash=sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1 \ + --hash=sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10 \ + --hash=sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387 \ + --hash=sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198 \ + --hash=sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f \ + --hash=sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b \ + --hash=sha256:9bec58347a5a6cebf239daba9bda37dffec5b8d2ce004d9fe4edef3d2815137e \ + --hash=sha256:9da1cf97b92b51253d5b68cf5a2b9e0dafca095e36b7f2da335e27dc6172a614 \ + --hash=sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252 \ + --hash=sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9 \ + --hash=sha256:a7fad897f14d92086d6b03fdd2eb844777b0c4d7ec5e3bac0fbae2ab0602bbe5 \ + --hash=sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c \ + --hash=sha256:abb7fa19dbf88d3857363e0493b999b8011eea856b846305d8c0512dfdf8fbb1 \ + --hash=sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770 \ + --hash=sha256:aff2e4e06435d61f11a428360a932138d0ec288b0a31dd9bd78d200bd4a2b339 \ + --hash=sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251 \ + --hash=sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db \ + --hash=sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf \ + --hash=sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95 \ + --hash=sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df \ + --hash=sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2 \ + --hash=sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945 \ + --hash=sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474 \ + --hash=sha256:cc2782eb0f7a16462285b6f8394bbbd0e1ee5f928034e941ffc444012224171b \ + --hash=sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615 \ + --hash=sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06 \ + --hash=sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33 \ + --hash=sha256:d4a996adb6904f85894570301939afeee65f072b4fd265ed7e569e8d9058e4ec \ + --hash=sha256:d81ac3ae39d38588ad0549e321e6f773a4e7cc68e7751524a22885d5bbadf886 \ + --hash=sha256:db429c19a6c7e8a1c320e6a13c99799450f411b02251fb1b75e6217cf4a14fcb \ + --hash=sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1 \ + --hash=sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05 \ + --hash=sha256:e514326b79e51f0a177daab1052bc164d9d9e54133797a3a58d24c9c87a3fe6d \ + --hash=sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39 \ + --hash=sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67 \ + --hash=sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e \ + --hash=sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28 \ + --hash=sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a \ + --hash=sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394 \ + --hash=sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725 \ + --hash=sha256:fb075ad271405dcad8e2a7ffc9a750a3bf70e533bd86e89f0603e607b93aa64c \ + --hash=sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206 + # via + # aiohttp + # yarl +py-sr25519-bindings==0.2.2 \ + --hash=sha256:04a2f2eac269bb2f9bf30c795990211cd8d4cfdd28eafbd73b2dfc77a9ef940f \ + --hash=sha256:09657937b8f04c034622691c4753fcef0b3857939dbeff72590b7f5de336302d \ + --hash=sha256:0b5c5f9080e879badefff596361520b2d9de9d9c4be7c14b36a017d798c451e2 \ + --hash=sha256:0b8b2666d381416fb07336c6596a5554dd0e0f1ec50ff32bcc975ae29df79961 \ + --hash=sha256:0c2483031813f908da35c380196bc88410e2542482a5b4b51d265c6566de116c \ + --hash=sha256:0e4217f59936ae13fa4215838d2da59c130572408e3f29a9f7ca436924f4b356 \ + --hash=sha256:0f496da3eb2d843bd12ccff871d22d086b08cfe95852ca91dcdbd91e350aca8d \ + --hash=sha256:1111597744d7993ce732f785e97e0d2e4f9554509d90ba4b0e99829dbf1c2e6d \ + --hash=sha256:1350c85bdc903105d8fdc7dd369b802bf2821c321fea8aa0929f7a7063437d81 \ + --hash=sha256:1393798a36f74482c53c254969ae8d92f6549767ef69575206eaaf629cbf2a64 \ + --hash=sha256:15ae6f86f112c6b23d357b5a98a6cb493f5c2734fabff354a8198be9dea0e90e \ + --hash=sha256:16501bd5b9a37623dbf48aa6b197c57c004f9125e190450e041289a8c3eceac7 \ + --hash=sha256:192d65d3bc43c6f4121a0732e1f6eb6ad869897ca26368ba032e96a82b3b7606 \ + --hash=sha256:1a65275421f30e3d563c6f3dec552060f1f85b7840ab8ecf1d48ced008d0ba5f \ + --hash=sha256:1fce13a3434c57af097b8b07b69e3821b1f10623754204112c14bd544bd961c1 \ + --hash=sha256:25e6f2c026aa910cac7f16723b6b3e9736fe805e51b6ba41cfb4e25a4c0a6442 \ + --hash=sha256:2777013ff914bcc87e657657e99922fa48f3bb674734550989fb210fb3d878a2 \ + --hash=sha256:277e8ef38c9d899b1855fdcde07ae73a9917e06c46df556b8ca3216ae585b532 \ + --hash=sha256:292be23ad53d9f9dbf1703a2a341005629a8f93c57cfad254c8c1230ec7d3fe3 \ + --hash=sha256:297e29518a01a24b943333fc9fe5e7102cb7083f2d256270f42476bcf5ba666d \ + --hash=sha256:29b9ee2e2f8f36676fa2a72af5bdfe257d331b3d83e5a92b45bad2f25a5b975c \ + --hash=sha256:2ee25565a287690d6e48302f4584775622ce3329d2ab92fd3b0a4f063d4ca91f \ + --hash=sha256:30f1af9306fda911f296db29b4fff06197d3f38de5643b3d95862d3833db1e41 \ + --hash=sha256:314893d4ea96877560bc12446956d61707ca46fb99040ffad751a0710a7aa87f \ + --hash=sha256:315382f207430143cd748f805f13bf56f36fc66726303b491cd38ce78d8972e9 \ + --hash=sha256:3a34fa18885345a0102c3ffbaa17a32cd67d28a60376158508d5ed7f96a478f7 \ + --hash=sha256:3bb2c5fba39a82880c43b0d75e87f4d4a2416717c5fa2122b22e02689c2120e3 \ + --hash=sha256:3d0afcb14cd493485175dc9bf8c57b8b37581bbb29f55b6e4f3ce1f803222488 \ + --hash=sha256:3d3c6836df2d67008e3f11080fb216e414cc924de256dd118e50a92cd334f143 \ + --hash=sha256:3de67c503155019c494e5887d1797f046afe1aeb99ee4b3cf86c15386330f034 \ + --hash=sha256:3e5bf9343f3708cfdf5228dbb1b8a093c64144bb9c4bd02cfb014fb2241dd965 \ + --hash=sha256:3ea3dc2c6a2a38b791114bd50021f10db2dd2a1d7a1a1aac0c7e80d885c0d3b5 \ + --hash=sha256:48f053c5e8cb66125057b25223ef5ff57bb4383a82871d47089397317c5fd792 \ + --hash=sha256:4c0931d8fd07e13131e652f3211c1f1c12b7a5153bed9217e4483b195515c76f \ + --hash=sha256:4dd5cfe48faafa7e112a021284663db8b64efd9b2225e69906f0bf7f3159a3ce \ + --hash=sha256:4e932c33f6b660319c950c300c32ad2c0ba9642743a2e709a2fb886d32c28baf \ + --hash=sha256:50976e9b22328df5696fcbfded27215a35225ee41e0b3f1b26a01ab00ad08143 \ + --hash=sha256:512185a3be65a893208e9c30d11948c8b405532756f3bcab16d1dbe5d8e3355e \ + --hash=sha256:5329e2e54eb9850c2eb84d6a226bd98cdc3597535453eced920035e1e026dced \ + --hash=sha256:55134f0ba34c27fbb8b489a338c6cb6a31465813f615ed93afbd67e844ef3aed \ + --hash=sha256:5644353660fd9f97318d70fb7cf362f969a5ee572b61df8f18eda5fea80a6514 \ + --hash=sha256:56eeafc92d3c66990ab97ff91c09b3295aea6dac9b64af0227750a8192aeaeec \ + --hash=sha256:58702966f1547e47bfbf70924eef881087bff969e2dca15953cdc95cb2abb4a2 \ + --hash=sha256:58b1e28fc1c57f69d37556b8f3c51cdd84446f643729789b6c0ce19ce2726bd5 \ + --hash=sha256:5e927dd15d61e76fde3fa8bd6d776148ea987944fee1fe815fbc40c6a77f61ad \ + --hash=sha256:62e4bdd094589446a24dc1029cf2ef6c869e1f4fede04e17335bc92e60640fc5 \ + --hash=sha256:6449963cd6b300b224a1bc1fec77df012e30d609e54ccffe4f44f4563eab27c2 \ + --hash=sha256:6584cf4c87fae9bdd64bc50dd786d9c805165bb6bc7a1ff545e77b29a78acb8d \ + --hash=sha256:673b31e8f59bc1478814b011921073f8ad4e2c78a1d6580b3ddb1a9d7edc4392 \ + --hash=sha256:695e80ccdb710efba2f909235b18eaf230cf0b3f60e8d52a1c904eaeeff839ba \ + --hash=sha256:6ca700354e8cc3d082426ca5cdc7dd34a05988adec4edc0cd42d31c4ba16fbc0 \ + --hash=sha256:702a28e8ead7d1d664bea22168158edcc0e3d36e5cc1a79c7373ab1636f89cc2 \ + --hash=sha256:726346118fc2b785525945ee71ea1acf9be84c41e266c2345c93c7d4d6132cbc \ + --hash=sha256:727f91cff7901db2d4e0f762dafd48c2b1086945b4903dcdd0a3eb65624c17c8 \ + --hash=sha256:76e660007dd415de22b1d99a884ee39cb6abf03f24377f58e4498533856c2bac \ + --hash=sha256:776d1a1f114b1f0553c9c8336545daaf20443d0b681c47c499377f69406f7a56 \ + --hash=sha256:77f7f4b323c628242909228eaac78bf6376b39b8988704e7910e858c2017b487 \ + --hash=sha256:785521c868738a2345e3625ad9166ede228f63e9d3f0c7ff8e35f49d636bce04 \ + --hash=sha256:7b20210a0a0b39e3f0bcb7832a3df736eeea2fcc5776dba1ce5b0c050e489145 \ + --hash=sha256:7bf982a7d34f6eb0c7c42b7f59610a527e9b02654079fb78d7eb757c6bd79d9d \ + --hash=sha256:840c3ec1fc8dde12421369afa9761943efe377a7bd55a97524587e8b5a6546c2 \ + --hash=sha256:849f77ab12210e8549e58d444e9199d9aba83a988e99ca8bef04dd53e81f9561 \ + --hash=sha256:84cb2c645ce60a04688dedf61ed289d4fb716aef4129313814be1a2d47e268e7 \ + --hash=sha256:85432a949143d7a20e452b4c89d5f0ad9a0162e1ce5a904fc157fe204cbe5ded \ + --hash=sha256:862fa69f948cb3028051a71ce0d2d88cbe8b52723c782f0972d12f5f85a25637 \ + --hash=sha256:888d98a2d7736e0f269c8ab1f09dfac04af2d024b18c0485adc3615277f3442b \ + --hash=sha256:8ab2b063129babc8f1d9fe6cf5c2d8cc434b6797c553440302da1fab987d74ab \ + --hash=sha256:8c9ee94a9fa1625f3192c89ecacc2bd012e09b57e6d2ad8ede027b31381609d3 \ + --hash=sha256:8cc531500823ece8d6889082642e9ea06f2eaffd0ed43d65871cb4727429027c \ + --hash=sha256:9b5b2cdf08be144f395508acebd5fa41c81dbee1364de75ff80fe0f1308fd969 \ + --hash=sha256:9cdb4e0f231fd5824f73361a37a102871866d29752f96d88b1da958f1e5ff2d4 \ + --hash=sha256:9efc5526c0eb74c2f8df809c47e22d62febc31db8f38b5c6b1253e810e0ed71f \ + --hash=sha256:a26b1add87dc6086463975aa1d889f39f90b0d22949d4de52e8a53e516bd2ac4 \ + --hash=sha256:a42353737c22a3fa425ac350f5fac74d5b2f9c3cdb8ad44dbb367bd7869774cc \ + --hash=sha256:a9b8c9a81f90dc330eabbdc3ec5f9fdf84a34cd37a1e660cbf5c5daec7b2d08f \ + --hash=sha256:ab25059d290753202f160bb8a4fd3c789ab9663381ca564338015fd3b7625dde \ + --hash=sha256:acebe18639616cd00ad0544d9bdaa73c545f00c4fc0d29b8a4e1e6c447f7a607 \ + --hash=sha256:b1199dab44704aa34401428ca3170da5b7ffdc8c65208a2c75a3c1fe5298b20e \ + --hash=sha256:b312b8ac7c8354d5cf1b9aad993bbafbd99cc97b6d246f246e76814f576ed809 \ + --hash=sha256:b32743bba0a53225097120b212da88c14584022a357d7e91cf19ed0a3adad9f6 \ + --hash=sha256:b74c31e2960c4af5b709b562aaf610989af532aee771fcdf175533de60441607 \ + --hash=sha256:b8a479a7510f30d2912f552335cb83d321c0be83832a71cd0bcd190f6356a7bf \ + --hash=sha256:bc7ecd25700a664d835cc9db5f6a4f65fef62a395762487c8c2a661566316e8f \ + --hash=sha256:bd29a2ee1dfa55a3e17cf18fe0fa5f5749e0c49c9bd9c423a46e1cc242225447 \ + --hash=sha256:beb12471fb76be707fc9213d39e5be4cf4add7e38e08bc1fbf7e786250977e00 \ + --hash=sha256:c3ee5fd07b2974ce147ac7546b18729d2eb4efebe8eaad178690aaca656487f3 \ + --hash=sha256:c4518b553335f70f18b8167eb2b7f533a66eb703f251d4d4b36c4a03d14cd75e \ + --hash=sha256:c63b0966b45870f0b1dfc2a366f1763f4a165f3aec2b02e7464cfb2c6ca09e94 \ + --hash=sha256:c70ff898fa46f380a535c843e3a1a9824d1849216067bbf28eb9ad225b92f0bb \ + --hash=sha256:c8cab5620a4ef4cc69a314c9e9ac17af1c0d4d11e297fcefe5d71d827fd7ee21 \ + --hash=sha256:c917a8f365450be06e051f8d8671c182057cdda42bd5f6883c5f537a2bac4f5a \ + --hash=sha256:cba9efa48f48bf56e73a528005978b6f05cb2c847e21eb9645bbc6581619482f \ + --hash=sha256:cc40a53600e68848658cf6046cd43ef2ec9f0c8c04ebf8ea3636dd58c1c25296 \ + --hash=sha256:cf8c1d329275c41836aee5f8789ab14100dbdc2b6f3a0210fac2abb0f7507c24 \ + --hash=sha256:d9ee79ec4e722993da24385a8eb85d97878ef67d48d0e706c098c626d798c7bc \ + --hash=sha256:daa74fdd7bac2d97fbbbbb1ca40a0c02102220d09cfa9695cbde8d2cbedfadb7 \ + --hash=sha256:dc5a57b67384244083b8d0831f9490dadca34e0543c1bf2f3a876aa4e7081961 \ + --hash=sha256:ddb490e99d5646ba68f5308fed1b92efbc85470b1171a2b78e555b44a7073570 \ + --hash=sha256:e0728fff2a29d4cc76c4cf22142cd2e2e8dc37745b213a866412980191e1260c \ + --hash=sha256:e1a48b295b562836d72dee7136c0503ea63cd89fec85d418b91ba040471c37ed \ + --hash=sha256:e1d436db7f48dabd4201bb1a88c66a6a3cd15a40e89a236ec1b8cb60037dc1a9 \ + --hash=sha256:e4c95b3b6230faf2e89f6e5407d63a9d0d52385e6b7d42205570f5ee2f927940 \ + --hash=sha256:e9ac26fd6b8606796fcaee90fe277820efbe168490659d26295fd0fc7b37ee4a \ + --hash=sha256:ea139e7bf80ddc1c682db439825bec56baf745d643c146a783e9ddb737af266a \ + --hash=sha256:f1ab3c36d94dec25767e2a54a2fb0eb320fc0c3e1d7ea573288b961d432672ef \ + --hash=sha256:f1bf93d46ab717089f4fac9b764ea4e7be9f4a45a62bd9919ef850ae8d2ae433 \ + --hash=sha256:f22542738ed98fac0d3da2479dd3f26c695594800877a4d8bb116c47e4fd4b7c \ + --hash=sha256:f44a0a9cb155af6408e3f73833a935abc98934ce097b2ad07dd13e3a88f82cb8 \ + --hash=sha256:f46c87fd7a8e55c4fce272d4e34663d3c7c3ffee906826a2a16a1400027aa5b9 \ + --hash=sha256:f7126db740eb190cf1ba993e066f03c2914edaf08e6963d10bbdd740922c95e6 \ + --hash=sha256:fd56849d9195693c6a8e7c48efe4256918b6afeec090915f3f8f883cdb8addda \ + --hash=sha256:fea3ce0ac6a26a52735bb48f8daafb82d17147f776bb6d9d3c330bd2ccffe20d + # via bip-utils +pyasn1==0.6.1 \ + --hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629 \ + --hash=sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034 + # via pgpy +pycparser==2.22 \ + --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ + --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc + # via cffi +pycryptodome==3.23.0 \ + --hash=sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4 \ + --hash=sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c \ + --hash=sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630 \ + --hash=sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f \ + --hash=sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27 \ + --hash=sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a \ + --hash=sha256:350ebc1eba1da729b35ab7627a833a1a355ee4e852d8ba0447fafe7b14504d56 \ + --hash=sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef \ + --hash=sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5 \ + --hash=sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477 \ + --hash=sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886 \ + --hash=sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a \ + --hash=sha256:573a0b3017e06f2cffd27d92ef22e46aa3be87a2d317a5abf7cc0e84e321bd75 \ + --hash=sha256:63dad881b99ca653302b2c7191998dd677226222a3f2ea79999aa51ce695f720 \ + --hash=sha256:64093fc334c1eccfd3933c134c4457c34eaca235eeae49d69449dc4728079339 \ + --hash=sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625 \ + --hash=sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490 \ + --hash=sha256:6fe8258e2039eceb74dfec66b3672552b6b7d2c235b2dfecc05d16b8921649a8 \ + --hash=sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b \ + --hash=sha256:7ac1080a8da569bde76c0a104589c4f414b8ba296c0b3738cf39a466a9fb1818 \ + --hash=sha256:865d83c906b0fc6a59b510deceee656b6bc1c4fa0d82176e2b77e97a420a996a \ + --hash=sha256:89d4d56153efc4d81defe8b65fd0821ef8b2d5ddf8ed19df31ba2f00872b8002 \ + --hash=sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae \ + --hash=sha256:93837e379a3e5fd2bb00302a47aee9fdf7940d83595be3915752c74033d17ca7 \ + --hash=sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d \ + --hash=sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265 \ + --hash=sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39 \ + --hash=sha256:a176b79c49af27d7f6c12e4b178b0824626f40a7b9fed08f712291b6d54bf566 \ + --hash=sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353 \ + --hash=sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b \ + --hash=sha256:b34e8e11d97889df57166eda1e1ddd7676da5fcd4d71a0062a760e75060514b4 \ + --hash=sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2 \ + --hash=sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575 \ + --hash=sha256:ce64e84a962b63a47a592690bdc16a7eaf709d2c2697ababf24a0def566899a6 \ + --hash=sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843 \ + --hash=sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4 \ + --hash=sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446 \ + --hash=sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379 \ + --hash=sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa \ + --hash=sha256:e3f2d0aaf8080bda0587d58fc9fe4766e012441e2eed4269a77de6aea981c8be \ + --hash=sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7 + # via bip-utils +pydantic==2.11.7 \ + --hash=sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db \ + --hash=sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b + # via fastapi +pydantic-core==2.33.2 \ + --hash=sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d \ + --hash=sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac \ + --hash=sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02 \ + --hash=sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56 \ + --hash=sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4 \ + --hash=sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22 \ + --hash=sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef \ + --hash=sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec \ + --hash=sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d \ + --hash=sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b \ + --hash=sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a \ + --hash=sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f \ + --hash=sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052 \ + --hash=sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab \ + --hash=sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916 \ + --hash=sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c \ + --hash=sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf \ + --hash=sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27 \ + --hash=sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a \ + --hash=sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8 \ + --hash=sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7 \ + --hash=sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612 \ + --hash=sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1 \ + --hash=sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039 \ + --hash=sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca \ + --hash=sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7 \ + --hash=sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a \ + --hash=sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6 \ + --hash=sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782 \ + --hash=sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b \ + --hash=sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7 \ + --hash=sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025 \ + --hash=sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849 \ + --hash=sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7 \ + --hash=sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b \ + --hash=sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa \ + --hash=sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e \ + --hash=sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea \ + --hash=sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac \ + --hash=sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51 \ + --hash=sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e \ + --hash=sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162 \ + --hash=sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65 \ + --hash=sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2 \ + --hash=sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954 \ + --hash=sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b \ + --hash=sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de \ + --hash=sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc \ + --hash=sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64 \ + --hash=sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb \ + --hash=sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9 \ + --hash=sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101 \ + --hash=sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d \ + --hash=sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef \ + --hash=sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3 \ + --hash=sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1 \ + --hash=sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5 \ + --hash=sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88 \ + --hash=sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d \ + --hash=sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290 \ + --hash=sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e \ + --hash=sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d \ + --hash=sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808 \ + --hash=sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc \ + --hash=sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d \ + --hash=sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc \ + --hash=sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e \ + --hash=sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640 \ + --hash=sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30 \ + --hash=sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e \ + --hash=sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9 \ + --hash=sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a \ + --hash=sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9 \ + --hash=sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f \ + --hash=sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb \ + --hash=sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5 \ + --hash=sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab \ + --hash=sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d \ + --hash=sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572 \ + --hash=sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593 \ + --hash=sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29 \ + --hash=sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535 \ + --hash=sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1 \ + --hash=sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f \ + --hash=sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8 \ + --hash=sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf \ + --hash=sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246 \ + --hash=sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9 \ + --hash=sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011 \ + --hash=sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9 \ + --hash=sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a \ + --hash=sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3 \ + --hash=sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6 \ + --hash=sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8 \ + --hash=sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a \ + --hash=sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2 \ + --hash=sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c \ + --hash=sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6 \ + --hash=sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d + # via pydantic +pygments==2.19.2 \ + --hash=sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887 \ + --hash=sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b + # via + # pytest + # rich +pyjwt==2.10.1 \ + --hash=sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953 \ + --hash=sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb + # via -r src/requirements.txt +pynacl==1.5.0 \ + --hash=sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858 \ + --hash=sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d \ + --hash=sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93 \ + --hash=sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1 \ + --hash=sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92 \ + --hash=sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff \ + --hash=sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba \ + --hash=sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394 \ + --hash=sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b \ + --hash=sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543 + # via bip-utils +pyotp==2.9.0 \ + --hash=sha256:346b6642e0dbdde3b4ff5a930b664ca82abfa116356ed48cc42c7d6590d36f63 \ + --hash=sha256:81c2e5865b8ac55e825b0358e496e1d9387c811e85bb40e71a3b29b288963612 + # via -r src/requirements.txt +pyperclip==1.9.0 \ + --hash=sha256:b7de0142ddc81bfc5c7507eea19da920b92252b548b96186caf94a5e2527d310 + # via -r src/requirements.txt +pytest==8.4.1 \ + --hash=sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7 \ + --hash=sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c + # via + # -r src/requirements.txt + # pytest-cov + # pytest-xdist +pytest-cov==6.2.1 \ + --hash=sha256:25cc6cc0a5358204b8108ecedc51a9b57b34cc6b8c967cc2c01a4e00d8a67da2 \ + --hash=sha256:f5bc4c23f42f1cdd23c70b1dab1bbaef4fc505ba950d53e0081d0730dd7e86d5 + # via -r src/requirements.txt +pytest-xdist==3.8.0 \ + --hash=sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88 \ + --hash=sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1 + # via -r src/requirements.txt +python-dateutil==2.9.0.post0 \ + --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ + --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 + # via freezegun +python-multipart==0.0.20 \ + --hash=sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104 \ + --hash=sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13 + # via -r src/requirements.txt +qrcode==8.2 \ + --hash=sha256:16e64e0716c14960108e85d853062c9e8bba5ca8252c0b4d0231b9df4060ff4f \ + --hash=sha256:35c3f2a4172b33136ab9f6b3ef1c00260dd2f66f858f24d88418a015f446506c + # via -r src/requirements.txt +requests==2.32.4 \ + --hash=sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c \ + --hash=sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422 + # via -r src/requirements.txt +rich==14.1.0 \ + --hash=sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f \ + --hash=sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8 + # via typer +shellingham==1.5.4 \ + --hash=sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686 \ + --hash=sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de + # via typer +six==1.17.0 \ + --hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \ + --hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81 + # via + # ecdsa + # junit-xml + # python-dateutil +slowapi==0.1.9 \ + --hash=sha256:639192d0f1ca01b1c6d95bf6c71d794c3a9ee189855337b4821f7f457dddad77 \ + --hash=sha256:cfad116cfb84ad9d763ee155c1e5c5cbf00b0d47399a769b227865f5df576e36 + # via -r src/requirements.txt +sniffio==1.3.1 \ + --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ + --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc + # via anyio +sortedcontainers==2.4.0 \ + --hash=sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88 \ + --hash=sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0 + # via hypothesis +starlette==0.47.2 \ + --hash=sha256:6ae9aa5db235e4846decc1e7b79c4f346adf41e9777aebeb49dfd09bbd7023d8 \ + --hash=sha256:c5847e96134e5c5371ee9fac6fdf1a67336d5815e09eb2a01fdb57a351ef915b + # via + # -r src/requirements.txt + # fastapi +termcolor==3.1.0 \ + --hash=sha256:591dd26b5c2ce03b9e43f391264626557873ce1d379019786f99b0c2bee140aa \ + --hash=sha256:6a6dd7fbee581909eeec6a756cff1d7f7c376063b14e4a298dc4980309e55970 + # via -r src/requirements.txt +toga-core==0.5.2 \ + --hash=sha256:bdd3760146b74c8d315cb901392c2b645ab3e5d4cd90114f3e36e0e7dad3d6d1 \ + --hash=sha256:e872cebd2d899e9138f73393e8cd834a55a057aa269608ff7314a853ab33cb4e + # via + # -r src/requirements.txt + # toga-dummy +toga-dummy==0.5.2 \ + --hash=sha256:44ac143a53ea83ab784467279a91173d55e257a769a44993d2f3f54a0c5379df \ + --hash=sha256:93683f47579f3abc54cb0dec8260cb1f23491732e3c7077eac7a86957a67a91c + # via -r src/requirements.txt +toml==0.10.2 \ + --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \ + --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f + # via mutmut +tomli==2.2.1 \ + --hash=sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6 \ + --hash=sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd \ + --hash=sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c \ + --hash=sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b \ + --hash=sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8 \ + --hash=sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6 \ + --hash=sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77 \ + --hash=sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff \ + --hash=sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea \ + --hash=sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192 \ + --hash=sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249 \ + --hash=sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee \ + --hash=sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4 \ + --hash=sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98 \ + --hash=sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8 \ + --hash=sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4 \ + --hash=sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281 \ + --hash=sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744 \ + --hash=sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69 \ + --hash=sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13 \ + --hash=sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140 \ + --hash=sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e \ + --hash=sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e \ + --hash=sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc \ + --hash=sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff \ + --hash=sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec \ + --hash=sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2 \ + --hash=sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222 \ + --hash=sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106 \ + --hash=sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272 \ + --hash=sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a \ + --hash=sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7 + # via -r src/requirements.txt +travertino==0.5.2 \ + --hash=sha256:5afcc673e14e16c3c04c0e3fe387062633e6bc88e87bc0bbd214a04b4dfbbcd4 \ + --hash=sha256:fd69ac3b14f2847e4c972198588b8a86ca3b437aaa0c8ce7259bbe5dab17aff1 + # via toga-core +typer==0.16.0 \ + --hash=sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855 \ + --hash=sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b + # via -r src/requirements.txt +typing-extensions==4.14.1 \ + --hash=sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36 \ + --hash=sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76 + # via + # aiosignal + # anyio + # fastapi + # limits + # pydantic + # pydantic-core + # starlette + # typer + # typing-inspection +typing-inspection==0.4.1 \ + --hash=sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51 \ + --hash=sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28 + # via pydantic +urllib3==2.5.0 \ + --hash=sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760 \ + --hash=sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc + # via requests +uvicorn==0.35.0 \ + --hash=sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a \ + --hash=sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01 + # via -r src/requirements.txt +websocket-client==1.7.0 \ + --hash=sha256:10e511ea3a8c744631d3bd77e61eb17ed09304c413ad42cf6ddfa4c7787e8fe6 \ + --hash=sha256:f4c3d22fec12a2461427a29957ff07d35098ee2d976d3ba244e688b8b4057588 + # via -r src/requirements.txt +websockets==15.0.1 \ + --hash=sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2 \ + --hash=sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9 \ + --hash=sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5 \ + --hash=sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3 \ + --hash=sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8 \ + --hash=sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e \ + --hash=sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1 \ + --hash=sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256 \ + --hash=sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85 \ + --hash=sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880 \ + --hash=sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123 \ + --hash=sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375 \ + --hash=sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065 \ + --hash=sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed \ + --hash=sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41 \ + --hash=sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411 \ + --hash=sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597 \ + --hash=sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f \ + --hash=sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c \ + --hash=sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3 \ + --hash=sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb \ + --hash=sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e \ + --hash=sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee \ + --hash=sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f \ + --hash=sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf \ + --hash=sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf \ + --hash=sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4 \ + --hash=sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a \ + --hash=sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665 \ + --hash=sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22 \ + --hash=sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675 \ + --hash=sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4 \ + --hash=sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d \ + --hash=sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5 \ + --hash=sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65 \ + --hash=sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792 \ + --hash=sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57 \ + --hash=sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9 \ + --hash=sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3 \ + --hash=sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151 \ + --hash=sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d \ + --hash=sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475 \ + --hash=sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940 \ + --hash=sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431 \ + --hash=sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee \ + --hash=sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413 \ + --hash=sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8 \ + --hash=sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b \ + --hash=sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a \ + --hash=sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054 \ + --hash=sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb \ + --hash=sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205 \ + --hash=sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04 \ + --hash=sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4 \ + --hash=sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa \ + --hash=sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9 \ + --hash=sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122 \ + --hash=sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b \ + --hash=sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905 \ + --hash=sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770 \ + --hash=sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe \ + --hash=sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b \ + --hash=sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562 \ + --hash=sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561 \ + --hash=sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215 \ + --hash=sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931 \ + --hash=sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9 \ + --hash=sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f \ + --hash=sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7 + # via -r src/requirements.txt +wrapt==1.17.2 \ + --hash=sha256:08e7ce672e35efa54c5024936e559469436f8b8096253404faeb54d2a878416f \ + --hash=sha256:0a6e821770cf99cc586d33833b2ff32faebdbe886bd6322395606cf55153246c \ + --hash=sha256:0b929ac182f5ace000d459c59c2c9c33047e20e935f8e39371fa6e3b85d56f4a \ + --hash=sha256:129a150f5c445165ff941fc02ee27df65940fcb8a22a61828b1853c98763a64b \ + --hash=sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555 \ + --hash=sha256:1473400e5b2733e58b396a04eb7f35f541e1fb976d0c0724d0223dd607e0f74c \ + --hash=sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b \ + --hash=sha256:1a7ed2d9d039bd41e889f6fb9364554052ca21ce823580f6a07c4ec245c1f5d6 \ + --hash=sha256:1e1fe0e6ab7775fd842bc39e86f6dcfc4507ab0ffe206093e76d61cde37225c8 \ + --hash=sha256:1fb5699e4464afe5c7e65fa51d4f99e0b2eadcc176e4aa33600a3df7801d6662 \ + --hash=sha256:2696993ee1eebd20b8e4ee4356483c4cb696066ddc24bd70bcbb80fa56ff9061 \ + --hash=sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998 \ + --hash=sha256:36ccae62f64235cf8ddb682073a60519426fdd4725524ae38874adf72b5f2aeb \ + --hash=sha256:3cedbfa9c940fdad3e6e941db7138e26ce8aad38ab5fe9dcfadfed9db7a54e62 \ + --hash=sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984 \ + --hash=sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392 \ + --hash=sha256:4011d137b9955791f9084749cba9a367c68d50ab8d11d64c50ba1688c9b457f2 \ + --hash=sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306 \ + --hash=sha256:410a92fefd2e0e10d26210e1dfb4a876ddaf8439ef60d6434f21ef8d87efc5b7 \ + --hash=sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3 \ + --hash=sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9 \ + --hash=sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6 \ + --hash=sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192 \ + --hash=sha256:4afd5814270fdf6380616b321fd31435a462019d834f83c8611a0ce7484c7317 \ + --hash=sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f \ + --hash=sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda \ + --hash=sha256:582530701bff1dec6779efa00c516496968edd851fba224fbd86e46cc6b73563 \ + --hash=sha256:58455b79ec2661c3600e65c0a716955adc2410f7383755d537584b0de41b1d8a \ + --hash=sha256:58705da316756681ad3c9c73fd15499aa4d8c69f9fd38dc8a35e06c12468582f \ + --hash=sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d \ + --hash=sha256:5c803c401ea1c1c18de70a06a6f79fcc9c5acfc79133e9869e730ad7f8ad8ef9 \ + --hash=sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8 \ + --hash=sha256:612dff5db80beef9e649c6d803a8d50c409082f1fedc9dbcdfde2983b2025b82 \ + --hash=sha256:62c2caa1585c82b3f7a7ab56afef7b3602021d6da34fbc1cf234ff139fed3cd9 \ + --hash=sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845 \ + --hash=sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82 \ + --hash=sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125 \ + --hash=sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504 \ + --hash=sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b \ + --hash=sha256:80dd7db6a7cb57ffbc279c4394246414ec99537ae81ffd702443335a61dbf3a7 \ + --hash=sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc \ + --hash=sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6 \ + --hash=sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40 \ + --hash=sha256:91bd7d1773e64019f9288b7a5101f3ae50d3d8e6b1de7edee9c2ccc1d32f0c0a \ + --hash=sha256:95c658736ec15602da0ed73f312d410117723914a5c91a14ee4cdd72f1d790b3 \ + --hash=sha256:99039fa9e6306880572915728d7f6c24a86ec57b0a83f6b2491e1d8ab0235b9a \ + --hash=sha256:9a2bce789a5ea90e51a02dfcc39e31b7f1e662bc3317979aa7e5538e3a034f72 \ + --hash=sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681 \ + --hash=sha256:9abc77a4ce4c6f2a3168ff34b1da9b0f311a8f1cfd694ec96b0603dff1c79438 \ + --hash=sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae \ + --hash=sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2 \ + --hash=sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb \ + --hash=sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5 \ + --hash=sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a \ + --hash=sha256:acc130bc0375999da18e3d19e5a86403667ac0c4042a094fefb7eec8ebac7cf3 \ + --hash=sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8 \ + --hash=sha256:b4e42a40a5e164cbfdb7b386c966a588b1047558a990981ace551ed7e12ca9c2 \ + --hash=sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22 \ + --hash=sha256:b60fb58b90c6d63779cb0c0c54eeb38941bae3ecf7a73c764c52c88c2dcb9d72 \ + --hash=sha256:b870b5df5b71d8c3359d21be8f0d6c485fa0ebdb6477dda51a1ea54a9b558061 \ + --hash=sha256:ba0f0eb61ef00ea10e00eb53a9129501f52385c44853dbd6c4ad3f403603083f \ + --hash=sha256:bb87745b2e6dc56361bfde481d5a378dc314b252a98d7dd19a651a3fa58f24a9 \ + --hash=sha256:bb90fb8bda722a1b9d48ac1e6c38f923ea757b3baf8ebd0c82e09c5c1a0e7a04 \ + --hash=sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98 \ + --hash=sha256:c86563182421896d73858e08e1db93afdd2b947a70064b813d515d66549e15f9 \ + --hash=sha256:c958bcfd59bacc2d0249dcfe575e71da54f9dcf4a8bdf89c4cb9a68a1170d73f \ + --hash=sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b \ + --hash=sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925 \ + --hash=sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6 \ + --hash=sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0 \ + --hash=sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9 \ + --hash=sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c \ + --hash=sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991 \ + --hash=sha256:ecc840861360ba9d176d413a5489b9a0aff6d6303d7e733e2c4623cfa26904a6 \ + --hash=sha256:f09b286faeff3c750a879d336fb6d8713206fc97af3adc14def0cdd349df6000 \ + --hash=sha256:f393cda562f79828f38a819f4788641ac7c4085f30f1ce1a68672baa686482bb \ + --hash=sha256:f917c1180fdb8623c2b75a99192f4025e412597c50b2ac870f156de8fb101119 \ + --hash=sha256:fc78a84e2dfbc27afe4b2bd7c80c8db9bca75cc5b85df52bfe634596a1da846b \ + --hash=sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58 + # via deprecated +yarl==1.20.1 \ + --hash=sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845 \ + --hash=sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53 \ + --hash=sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a \ + --hash=sha256:0c869f2651cc77465f6cd01d938d91a11d9ea5d798738c1dc077f3de0b5e5fed \ + --hash=sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2 \ + --hash=sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02 \ + --hash=sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf \ + --hash=sha256:14a85f3bd2d7bb255be7183e5d7d6e70add151a98edf56a770d6140f5d5f4010 \ + --hash=sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3 \ + --hash=sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef \ + --hash=sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04 \ + --hash=sha256:1f8a891e4a22a89f5dde7862994485e19db246b70bb288d3ce73a34422e55b23 \ + --hash=sha256:21242b4288a6d56f04ea193adde174b7e347ac46ce6bc84989ff7c1b1ecea84e \ + --hash=sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6 \ + --hash=sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e \ + --hash=sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a \ + --hash=sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a \ + --hash=sha256:2c89b5c792685dd9cd3fa9761c1b9f46fc240c2a3265483acc1565769996a3f8 \ + --hash=sha256:30c41ad5d717b3961b2dd785593b67d386b73feca30522048d37298fee981805 \ + --hash=sha256:33f29ecfe0330c570d997bcf1afd304377f2e48f61447f37e846a6058a4d33b2 \ + --hash=sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458 \ + --hash=sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc \ + --hash=sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d \ + --hash=sha256:41493b9b7c312ac448b7f0a42a089dffe1d6e6e981a2d76205801a023ed26a2b \ + --hash=sha256:41ebd28167bc6af8abb97fec1a399f412eec5fd61a3ccbe2305a18b84fb4ca73 \ + --hash=sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7 \ + --hash=sha256:46b5e0ccf1943a9a6e766b2c2b8c732c55b34e28be57d8daa2b3c1d1d4009309 \ + --hash=sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e \ + --hash=sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698 \ + --hash=sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c \ + --hash=sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691 \ + --hash=sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16 \ + --hash=sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f \ + --hash=sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f \ + --hash=sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004 \ + --hash=sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3 \ + --hash=sha256:57edc88517d7fc62b174fcfb2e939fbc486a68315d648d7e74d07fac42cec240 \ + --hash=sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28 \ + --hash=sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513 \ + --hash=sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773 \ + --hash=sha256:59febc3969b0781682b469d4aca1a5cab7505a4f7b85acf6db01fa500fa3f6ba \ + --hash=sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4 \ + --hash=sha256:62915e6688eb4d180d93840cda4110995ad50c459bf931b8b3775b37c264af1e \ + --hash=sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1 \ + --hash=sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31 \ + --hash=sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16 \ + --hash=sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819 \ + --hash=sha256:69e9b141de5511021942a6866990aea6d111c9042235de90e08f94cf972ca03d \ + --hash=sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3 \ + --hash=sha256:6c4fbf6b02d70e512d7ade4b1f998f237137f1417ab07ec06358ea04f69134f8 \ + --hash=sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf \ + --hash=sha256:749d73611db8d26a6281086f859ea7ec08f9c4c56cec864e52028c8b328db723 \ + --hash=sha256:76d12524d05841276b0e22573f28d5fbcb67589836772ae9244d90dd7d66aa13 \ + --hash=sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1 \ + --hash=sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b \ + --hash=sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f \ + --hash=sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d \ + --hash=sha256:835ab2cfc74d5eb4a6a528c57f05688099da41cf4957cf08cad38647e4a83b30 \ + --hash=sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77 \ + --hash=sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a \ + --hash=sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389 \ + --hash=sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e \ + --hash=sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e \ + --hash=sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c \ + --hash=sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1 \ + --hash=sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833 \ + --hash=sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b \ + --hash=sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee \ + --hash=sha256:9427925776096e664c39e131447aa20ec738bdd77c049c48ea5200db2237e000 \ + --hash=sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38 \ + --hash=sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8 \ + --hash=sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd \ + --hash=sha256:aef6c4d69554d44b7f9d923245f8ad9a707d971e6209d51279196d8e8fe1ae16 \ + --hash=sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d \ + --hash=sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a \ + --hash=sha256:b5f307337819cdfdbb40193cad84978a029f847b0a357fbe49f712063cfc4f06 \ + --hash=sha256:b982fa7f74c80d5c0c7b5b38f908971e513380a10fecea528091405f519b9ebb \ + --hash=sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4 \ + --hash=sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9 \ + --hash=sha256:bea21cdae6c7eb02ba02a475f37463abfe0a01f5d7200121b03e605d6a0439f8 \ + --hash=sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390 \ + --hash=sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8 \ + --hash=sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be \ + --hash=sha256:c7ddf7a09f38667aea38801da8b8d6bfe81df767d9dfc8c88eb45827b195cd1c \ + --hash=sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac \ + --hash=sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b \ + --hash=sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5 \ + --hash=sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4 \ + --hash=sha256:d2b6fb3622b7e5bf7a6e5b679a69326b4279e805ed1699d749739a61d242449e \ + --hash=sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f \ + --hash=sha256:dab096ce479d5894d62c26ff4f699ec9072269d514b4edd630a393223f45a0ee \ + --hash=sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5 \ + --hash=sha256:dd803820d44c8853a109a34e3660e5a61beae12970da479cf44aa2954019bf70 \ + --hash=sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1 \ + --hash=sha256:df47c55f7d74127d1b11251fe6397d84afdde0d53b90bedb46a23c0e534f9d24 \ + --hash=sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653 \ + --hash=sha256:e42ba79e2efb6845ebab49c7bf20306c4edf74a0b20fc6b2ccdd1a219d12fad3 \ + --hash=sha256:eae7bfe2069f9c1c5b05fc7fe5d612e5bbc089a39309904ee8b829e322dcad00 \ + --hash=sha256:f5a5928ff5eb13408c62a968ac90d43f8322fd56d87008b8f9dabf3c0f6ee983 \ + --hash=sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d \ + --hash=sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7 \ + --hash=sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce \ + --hash=sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e \ + --hash=sha256:ff70f32aa316393eaf8222d518ce9118148eddb8a53073c2403863b41033eed5 + # via aiohttp diff --git a/scripts/ai_tui_agent_test.py b/scripts/ai_tui_agent_test.py new file mode 100755 index 00000000..504d899d --- /dev/null +++ b/scripts/ai_tui_agent_test.py @@ -0,0 +1,1040 @@ +#!/usr/bin/env python3 +""" +Deterministic AI-agent harness for SeedPass TUI testing. + +This script drives the interactive CLI like a user and records: +1. step-level pass/fail status +2. coverage checkpoints for key menu flows +3. full terminal transcript + +Usage example: + source .venv/bin/activate + python scripts/ai_tui_agent_test.py +""" + +from __future__ import annotations + +import argparse +import json +import os +import pty +import random +import re +import select +import shutil +import subprocess +import sys +import tempfile +import time +from dataclasses import dataclass, asdict +from datetime import datetime, UTC +from pathlib import Path +from typing import Pattern + +ANSI_RE = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") + + +@dataclass +class StepResult: + step_id: str + description: str + status: str + duration_sec: float + detail: str | None = None + + +class TUIHarnessError(RuntimeError): + """Raised when the interactive harness cannot advance as expected.""" + + +class TUIRunner: + def __init__( + self, proc: subprocess.Popen[bytes], master_fd: int, read_chunk: int = 4096 + ): + self.proc = proc + self.master_fd = master_fd + self.read_chunk = read_chunk + self.raw_output = "" + self.clean_output = "" + self.search_pos = 0 + self._fd_closed = False + + def _refresh_clean_output(self) -> None: + self.clean_output = ANSI_RE.sub("", self.raw_output) + + def _read_available(self, timeout: float) -> bool: + if self._fd_closed: + return False + ready, _, _ = select.select([self.master_fd], [], [], timeout) + if not ready: + return False + try: + chunk = os.read(self.master_fd, self.read_chunk) + except OSError: + return False + if not chunk: + return False + self.raw_output += chunk.decode("utf-8", errors="ignore") + self._refresh_clean_output() + return True + + def wait_for(self, pattern: str | Pattern[str], timeout: float) -> re.Match[str]: + end = time.monotonic() + timeout + compiled = re.compile(pattern) if isinstance(pattern, str) else pattern + while time.monotonic() < end: + match = compiled.search(self.clean_output, self.search_pos) + if match: + self.search_pos = match.end() + return match + if self.proc.poll() is not None: + raise TUIHarnessError( + f"Process exited before pattern appeared: {compiled.pattern!r}" + ) + self._read_available(0.2) + preview = self.clean_output[max(0, len(self.clean_output) - 1200) :] + raise TUIHarnessError( + f"Timed out waiting for pattern: {compiled.pattern!r}\n" + f"Recent output:\n{preview}" + ) + + def try_wait_for(self, pattern: str | Pattern[str], timeout: float) -> bool: + try: + self.wait_for(pattern, timeout) + return True + except TUIHarnessError: + return False + + def sendline(self, value: str = "") -> None: + os.write(self.master_fd, (value + "\n").encode("utf-8")) + + def expect_and_send( + self, pattern: str | Pattern[str], value: str = "", timeout: float = 20.0 + ) -> None: + self.wait_for(pattern, timeout) + self.sendline(value) + + def pump(self, duration: float = 0.2) -> None: + self._read_available(duration) + + def close(self, kill_after: float = 1.5) -> int: + end = time.monotonic() + kill_after + while time.monotonic() < end: + code = self.proc.poll() + if code is not None: + if not self._fd_closed: + try: + os.close(self.master_fd) + except Exception: + pass + self._fd_closed = True + return code + self.pump(0.1) + if not self._fd_closed: + try: + os.close(self.master_fd) + except Exception: + pass + self._fd_closed = True + self.proc.kill() + return self.proc.wait(timeout=2.0) + + +def _parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Run deterministic, repeatable TUI coverage checks for SeedPass." + ) + parser.add_argument( + "--scenario", + choices=("core", "extended", "stress"), + default="extended", + help="Scenario profile to run (default: extended).", + ) + parser.add_argument( + "--stress-cycles", + type=int, + default=6, + help="Deterministic menu-stress loops for --scenario stress.", + ) + parser.add_argument( + "--stress-seed", + type=int, + default=1337, + help="RNG seed for deterministic invalid-input campaigns in stress scenario.", + ) + parser.add_argument( + "--repo-root", + type=Path, + default=Path(__file__).resolve().parents[1], + help="SeedPass repository root (default: script parent repo).", + ) + parser.add_argument( + "--python-bin", + default=sys.executable, + help="Python executable used to launch SeedPass (default: current interpreter).", + ) + parser.add_argument( + "--timeout", + type=float, + default=25.0, + help="Per-prompt timeout in seconds.", + ) + parser.add_argument( + "--password", + default="AgentPass123!", + help="Master password used during the run.", + ) + parser.add_argument( + "--output-dir", + type=Path, + default=Path("artifacts/agent_tui_test"), + help="Directory for transcript/report artifacts.", + ) + parser.add_argument( + "--keep-home", + action="store_true", + help="Keep the temporary HOME directory after the test run.", + ) + parser.add_argument( + "--verbose", + action="store_true", + help="Print step progress while running.", + ) + return parser.parse_args() + + +def _run_step( + step_id: str, + description: str, + fn, + results: list[StepResult], + *, + verbose: bool = False, +) -> None: + start = time.monotonic() + try: + fn() + except Exception as exc: + duration = time.monotonic() - start + results.append( + StepResult( + step_id=step_id, + description=description, + status="failed", + duration_sec=duration, + detail=str(exc), + ) + ) + raise + duration = time.monotonic() - start + results.append( + StepResult( + step_id=step_id, + description=description, + status="passed", + duration_sec=duration, + ) + ) + if verbose: + print(f"[PASS] {step_id} ({duration:.2f}s) - {description}") + + +def _drain_to_main_menu(runner: TUIRunner, timeout: float) -> None: + main_menu_prompt = r"Enter your choice \(1-8\) or press Enter to exit:" + helper_prompts: list[tuple[str, str]] = [ + (r"Press Enter to continue\.?", ""), + (r"Select an action or press Enter to return:", ""), + (r"Enter index to view details or press Enter to go back:", ""), + ( + r"Enter 'v' to view details, 'r' to restore, or press Enter to go back:", + "", + ), + (r"Select an option or press Enter to go back:", ""), + (r"Enter index to manage or press Enter to go back:", ""), + ] + + end = time.monotonic() + timeout + while time.monotonic() < end: + try: + runner.wait_for(main_menu_prompt, timeout=1.0) + return + except TUIHarnessError: + progressed = False + for pattern, value in helper_prompts: + try: + runner.expect_and_send(pattern, value, timeout=0.25) + progressed = True + break + except TUIHarnessError: + continue + if progressed: + continue + runner.pump(0.2) + raise TUIHarnessError("Unable to return to main menu within timeout.") + + +def _complete_onboarding_to_main_menu( + runner: TUIRunner, timeout: float, password: str +) -> None: + end = time.monotonic() + timeout + while time.monotonic() < end: + if runner.try_wait_for( + r"Enter your choice \(1-8\) or press Enter to exit:", timeout=0.4 + ): + return + if runner.try_wait_for(r"Enter a new password:", timeout=0.2): + runner.sendline(password) + continue + if runner.try_wait_for(r"Confirm your password:", timeout=0.2): + runner.sendline(password) + continue + if runner.try_wait_for(r"Passwords do not match\.", timeout=0.2): + continue + if runner.try_wait_for(r"Press Enter to continue\.?", timeout=0.2): + runner.sendline("") + continue + runner.pump(0.1) + raise TUIHarnessError("Onboarding did not reach main menu within timeout.") + + +def _add_entry_menu_open( + runner: TUIRunner, timeout: float, choice: str | None = None +) -> None: + runner.sendline("1") + if choice is None: + runner.wait_for(r"Select entry type or press Enter to go back:", timeout) + else: + runner.expect_and_send( + r"Select entry type or press Enter to go back:", choice, timeout + ) + + +def _complete_initial_seed_setup( + runner: TUIRunner, timeout: float, password: str, coverage: dict[str, bool] +) -> None: + # First-run onboarding. + runner.expect_and_send(r"Select an option:\s*$", "1", timeout) + runner.expect_and_send(r"Enter choice \(1/2/3/4/5\):", "3", timeout) + runner.expect_and_send( + r"Do you want to use this generated seed\? \(Y/N\):", "Y", timeout + ) + _complete_onboarding_to_main_menu(runner, timeout, password) + coverage["startup_onboarding"] = True + coverage["main_menu"] = True + + +def _add_quick_password_entry( + runner: TUIRunner, + timeout: float, + *, + label: str, + username: str, + url: str, + exercise_invalid_length: bool, + coverage: dict[str, bool], +) -> None: + _add_entry_menu_open(runner, timeout, "1") + runner.expect_and_send(r"Choose mode: \[Q\]uick or \[A\]dvanced\?", "q", timeout) + runner.expect_and_send(r"Enter the label or website name:", label, timeout) + runner.expect_and_send(r"Enter the username \(optional\):", username, timeout) + runner.expect_and_send(r"Enter the URL \(optional\):", url, timeout) + if exercise_invalid_length: + runner.expect_and_send(r"Enter desired password length .*:", "3", timeout) + runner.wait_for(r"Password length must be between 8 and 128", timeout) + coverage["invalid_length_validation"] = True + runner.expect_and_send(r"Enter desired password length .*:", "12", timeout) + runner.expect_and_send(r"Include special characters\? \(Y/n\):", "", timeout) + runner.wait_for(r"Password generated and indexed with ID 0", timeout) + coverage["add_password_quick"] = True + runner.expect_and_send(r"Press Enter to continue\.\.\.", "", timeout) + _drain_to_main_menu(runner, timeout) + + +def _invalid_input_checks( + runner: TUIRunner, + timeout: float, + *, + main_menu_choice: str = "99", + add_entry_choice: str = "9", + retrieve_index: str = "abc", +) -> None: + runner.sendline(main_menu_choice) + runner.wait_for(r"Invalid choice\. Please select a valid option\.", timeout) + _add_entry_menu_open(runner, timeout, add_entry_choice) + runner.wait_for(r"Invalid choice\.", timeout) + runner.expect_and_send(r"Select entry type or press Enter to go back:", "", timeout) + _drain_to_main_menu(runner, timeout) + runner.sendline("2") + runner.expect_and_send( + r"Enter the index number of the entry to retrieve:", retrieve_index, timeout + ) + runner.wait_for(r"Error: Index must be a number\.", timeout) + runner.expect_and_send(r"Press Enter to continue\.\.\.", "", timeout) + _drain_to_main_menu(runner, timeout) + + +def _wait_for_retrieve_password_output( + runner: TUIRunner, timeout: float, label: str +) -> None: + runner.wait_for( + rf"(Retrieved Password for {re.escape(label)}|Retrieving password for '{re.escape(label)}')", + timeout, + ) + + +def _scenario_core( + runner: TUIRunner, + timeout: float, + password: str, + coverage: dict[str, bool], + post_conditions: dict[str, bool], +) -> None: + _complete_initial_seed_setup(runner, timeout, password, coverage) + + # Invalid input resilience checks. + _invalid_input_checks(runner, timeout) + coverage["invalid_input_resilience"] = True + + # Add a password and exercise length validation. + _add_quick_password_entry( + runner, + timeout, + label="agent.example", + username="agent", + url="https://agent.example", + exercise_invalid_length=True, + coverage=coverage, + ) + + # Retrieve and action menu. + runner.sendline("2") + runner.expect_and_send( + r"Enter the index number of the entry to retrieve:", "0", timeout + ) + _wait_for_retrieve_password_output(runner, timeout, "agent.example") + if runner.try_wait_for(r"Reveal hidden fields\? \(y/N\):", timeout=0.4): + runner.sendline("") + runner.expect_and_send(r"Press Enter to continue\.\.\.", "", timeout) + runner.wait_for(r"Entry Actions:", timeout) + coverage["retrieve_entry"] = True + runner.expect_and_send(r"Select an action or press Enter to return:", "", timeout) + _drain_to_main_menu(runner, timeout) + + # Search. + runner.sendline("3") + runner.expect_and_send(r"Enter search string:", "agent", timeout) + runner.wait_for(r"Search Results", timeout) + runner.wait_for(r"0\. Password - agent\.example", timeout) + coverage["search_entries"] = True + runner.expect_and_send( + r"Enter index to view details or press Enter to go back:", "", timeout + ) + _drain_to_main_menu(runner, timeout) + + # List entries. + runner.sendline("4") + runner.expect_and_send( + r"Select entry type or press Enter to go back:", "1", timeout + ) + runner.wait_for(r"\[\+\] Entries:", timeout) + runner.wait_for(r"0\. Password - agent\.example", timeout) + coverage["list_entries"] = True + runner.expect_and_send( + r"Enter index to view details or press Enter to go back:", "", timeout + ) + runner.expect_and_send(r"Select entry type or press Enter to go back:", "", timeout) + _drain_to_main_menu(runner, timeout) + + # Graceful exit. + runner.sendline("") + runner.wait_for(r"Exiting the program\.", timeout) + coverage["graceful_exit"] = True + + +def _scenario_stress( + runner: TUIRunner, + timeout: float, + password: str, + coverage: dict[str, bool], + post_conditions: dict[str, bool], + *, + cycles: int, + seed: int, +) -> None: + _complete_initial_seed_setup(runner, timeout, password, coverage) + + _add_quick_password_entry( + runner, + timeout, + label="stress.example", + username="stress", + url="https://stress.example", + exercise_invalid_length=False, + coverage=coverage, + ) + + rng = random.Random(seed) + invalid_main_menu_inputs = ["99", "0", "x", "-1", "one", "1x"] + invalid_add_entry_inputs = ["9", "0", "x", "-1", "one", "1x"] + invalid_retrieve_inputs = ["abc", "!", "one", "1x", "index", "0x1"] + + # Deterministic negative-input + back-navigation stress cycles. + for _ in range(cycles): + _invalid_input_checks( + runner, + timeout, + main_menu_choice=rng.choice(invalid_main_menu_inputs), + add_entry_choice=rng.choice(invalid_add_entry_inputs), + retrieve_index=rng.choice(invalid_retrieve_inputs), + ) + + runner.sendline("4") + runner.expect_and_send( + r"Select entry type or press Enter to go back:", "1", timeout + ) + runner.wait_for(r"\[\+\] Entries:", timeout) + runner.wait_for(r"0\. Password - stress\.example", timeout) + runner.expect_and_send( + r"Enter index to view details or press Enter to go back:", "", timeout + ) + runner.expect_and_send( + r"Select entry type or press Enter to go back:", "", timeout + ) + _drain_to_main_menu(runner, timeout) + + runner.sendline("2") + runner.expect_and_send( + r"Enter the index number of the entry to retrieve:", "0", timeout + ) + _wait_for_retrieve_password_output(runner, timeout, "stress.example") + if runner.try_wait_for(r"Reveal hidden fields\? \(y/N\):", timeout=0.4): + runner.sendline("") + runner.expect_and_send(r"Press Enter to continue\.\.\.", "", timeout) + runner.wait_for(r"Entry Actions:", timeout) + runner.expect_and_send( + r"Select an action or press Enter to return:", "", timeout + ) + _drain_to_main_menu(runner, timeout) + + coverage["invalid_input_resilience"] = True + coverage["retrieve_entry"] = True + coverage["list_entries"] = True + coverage["stress_cycles"] = True + coverage["seeded_negative_campaign"] = True + + runner.sendline("") + runner.wait_for(r"Exiting the program\.", timeout) + coverage["graceful_exit"] = True + + +def _scenario_extended( + runner: TUIRunner, + timeout: float, + password: str, + coverage: dict[str, bool], + post_conditions: dict[str, bool], +) -> None: + _complete_initial_seed_setup(runner, timeout, password, coverage) + + # Invalid input resilience checks. + _invalid_input_checks(runner, timeout) + coverage["invalid_input_resilience"] = True + + # Add password in quick mode, including validation checks. + _add_quick_password_entry( + runner, + timeout, + label="agent.example", + username="agent", + url="https://agent.example", + exercise_invalid_length=True, + coverage=coverage, + ) + + # Retrieve and action menu. + runner.sendline("2") + runner.expect_and_send( + r"Enter the index number of the entry to retrieve:", "0", timeout + ) + _wait_for_retrieve_password_output(runner, timeout, "agent.example") + if runner.try_wait_for(r"Reveal hidden fields\? \(y/N\):", timeout=0.4): + runner.sendline("") + runner.expect_and_send(r"Press Enter to continue\.\.\.", "", timeout) + runner.wait_for(r"Entry Actions:", timeout) + coverage["retrieve_entry"] = True + runner.expect_and_send(r"Select an action or press Enter to return:", "", timeout) + _drain_to_main_menu(runner, timeout) + + # Search. + runner.sendline("3") + runner.expect_and_send(r"Enter search string:", "agent", timeout) + runner.wait_for(r"Search Results", timeout) + runner.wait_for(r"0\. Password - agent\.example", timeout) + coverage["search_entries"] = True + runner.expect_and_send( + r"Enter index to view details or press Enter to go back:", "", timeout + ) + _drain_to_main_menu(runner, timeout) + + # List entries. + runner.sendline("4") + runner.expect_and_send( + r"Select entry type or press Enter to go back:", "1", timeout + ) + runner.wait_for(r"\[\+\] Entries:", timeout) + runner.wait_for(r"0\. Password - agent\.example", timeout) + coverage["list_entries"] = True + runner.expect_and_send( + r"Enter index to view details or press Enter to go back:", "", timeout + ) + runner.expect_and_send(r"Select entry type or press Enter to go back:", "", timeout) + _drain_to_main_menu(runner, timeout) + + # Add generated TOTP and verify 2FA screen shows non-empty codes. + _add_entry_menu_open(runner, timeout, "2") + runner.expect_and_send(r"Select option or press Enter to go back:", "1", timeout) + runner.expect_and_send(r"Label:", "agent-totp", timeout) + runner.expect_and_send(r"Period \(default 30\):", "", timeout) + runner.expect_and_send(r"Digits \(default 6\):", "", timeout) + runner.expect_and_send(r"Notes \(optional\):", "", timeout) + runner.expect_and_send(r"Enter tags \(comma-separated, optional\):", "", timeout) + runner.wait_for(r"TOTP entry added with ID", timeout) + runner.expect_and_send(r"Press Enter to continue\.\.\.", "", timeout) + _drain_to_main_menu(runner, timeout) + coverage["add_totp"] = True + + runner.sendline("6") + runner.wait_for(r"Press Enter to return to the menu\.", timeout) + runner.wait_for(r"(Generated|Imported) 2FA Codes:", timeout) + runner.wait_for(r"agent-totp", timeout) + runner.sendline("") + _drain_to_main_menu(runner, timeout) + + # Add all remaining entry types and verify they appear in listing. + _add_entry_menu_open(runner, timeout, "3") + runner.expect_and_send(r"Label \(key\):", "agent-ssh", timeout) + runner.expect_and_send(r"Notes \(optional\):", "", timeout) + runner.expect_and_send(r"Enter tags \(comma-separated, optional\):", "", timeout) + runner.expect_and_send( + r"WARNING: Displaying SSH keys reveals sensitive information\. Continue\? \(Y/N\):", + "y", + timeout, + ) + runner.wait_for(r"SSH key entry added with ID", timeout) + runner.expect_and_send(r"Press Enter to continue\.\.\.", "", timeout) + _drain_to_main_menu(runner, timeout) + + _add_entry_menu_open(runner, timeout, "4") + runner.expect_and_send(r"Label:", "agent-seed", timeout) + runner.expect_and_send(r"Word count \(12 or 24, default 24\):", "12", timeout) + runner.expect_and_send(r"Notes \(optional\):", "", timeout) + runner.expect_and_send(r"Enter tags \(comma-separated, optional\):", "", timeout) + runner.expect_and_send( + r"WARNING: Displaying the seed phrase reveals sensitive information\. Continue\? \(Y/N\):", + "y", + timeout, + ) + runner.wait_for(r"Seed entry 'agent-seed' added with ID", timeout) + runner.expect_and_send(r"Show Compact Seed QR\? \(Y/N\):", "n", timeout) + runner.expect_and_send(r"Press Enter to continue\.\.\.", "", timeout) + _drain_to_main_menu(runner, timeout) + + _add_entry_menu_open(runner, timeout, "5") + runner.expect_and_send(r"Label:", "agent-nostr", timeout) + runner.expect_and_send(r"Notes \(optional\):", "", timeout) + runner.expect_and_send(r"Enter tags \(comma-separated, optional\):", "", timeout) + runner.wait_for(r"Nostr key entry added with ID", timeout) + runner.expect_and_send(r"Show QR code for npub\? \(Y/N\):", "n", timeout) + runner.expect_and_send( + r"WARNING: Displaying the nsec QR reveals your private key\. Continue\? \(Y/N\):", + "n", + timeout, + ) + runner.expect_and_send(r"Press Enter to continue\.\.\.", "", timeout) + _drain_to_main_menu(runner, timeout) + + _add_entry_menu_open(runner, timeout, "6") + runner.expect_and_send(r"Label:", "agent-pgp", timeout) + runner.expect_and_send( + r"Key type \(ed25519 or rsa, default ed25519\):", "", timeout + ) + runner.expect_and_send(r"User ID \(optional\):", "", timeout) + runner.expect_and_send(r"Notes \(optional\):", "", timeout) + runner.expect_and_send(r"Enter tags \(comma-separated, optional\):", "", timeout) + runner.expect_and_send( + r"WARNING: Displaying the PGP key reveals sensitive information\. Continue\? \(Y/N\):", + "y", + timeout, + ) + runner.wait_for(r"PGP key entry added with ID", timeout) + runner.expect_and_send(r"Press Enter to continue\.\.\.", "", timeout) + _drain_to_main_menu(runner, timeout) + + _add_entry_menu_open(runner, timeout, "7") + runner.expect_and_send(r"Label:", "agent-kv", timeout) + runner.expect_and_send(r"Key:", "token", timeout) + runner.expect_and_send(r"Value:", "abc123", timeout) + runner.expect_and_send(r"Notes \(optional\):", "", timeout) + runner.expect_and_send(r"Enter tags \(comma-separated, optional\):", "", timeout) + runner.expect_and_send(r"Add custom field\? \(y/N\):", "n", timeout) + runner.wait_for(r"Key/Value entry added with ID", timeout) + runner.expect_and_send(r"Press Enter to continue\.\.\.", "", timeout) + _drain_to_main_menu(runner, timeout) + + _add_entry_menu_open(runner, timeout, "8") + runner.expect_and_send(r"Label:", "agent-managed", timeout) + runner.expect_and_send(r"Notes \(optional\):", "", timeout) + runner.expect_and_send(r"Enter tags \(comma-separated, optional\):", "", timeout) + runner.wait_for(r"Managed account 'agent-managed' added with ID", timeout) + runner.expect_and_send(r"Reveal seed now\? \(y/N\):", "n", timeout) + runner.expect_and_send(r"Press Enter to continue\.\.\.", "", timeout) + _drain_to_main_menu(runner, timeout) + + runner.sendline("4") + runner.expect_and_send( + r"Select entry type or press Enter to go back:", "1", timeout + ) + runner.wait_for(r"agent\.example", timeout) + runner.wait_for(r"agent-totp", timeout) + runner.wait_for(r"agent-ssh", timeout) + runner.wait_for(r"agent-seed", timeout) + runner.wait_for(r"agent-nostr", timeout) + runner.wait_for(r"agent-pgp", timeout) + runner.wait_for(r"agent-kv", timeout) + runner.wait_for(r"agent-managed", timeout) + runner.expect_and_send( + r"Enter index to view details or press Enter to go back:", "", timeout + ) + runner.expect_and_send(r"Select entry type or press Enter to go back:", "", timeout) + _drain_to_main_menu(runner, timeout) + coverage["add_all_entry_types"] = True + + # Modify entry. + runner.sendline("5") + runner.expect_and_send( + r"Enter the index number of the entry to modify:", "0", timeout + ) + runner.expect_and_send(r"Enter new label .*:", "", timeout) + runner.expect_and_send(r"Enter new username .*:", "agent2", timeout) + runner.expect_and_send(r"Enter new URL .*:", "", timeout) + runner.expect_and_send(r"Archive this password\? .*:", "n", timeout) + runner.expect_and_send(r"Enter new notes .*:", "", timeout) + runner.expect_and_send(r"Edit custom fields\? \(y/N\):", "n", timeout) + runner.expect_and_send( + r"Enter tags \(comma-separated, leave blank to keep current\):", "", timeout + ) + runner.wait_for(r"Entry updated successfully for index 0", timeout) + coverage["modify_entry"] = True + runner.expect_and_send(r"Press Enter to continue\.\.\.", "", timeout) + _drain_to_main_menu(runner, timeout) + + # Archive + restore via archived menu. + runner.sendline("2") + runner.expect_and_send( + r"Enter the index number of the entry to retrieve:", "0", timeout + ) + if runner.try_wait_for(r"Reveal hidden fields\? \(y/N\):", timeout=0.4): + runner.sendline("") + runner.expect_and_send(r"Press Enter to continue\.\.\.", "", timeout) + runner.expect_and_send(r"Select an action or press Enter to return:", "A", timeout) + runner.wait_for(r"Entry at index 0 modified successfully", timeout) + runner.expect_and_send(r"Select an action or press Enter to return:", "", timeout) + _drain_to_main_menu(runner, timeout) + + runner.sendline("8") + runner.wait_for(r"Archived Entries", timeout) + runner.wait_for(r"0\. agent\.example", timeout) + runner.expect_and_send( + r"Enter index to manage or press Enter to go back:", "0", timeout + ) + runner.expect_and_send( + r"Enter 'v' to view details, 'r' to restore, or press Enter to go back:", + "r", + timeout, + ) + runner.wait_for(r"Entry at index 0 modified successfully", timeout) + coverage["archive_restore"] = True + _drain_to_main_menu(runner, timeout) + runner.sendline("8") + if runner.try_wait_for(r"Archived Entries", timeout=0.8): + if runner.try_wait_for(r"0\. agent\.example", timeout=0.4): + raise TUIHarnessError( + "Archive/restore post-condition failed: restored entry is still archived." + ) + runner.expect_and_send( + r"Enter index to manage or press Enter to go back:", "", timeout + ) + elif runner.try_wait_for(r"Press Enter to continue\.\.\.", timeout=0.8): + runner.sendline("") + else: + raise TUIHarnessError( + "Archive/restore post-condition failed: archived view prompt was not recognized." + ) + _drain_to_main_menu(runner, timeout) + post_conditions["archive_restore_consistency"] = True + + # 2FA codes view remains accessible after mixed operations. + runner.sendline("6") + runner.wait_for(r"Press Enter to return to the menu\.", timeout) + runner.wait_for(r"(Generated|Imported) 2FA Codes:", timeout) + runner.wait_for(r"agent-totp", timeout) + runner.sendline("") + coverage["totp_codes_view"] = True + _drain_to_main_menu(runner, timeout) + + # Settings toggles and lock/unlock flow. + runner.sendline("7") + runner.expect_and_send( + r"Select an option or press Enter to go back:", "15", timeout + ) + runner.expect_and_send( + r"Enable secret mode\? \(y/n, blank to keep\):", "y", timeout + ) + runner.expect_and_send(r"Clipboard clear delay in seconds \[[0-9]+\]:", "", timeout) + runner.expect_and_send(r"Press Enter to continue\.?", "", timeout) + runner.expect_and_send( + r"Select an option or press Enter to go back:", "16", timeout + ) + runner.expect_and_send( + r"Enable offline mode\? \(y/n, blank to keep\):", "n", timeout + ) + runner.expect_and_send(r"Press Enter to continue\.?", "", timeout) + runner.expect_and_send( + r"Select an option or press Enter to go back:", "17", timeout + ) + runner.expect_and_send( + r"Enable Quick Unlock\? \(y/n, blank to keep\):", "y", timeout + ) + runner.expect_and_send(r"Press Enter to continue\.?", "", timeout) + runner.expect_and_send( + r"Select an option or press Enter to go back:", "13", timeout + ) + # Unlock prompt text can vary; accept either and submit password. + if runner.try_wait_for(r"Enter your master password to continue:", timeout=timeout): + runner.sendline(password) + elif runner.try_wait_for(r"Enter your master password:", timeout=timeout): + runner.sendline(password) + elif runner.try_wait_for(r"Enter your password:", timeout=timeout): + runner.sendline(password) + runner.expect_and_send(r"Press Enter to continue\.?", "", timeout) + runner.expect_and_send(r"Select an option or press Enter to go back:", "", timeout) + _drain_to_main_menu(runner, timeout) + coverage["settings_toggles_lock_unlock"] = True + runner.sendline("2") + runner.expect_and_send( + r"Enter the index number of the entry to retrieve:", "0", timeout + ) + _wait_for_retrieve_password_output(runner, timeout, "agent.example") + if runner.try_wait_for(r"Reveal hidden fields\? \(y/N\):", timeout=0.4): + runner.sendline("") + runner.expect_and_send(r"Press Enter to continue\.\.\.", "", timeout) + runner.expect_and_send(r"Select an action or press Enter to return:", "", timeout) + _drain_to_main_menu(runner, timeout) + post_conditions["lock_unlock_recovers_retrieval"] = True + + # Settings -> Stats and back. + runner.sendline("7") + runner.expect_and_send( + r"Select an option or press Enter to go back:", "14", timeout + ) + runner.wait_for(r"=== Seed Profile Stats ===", timeout) + runner.expect_and_send(r"Press Enter to continue\.?", "", timeout) + runner.expect_and_send(r"Select an option or press Enter to go back:", "", timeout) + coverage["settings_stats"] = True + _drain_to_main_menu(runner, timeout) + + # Graceful exit. + runner.sendline("") + runner.wait_for(r"Exiting the program\.", timeout) + coverage["graceful_exit"] = True + + +def main() -> int: + args = _parse_args() + if args.stress_cycles < 1: + print("Error: --stress-cycles must be >= 1", file=sys.stderr) + return 2 + + repo_root = args.repo_root.resolve() + src_main = repo_root / "src" / "main.py" + if not src_main.exists(): + print(f"Error: cannot find {src_main}", file=sys.stderr) + return 2 + + timestamp = datetime.now(UTC).strftime("%Y%m%dT%H%M%SZ") + artifact_dir = args.output_dir.resolve() / timestamp + artifact_dir.mkdir(parents=True, exist_ok=True) + + temp_home_dir = Path(tempfile.mkdtemp(prefix="seedpass-agent-home-")) + env = os.environ.copy() + env["HOME"] = str(temp_home_dir) + env["PYTHONUNBUFFERED"] = "1" + env.setdefault("TERM", "xterm") + + cmd = [args.python_bin, str(src_main), "--no-clipboard"] + master_fd, slave_fd = pty.openpty() + proc = subprocess.Popen( + cmd, + cwd=str(repo_root), + env=env, + stdin=slave_fd, + stdout=slave_fd, + stderr=slave_fd, + close_fds=True, + ) + os.close(slave_fd) + runner = TUIRunner(proc, master_fd) + + results: list[StepResult] = [] + scenario_coverage_keys: dict[str, list[str]] = { + "core": [ + "startup_onboarding", + "main_menu", + "invalid_input_resilience", + "add_password_quick", + "invalid_length_validation", + "retrieve_entry", + "search_entries", + "list_entries", + "graceful_exit", + ], + "extended": [ + "startup_onboarding", + "main_menu", + "invalid_input_resilience", + "add_password_quick", + "invalid_length_validation", + "add_totp", + "add_all_entry_types", + "retrieve_entry", + "search_entries", + "list_entries", + "modify_entry", + "archive_restore", + "totp_codes_view", + "settings_toggles_lock_unlock", + "settings_stats", + "graceful_exit", + ], + "stress": [ + "startup_onboarding", + "main_menu", + "add_password_quick", + "invalid_input_resilience", + "retrieve_entry", + "list_entries", + "stress_cycles", + "seeded_negative_campaign", + "graceful_exit", + ], + } + scenario_post_condition_keys: dict[str, list[str]] = { + "core": [], + "extended": [ + "archive_restore_consistency", + "lock_unlock_recovers_retrieval", + ], + "stress": [], + } + coverage = { + key: False + for key in sorted({k for keys in scenario_coverage_keys.values() for k in keys}) + } + post_conditions = { + key: False + for key in sorted( + {k for keys in scenario_post_condition_keys.values() for k in keys} + ) + } + required_keys = scenario_coverage_keys[args.scenario] + required_post_conditions = scenario_post_condition_keys[args.scenario] + + failure: str | None = None + start_time = time.monotonic() + scenario_handlers = { + "core": lambda: _scenario_core( + runner, args.timeout, args.password, coverage, post_conditions + ), + "extended": lambda: _scenario_extended( + runner, args.timeout, args.password, coverage, post_conditions + ), + "stress": lambda: _scenario_stress( + runner, + args.timeout, + args.password, + coverage, + post_conditions, + cycles=args.stress_cycles, + seed=args.stress_seed, + ), + } + try: + _run_step( + f"{args.scenario}_scenario", + ( + "Drive end-to-end deterministic TUI coverage workflow." + if args.scenario == "extended" + else f"Drive deterministic {args.scenario} TUI scenario." + ), + scenario_handlers[args.scenario], + results, + verbose=args.verbose, + ) + except Exception as exc: + failure = str(exc) + finally: + exit_code = runner.close() + total_duration = time.monotonic() - start_time + if failure is None and exit_code != 0: + failure = f"SeedPass exited with non-zero code: {exit_code}" + + transcript_clean = artifact_dir / "transcript.clean.txt" + transcript_raw = artifact_dir / "transcript.raw.txt" + transcript_clean.write_text(runner.clean_output, encoding="utf-8") + transcript_raw.write_text(runner.raw_output, encoding="utf-8") + + report = { + "timestamp_utc": timestamp, + "command": cmd, + "repo_root": str(repo_root), + "home_dir": str(temp_home_dir), + "scenario": args.scenario, + "stress_cycles": args.stress_cycles if args.scenario == "stress" else None, + "stress_seed": args.stress_seed if args.scenario == "stress" else None, + "required_coverage_keys": required_keys, + "required_post_conditions": required_post_conditions, + "duration_sec": round(total_duration, 3), + "seedpass_exit_code": exit_code, + "status": ( + "passed" + if ( + failure is None + and all(coverage[key] for key in required_keys) + and all(post_conditions[key] for key in required_post_conditions) + and exit_code == 0 + ) + else "failed" + ), + "failure": failure, + "steps": [asdict(item) for item in results], + "coverage_points": coverage, + "post_conditions": post_conditions, + "transcript_clean": str(transcript_clean), + "transcript_raw": str(transcript_raw), + } + report_file = artifact_dir / "report.json" + report_file.write_text(json.dumps(report, indent=2), encoding="utf-8") + + if not args.keep_home: + shutil.rmtree(temp_home_dir, ignore_errors=True) + + print(f"AI agent TUI report: {report_file}") + print(f"Status: {report['status']}") + if failure: + print(f"Failure: {failure}") + if report["status"] != "passed": + return 1 + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/check_critical_coverage.py b/scripts/check_critical_coverage.py new file mode 100644 index 00000000..29afe3f7 --- /dev/null +++ b/scripts/check_critical_coverage.py @@ -0,0 +1,269 @@ +#!/usr/bin/env python3 +""" +Enforce coverage thresholds for critical SeedPass modules. + +Reads coverage.py JSON output (pytest --cov-report=json:) and: +1. Fails if critical modules are below configured coverage thresholds. +2. Reports fully uncovered functions/methods for those modules. +""" + +from __future__ import annotations + +import argparse +import ast +import json +import sys +from dataclasses import dataclass +from pathlib import Path + +DEFAULT_THRESHOLDS: dict[str, float] = { + "src/main.py": 50.0, + "src/seedpass/core/manager.py": 60.0, + "src/seedpass/core/encryption.py": 80.0, + "src/seedpass/core/migrations.py": 90.0, +} + + +@dataclass(frozen=True) +class FunctionCoverage: + name: str + start_line: int + end_line: int + covered: bool + + +def _parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Validate coverage thresholds for critical modules." + ) + parser.add_argument( + "coverage_json", + type=Path, + help="Path to coverage JSON report.", + ) + parser.add_argument( + "--threshold", + action="append", + default=[], + metavar="PATH=PERCENT", + help="Override/add threshold mapping, e.g. src/main.py=40", + ) + parser.add_argument( + "--no-default-thresholds", + action="store_true", + help="Disable built-in threshold set; use only --threshold entries.", + ) + parser.add_argument( + "--repo-root", + type=Path, + default=Path(__file__).resolve().parents[1], + help="Repository root for resolving module paths.", + ) + parser.add_argument( + "--json-output", + type=Path, + default=None, + help="Optional path to write machine-readable gate results JSON.", + ) + return parser.parse_args() + + +def _parse_threshold_overrides(values: list[str]) -> dict[str, float]: + parsed: dict[str, float] = {} + for item in values: + if "=" not in item: + raise ValueError( + f"Invalid --threshold value {item!r}; expected PATH=PERCENT" + ) + path, raw_percent = item.split("=", 1) + path = path.strip() + if not path: + raise ValueError(f"Invalid --threshold value {item!r}; empty path") + try: + percent = float(raw_percent) + except ValueError as exc: + raise ValueError( + f"Invalid --threshold value {item!r}; percent must be numeric" + ) from exc + if not (0.0 <= percent <= 100.0): + raise ValueError( + f"Invalid --threshold value {item!r}; percent must be 0..100" + ) + parsed[path] = percent + return parsed + + +def _load_coverage_json(path: Path) -> dict: + try: + return json.loads(path.read_text(encoding="utf-8")) + except FileNotFoundError as exc: + raise RuntimeError(f"Coverage JSON not found: {path}") from exc + except json.JSONDecodeError as exc: + raise RuntimeError(f"Invalid coverage JSON: {path}: {exc}") from exc + + +def _normalize_path(path: str) -> str: + return path.replace("\\", "/") + + +def _find_file_payload(files_payload: dict, module_path: str): + module_norm = _normalize_path(module_path) + for candidate_key, payload in files_payload.items(): + candidate_norm = _normalize_path(candidate_key) + if candidate_norm.endswith(module_norm): + return payload + return None + + +class _FunctionCollector(ast.NodeVisitor): + def __init__(self) -> None: + self.stack: list[str] = [] + self.functions: list[tuple[str, int, int]] = [] + + def _collect_fn(self, node: ast.AST, fn_name: str) -> None: + end_line = getattr(node, "end_lineno", None) or getattr(node, "lineno", 0) + full_name = ".".join(self.stack + [fn_name]) + self.functions.append((full_name, int(node.lineno), int(end_line))) + + def visit_ClassDef(self, node: ast.ClassDef) -> None: + self.stack.append(node.name) + self.generic_visit(node) + self.stack.pop() + + def visit_FunctionDef(self, node: ast.FunctionDef) -> None: + self._collect_fn(node, node.name) + self.generic_visit(node) + + def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> None: + self._collect_fn(node, node.name) + self.generic_visit(node) + + +def _compute_function_coverage( + file_path: Path, executed_lines: set[int] +) -> list[FunctionCoverage]: + source = file_path.read_text(encoding="utf-8") + tree = ast.parse(source) + collector = _FunctionCollector() + collector.visit(tree) + functions: list[FunctionCoverage] = [] + for name, start_line, end_line in collector.functions: + line_range = range(start_line, end_line + 1) + covered = any(line in executed_lines for line in line_range) + functions.append( + FunctionCoverage( + name=name, + start_line=start_line, + end_line=end_line, + covered=covered, + ) + ) + return functions + + +def main() -> int: + args = _parse_args() + try: + overrides = _parse_threshold_overrides(args.threshold) + except ValueError as exc: + print(f"Error: {exc}", file=sys.stderr) + return 2 + + thresholds = {} if args.no_default_thresholds else dict(DEFAULT_THRESHOLDS) + thresholds.update(overrides) + if not thresholds: + print( + "Error: no thresholds configured. Provide --threshold entries.", + file=sys.stderr, + ) + return 2 + + try: + coverage = _load_coverage_json(args.coverage_json) + except RuntimeError as exc: + print(f"Error: {exc}", file=sys.stderr) + return 2 + + files_payload = coverage.get("files") + if not isinstance(files_payload, dict): + print("Error: coverage JSON missing 'files' map", file=sys.stderr) + return 2 + + repo_root = args.repo_root.resolve() + failing_modules: list[str] = [] + result_payload: dict[str, dict] = {} + + print("Critical module coverage gates:") + for module_path, threshold in sorted(thresholds.items()): + payload = _find_file_payload(files_payload, module_path) + module_result = { + "threshold_percent": threshold, + "actual_percent": None, + "meets_threshold": False, + "uncovered_functions": [], + "error": None, + } + if payload is None: + msg = "missing from coverage report" + print(f"- FAIL {module_path}: {msg}") + module_result["error"] = msg + failing_modules.append(module_path) + result_payload[module_path] = module_result + continue + + summary = payload.get("summary", {}) + percent = float(summary.get("percent_covered", 0.0)) + module_result["actual_percent"] = percent + module_result["meets_threshold"] = percent >= threshold + + module_file = (repo_root / module_path).resolve() + try: + executed_lines = {int(x) for x in payload.get("executed_lines", [])} + functions = _compute_function_coverage(module_file, executed_lines) + except Exception as exc: # pragma: no cover - defensive report path + module_result["error"] = f"function coverage analysis error: {exc}" + functions = [] + + uncovered = [ + { + "name": fn.name, + "line": fn.start_line, + } + for fn in functions + if not fn.covered + ] + module_result["uncovered_functions"] = uncovered + + status = "PASS" if module_result["meets_threshold"] else "FAIL" + print(f"- {status} {module_path}: {percent:.2f}% (threshold {threshold:.2f}%)") + if uncovered: + preview = ", ".join( + f"{item['name']}@L{item['line']}" for item in uncovered[:8] + ) + suffix = " ..." if len(uncovered) > 8 else "" + print(f" uncovered functions: {preview}{suffix}") + + if not module_result["meets_threshold"]: + failing_modules.append(module_path) + result_payload[module_path] = module_result + + output = { + "status": "passed" if not failing_modules else "failed", + "failing_modules": failing_modules, + "modules": result_payload, + "coverage_json": str(args.coverage_json.resolve()), + } + if args.json_output: + args.json_output.parent.mkdir(parents=True, exist_ok=True) + args.json_output.write_text(json.dumps(output, indent=2), encoding="utf-8") + + if failing_modules: + print("\nCoverage gate failed for:") + for module in failing_modules: + print(f"- {module}") + return 1 + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/dependency_scan.sh b/scripts/dependency_scan.sh new file mode 100755 index 00000000..bdb4589c --- /dev/null +++ b/scripts/dependency_scan.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Run pip-audit against the pinned requirements +if ! command -v pip-audit >/dev/null 2>&1; then + python -m pip install --quiet pip-audit +fi + +pip-audit -r requirements.lock "$@" diff --git a/scripts/generate_test_profile.py b/scripts/generate_test_profile.py index 00e7aa03..5e73847a 100644 --- a/scripts/generate_test_profile.py +++ b/scripts/generate_test_profile.py @@ -43,6 +43,7 @@ from seedpass.core.vault import Vault from seedpass.core.config_manager import ConfigManager from seedpass.core.backup import BackupManager from seedpass.core.entry_management import EntryManager +from seedpass.core.state_manager import StateManager from nostr.client import NostrClient from utils.fingerprint import generate_fingerprint from utils.fingerprint_manager import FingerprintManager @@ -79,7 +80,7 @@ def initialize_profile( profile_dir = APP_DIR / fingerprint profile_dir.mkdir(parents=True, exist_ok=True) - seed_key = derive_key_from_password(DEFAULT_PASSWORD) + seed_key = derive_key_from_password(DEFAULT_PASSWORD, fingerprint) seed_mgr = EncryptionManager(seed_key, profile_dir) seed_file = profile_dir / "parent_seed.enc" clear_path = profile_dir / "seed_phrase.txt" @@ -195,11 +196,13 @@ def main() -> None: encrypted = entry_mgr.vault.get_encrypted_index() if encrypted: + idx = StateManager(dir_path).state.get("nostr_account_idx", 0) client = NostrClient( entry_mgr.vault.encryption_manager, fingerprint or dir_path.name, parent_seed=seed, config_manager=cfg_mgr, + account_index=idx, ) asyncio.run(client.publish_snapshot(encrypted)) print("[+] Data synchronized to Nostr.") diff --git a/scripts/install.ps1 b/scripts/install.ps1 index 08838994..1cadfeb0 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -2,10 +2,12 @@ # SeedPass Universal Installer for Windows # # Supports installing from a specific branch using the -Branch parameter. -# Example: .\install.ps1 -Branch beta +# Use -IncludeGui to install the optional BeeWare GUI backend. +# Example: .\install.ps1 -Branch beta -IncludeGui param( - [string]$Branch = "main" # The git branch to install from + [string]$Branch = "main", # The git branch to install from + [switch]$IncludeGui # Install BeeWare GUI components ) # --- Configuration --- @@ -249,20 +251,30 @@ if ($LASTEXITCODE -ne 0) { Write-Error "Failed to upgrade pip" } -& "$VenvDir\Scripts\python.exe" -m pip install -r "src\requirements.txt" +& "$VenvDir\Scripts\python.exe" -m pip install --require-hashes -r "requirements.lock" if ($LASTEXITCODE -ne 0) { Write-Warning "Failed to install Python dependencies. If errors mention C++, install Microsoft C++ Build Tools: https://visualstudio.microsoft.com/visual-cpp-build-tools/" Write-Error "Dependency installation failed." } -& "$VenvDir\Scripts\python.exe" -m pip install -e . +if ($IncludeGui) { + & "$VenvDir\Scripts\python.exe" -m pip install -e .[gui] +} else { + & "$VenvDir\Scripts\python.exe" -m pip install -e . +} if ($LASTEXITCODE -ne 0) { Write-Error "Failed to install SeedPass package" } -Write-Info "Installing BeeWare GUI backend..." -& "$VenvDir\Scripts\python.exe" -m pip install toga-winforms -if ($LASTEXITCODE -ne 0) { Write-Warning "Failed to install GUI backend" } +if ($IncludeGui) { + Write-Info "Installing BeeWare GUI backend..." + try { + & "$VenvDir\Scripts\python.exe" -m pip install toga-winforms + if ($LASTEXITCODE -ne 0) { throw "toga-winforms installation failed" } + } catch { + Write-Warning "Failed to install GUI backend. Install Microsoft C++ Build Tools from https://visualstudio.microsoft.com/visual-cpp-build-tools/ and rerun the installer." + } +} # 5. Create launcher script Write-Info "Creating launcher script..." diff --git a/scripts/install.sh b/scripts/install.sh index 1184d6b1..33b0b97d 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -5,7 +5,9 @@ # Supports installing from a specific branch using the -b or --branch flag. # Example: ./install.sh -b beta -set -e +set -euo pipefail +IFS=$'\n\t' +trap 'echo "[ERROR] Line $LINENO failed"; exit 1' ERR # --- Configuration --- REPO_URL="https://github.com/PR0M3TH3AN/SeedPass.git" @@ -15,115 +17,52 @@ VENV_DIR="$INSTALL_DIR/venv" LAUNCHER_DIR="$HOME/.local/bin" LAUNCHER_PATH="$LAUNCHER_DIR/seedpass" BRANCH="main" # Default branch -HEADLESS_MODE="${SEEDPASS_HEADLESS:-}" -ENABLE_GUI_EXPERIMENTAL="${SEEDPASS_ENABLE_GUI:-}" -SKIP_GUI=1 +MODE="tui" +INSTALL_GUI=false # --- Helper Functions --- -is_truthy() { - case "$1" in - 1|y|Y|yes|Yes|YES|true|True|TRUE|on|On|ON|enable|Enable|enabled|Enabled) - return 0 - ;; - *) - return 1 - ;; - esac -} - -print_info() { echo -e "\033[1;34m[INFO]\033[0m $1"; } -print_success() { echo -e "\033[1;32m[SUCCESS]\033[0m $1"; } -print_warning() { echo -e "\033[1;33m[WARNING]\033[0m $1"; } -print_error() { echo -e "\033[1;31m[ERROR]\033[0m $1" >&2; exit 1; } - -run_with_privilege() { - if [ "$EUID" -eq 0 ]; then - "$@" - elif command -v sudo &>/dev/null; then - sudo "$@" - else - print_error "Elevated privileges are required to install system packages, but 'sudo' was not found." - fi -} - -check_pkg_config_cairo() { - if ! command -v pkg-config >/dev/null 2>&1; then - return 1 - fi - pkg-config --exists cairo gobject-2.0 >/dev/null 2>&1 -} - -check_python_has_gtk() { - python3 - <<'PY' >/dev/null 2>&1 -import sys -try: - import gi - gi.require_version('Gtk', '3.0') - from gi.repository import Gtk # noqa: F401 - import cairo # noqa: F401 -except Exception: - sys.exit(1) -PY -} - -ensure_linux_gui_prereqs() { - if check_pkg_config_cairo && check_python_has_gtk; then - print_info "Cairo/GObject development libraries already available." - return 0 - fi - - print_info "Installing system packages required for Gtk/pycairo (this may prompt for your password)..." +print_info() { echo -e "\033[1;34m[INFO]\033[0m" "$1"; } +print_success() { echo -e "\033[1;32m[SUCCESS]\033[0m" "$1"; } +print_warning() { echo -e "\033[1;33m[WARNING]\033[0m" "$1"; } +print_error() { echo -e "\033[1;31m[ERROR]\033[0m" "$1" >&2; exit 1; } +# Install build dependencies for Gtk/GObject if available via the system package manager +install_dependencies() { + print_info "Installing system packages required for Gtk bindings..." if command -v apt-get &>/dev/null; then - run_with_privilege apt-get update - run_with_privilege env DEBIAN_FRONTEND=noninteractive apt-get install -y \ - build-essential pkg-config python3-dev python3-venv python3-gi \ - libgirepository-2.0-dev libcairo2-dev gir1.2-gtk-3.0 \ - libcanberra-gtk3-module gobject-introspection - elif command -v dnf &>/dev/null; then - run_with_privilege dnf groupinstall -y "Development Tools" - run_with_privilege dnf install -y \ - gcc make pkgconf-pkg-config python3-devel python3-gobject \ - gobject-introspection-devel cairo-devel cairo-gobject-devel \ - gtk3 libcanberra-gtk3 + sudo apt-get update && sudo apt-get install -y \\ + build-essential pkg-config libcairo2 libcairo2-dev \\ + libgirepository1.0-dev gobject-introspection \\ + gir1.2-gtk-3.0 libgtk-3-dev python3-dev libffi-dev libssl-dev \\ + cmake rustc cargo zlib1g-dev libjpeg-dev libpng-dev \\ + libfreetype6-dev xclip wl-clipboard elif command -v yum &>/dev/null; then - run_with_privilege yum groupinstall -y "Development Tools" - run_with_privilege yum install -y \ - cairo cairo-devel gobject-introspection-devel gtk3-devel \ - python3-devel python3-gobject pkgconf-pkg-config libcanberra-gtk3 + sudo yum install -y @'Development Tools' cairo cairo-devel \\ + gobject-introspection-devel gtk3-devel python3-devel \\ + libffi-devel openssl-devel cmake rust cargo zlib-devel \\ + libjpeg-turbo-devel libpng-devel freetype-devel xclip \\ + wl-clipboard + elif command -v dnf &>/dev/null; then + sudo dnf groupinstall -y "Development Tools" && sudo dnf install -y \\ + cairo cairo-devel gobject-introspection-devel gtk3-devel \\ + python3-devel libffi-devel openssl-devel cmake rust cargo \\ + zlib-devel libjpeg-turbo-devel libpng-devel freetype-devel \\ + xclip wl-clipboard elif command -v pacman &>/dev/null; then - run_with_privilege pacman -Syu --noconfirm --needed \ - base-devel pkgconf python python-pip python-gobject \ - cairo gobject-introspection gtk3 libcanberra - elif command -v zypper &>/dev/null; then - run_with_privilege zypper install -y -t pattern devel_basis || true - run_with_privilege zypper install -y \ - pkgconf-pkg-config python3-devel python3-gobject gobject-introspection-devel \ - cairo-devel gtk3 'typelib(Gtk)=3.0' libcanberra-gtk3-module - elif command -v apk &>/dev/null; then - run_with_privilege apk add --no-cache \ - build-base pkgconf python3-dev py3-gobject3 \ - gobject-introspection-dev cairo-dev gtk+3.0-dev + sudo pacman -Syu --noconfirm base-devel pkgconf cmake rustup \\ + gtk3 gobject-introspection cairo libjpeg-turbo zlib \\ + libpng freetype xclip wl-clipboard && rustup default stable elif command -v brew &>/dev/null; then - brew install pkg-config cairo gobject-introspection gtk+3 pygobject3 + brew install pkg-config cairo gobject-introspection gtk+3 cmake rustup-init && \\ + rustup-init -y else - print_warning "Unsupported package manager. Please install cairo/GTK development libraries manually." + print_warning "Unsupported package manager. Please install Gtk/GObject dependencies manually." fi - - if ! check_pkg_config_cairo; then - print_error "Cairo/GObject development files are still missing (pkg-config cannot locate 'cairo' and 'gobject-2.0')." - fi - - if ! check_python_has_gtk; then - print_error "Gtk/cairo Python bindings are still unavailable after installing prerequisites." - fi - - print_info "Gtk/cairo development dependencies verified." } - usage() { - echo "Usage: $0 [-b | --branch ] [-h | --help]" + echo "Usage: $0 [-b | --branch ] [-m | --mode ] [-h | --help]" echo " -b, --branch Specify the git branch to install (default: main)" + echo " -m, --mode Installation mode: tui, gui, both (default: tui)" echo " -h, --help Display this help message" exit 0 } @@ -144,12 +83,40 @@ main() { -h|--help) usage ;; + -m|--mode) + if [ -n "$2" ]; then + MODE="$2" + shift 2 + else + print_error "Error: --mode requires an argument (tui|gui|both)." + fi + ;; *) - print_error "Unknown parameter passed: $1" + print_error "Unknown parameter passed: $1"; usage ;; esac done + case "$MODE" in + tui|gui|both) ;; + *) + print_error "Invalid mode: $MODE. Use 'tui', 'gui', or 'both'." + ;; + esac + + DISPLAY_DETECTED=false + if [ -n "${DISPLAY:-}" ] || [ -n "${WAYLAND_DISPLAY:-}" ]; then + DISPLAY_DETECTED=true + fi + + if [[ "$MODE" == "gui" || "$MODE" == "both" ]]; then + if [ "$DISPLAY_DETECTED" = true ]; then + INSTALL_GUI=true + else + print_warning "No display detected. Skipping GUI installation." + fi + fi + # 1. Detect OS OS_NAME=$(uname -s) print_info "Installing SeedPass from branch: '$BRANCH'" @@ -157,57 +124,40 @@ main() { # 2. Check for prerequisites print_info "Checking for prerequisites (git, python3, pip)..." - if ! command -v git &>/dev/null; then + if ! command -v git &> /dev/null; then print_warning "Git is not installed. Attempting to install..." if [ "$OS_NAME" = "Linux" ]; then - if command -v apt-get &>/dev/null; then run_with_privilege apt-get update && run_with_privilege apt-get install -y git - elif command -v dnf &>/dev/null; then run_with_privilege dnf install -y git - elif command -v pacman &>/dev/null; then run_with_privilege pacman -Syu --noconfirm git + if command -v apt-get &> /dev/null; then sudo apt-get update && sudo apt-get install -y git; + elif command -v dnf &> /dev/null; then sudo dnf install -y git; + elif command -v pacman &> /dev/null; then sudo pacman -Syu --noconfirm git; else print_error "Git is not installed and automatic installation is not supported on this system."; fi elif [ "$OS_NAME" = "Darwin" ]; then - if command -v brew &>/dev/null; then brew install git + if command -v brew &> /dev/null; then brew install git; else print_error "Git is not installed and Homebrew was not found. Please install Git manually."; fi else print_error "Git is not installed. Please install it." fi - if ! command -v git &>/dev/null; then print_error "Git installation failed or git not found in PATH."; fi + if ! command -v git &> /dev/null; then print_error "Git installation failed or git not found in PATH."; fi fi - - if ! command -v python3 &>/dev/null; then print_error "Python 3 is not installed. Please install it."; fi - - if ! python3 -m ensurepip --default-pip &>/dev/null && ! command -v pip3 &>/dev/null; then - print_error "pip for Python 3 is not available. Please install it." - fi - - if ! python3 -c "import venv" &>/dev/null; then + if ! command -v python3 &> /dev/null; then print_error "Python 3 is not installed. Please install it."; fi + if ! python3 -m ensurepip --default-pip &> /dev/null && ! command -v pip3 &> /dev/null; then print_error "pip for Python 3 is not available. Please install it."; fi + if ! python3 -c "import venv" &> /dev/null; then print_warning "Python 'venv' module not found. Attempting to install..." if [ "$OS_NAME" = "Linux" ]; then - if command -v apt-get &>/dev/null; then run_with_privilege apt-get update && run_with_privilege apt-get install -y python3-venv - elif command -v dnf &>/dev/null; then run_with_privilege dnf install -y python3-virtualenv + if command -v apt-get &> /dev/null; then sudo apt-get update && sudo apt-get install -y python3-venv; + elif command -v dnf &> /dev/null; then sudo dnf install -y python3-virtualenv; else print_error "Could not auto-install python3-venv. Please install it for your distribution."; fi - else - print_error "Python 'venv' module is missing." - fi + else print_error "Python 'venv' module is missing."; fi fi # 3. Install OS-specific dependencies - if [ "$OS_NAME" = "Linux" ]; then - if is_truthy "$HEADLESS_MODE"; then - SKIP_GUI=1 - print_info "Headless mode requested via SEEDPASS_HEADLESS. GUI backend installation will be skipped in favor of toga-dummy." - elif is_truthy "$ENABLE_GUI_EXPERIMENTAL"; then - SKIP_GUI=0 - print_warning "Experimental GUI installation requested (SEEDPASS_ENABLE_GUI set)." - print_info "Checking for Gtk/cairo development libraries..." - if check_pkg_config_cairo && check_python_has_gtk; then - print_info "Gtk/cairo bindings already available." - else - print_warning "Gtk/cairo bindings not fully available. Attempting to install prerequisites..." - ensure_linux_gui_prereqs - fi + if [ "$INSTALL_GUI" = true ]; then + print_info "Checking for Gtk development libraries..." + if command -v pkg-config &>/dev/null && pkg-config --exists girepository-2.0; then + print_info "Gtk bindings already available." else - SKIP_GUI=1 - print_info "Defaulting to headless installation on Linux (toga-dummy backend)." + print_warning "Gtk introspection bindings not found. Installing dependencies..." + install_dependencies fi fi @@ -232,35 +182,49 @@ main() { source "$VENV_DIR/bin/activate" # 6. Install/Update Python dependencies - print_info "Installing/updating Python dependencies from src/requirements.txt..." + print_info "Installing/updating Python dependencies from requirements.lock..." pip install --upgrade pip - pip install -r src/requirements.txt - pip install -e . - - print_info "Installing platform-specific Toga backend..." - if [ "$OS_NAME" = "Linux" ]; then - if [ "$SKIP_GUI" -eq 1 ]; then - print_info "Installing toga-dummy backend for headless Linux..." - pip install --upgrade "toga-dummy>=0.5.2" - else - print_info "Installing experimental toga-gtk backend for Linux..." - pip install --upgrade "toga-gtk>=0.5.2" + pip install --require-hashes -r requirements.lock + if [ "$INSTALL_GUI" = true ]; then + GUI_READY=true + if [ "$OS_NAME" = "Linux" ]; then + if ! (command -v pkg-config &>/dev/null && pkg-config --exists girepository-2.0); then + print_warning "GTK libraries (girepository-2.0) not found. Install them with: sudo apt install libgirepository1.0-dev" + read -r -p "Continue with GUI installation anyway? (y/N) " CONTINUE_GUI + if [[ ! "$CONTINUE_GUI" =~ ^[Yy]$ ]]; then + GUI_READY=false + fi + fi fi - elif [ "$OS_NAME" = "Darwin" ]; then - if is_truthy "$ENABLE_GUI_EXPERIMENTAL"; then - print_info "Installing toga-cocoa for macOS..." - pip install --upgrade "toga-cocoa>=0.5.2" + if [ "$GUI_READY" = true ]; then + if [ "$OS_NAME" = "Linux" ]; then + print_info "Installing Linux GUI dependencies..." + pip install -e ".[gui-gtk]" + elif [ "$OS_NAME" = "Darwin" ]; then + print_info "Installing macOS GUI dependencies..." + pip install -e ".[gui-mac]" + else + print_warning "Unsupported OS for GUI installation. Installing core package only." + pip install -e . + fi else - print_info "Defaulting to headless backend on macOS. Set SEEDPASS_ENABLE_GUI=1 to install toga-cocoa." - pip install --upgrade "toga-dummy>=0.5.2" + print_warning "Skipping GUI installation." + pip install -e . fi + else + pip install -e . fi + + if ! "$VENV_DIR/bin/python" -c "import seedpass.cli; print('ok')"; then + print_error "SeedPass CLI import check failed." + fi + deactivate # 7. Create launcher script print_info "Creating launcher script at '$LAUNCHER_PATH'..." mkdir -p "$LAUNCHER_DIR" - cat > "$LAUNCHER_PATH" << EOF2 +cat > "$LAUNCHER_PATH" << EOF2 #!/bin/bash source "$VENV_DIR/bin/activate" exec "$VENV_DIR/bin/seedpass" "\$@" @@ -292,14 +256,11 @@ EOF2 # 8. Final instructions print_success "Installation/update complete!" - print_info "SeedPass launcher created at: $LAUNCHER_PATH" + print_info "You can now launch the interactive TUI by typing: seedpass" + print_info "'seedpass' resolves to: $(command -v seedpass)" if [[ ":$PATH:" != *":$LAUNCHER_DIR:"* ]]; then print_warning "Directory '$LAUNCHER_DIR' is not in your PATH." - print_warning "To use 'seedpass' without the full path, add the following line to your shell config (e.g., ~/.bashrc):" - print_warning " export PATH=\"$HOME/.local/bin:$PATH\"" - print_warning "Then reload your shell or run: source ~/.bashrc" - else - print_info "You can now launch the interactive TUI by typing: seedpass" + print_warning "Please add 'export PATH=\"$HOME/.local/bin:$PATH\"' to your shell's config file (e.g., ~/.bashrc, ~/.zshrc) and restart your terminal." fi } diff --git a/scripts/installer_smoke_unix.sh b/scripts/installer_smoke_unix.sh new file mode 100644 index 00000000..4cc16ff9 --- /dev/null +++ b/scripts/installer_smoke_unix.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' + +BRANCH="${1:-beta}" +MODE="${2:-tui}" + +case "$MODE" in + tui|gui|both) ;; + *) + echo "[ERROR] MODE must be one of: tui, gui, both" >&2 + exit 2 + ;; +esac + +if ! command -v git >/dev/null 2>&1; then + echo "[ERROR] git is required for installer smoke test" >&2 + exit 2 +fi + +TMP_HOME="$(mktemp -d)" +cleanup() { + rm -rf "$TMP_HOME" +} +trap cleanup EXIT + +export HOME="$TMP_HOME" +unset DISPLAY || true +unset WAYLAND_DISPLAY || true + +echo "[INFO] Smoke install start: branch=$BRANCH mode=$MODE home=$HOME" + +bash scripts/install.sh -b "$BRANCH" -m "$MODE" + +LAUNCHER="$HOME/.local/bin/seedpass" +APP_DIR="$HOME/.seedpass/app" +if [[ ! -x "$LAUNCHER" ]]; then + echo "[ERROR] launcher missing: $LAUNCHER" >&2 + exit 1 +fi +if [[ ! -d "$APP_DIR/.git" ]]; then + echo "[ERROR] install dir missing git checkout: $APP_DIR" >&2 + exit 1 +fi + +actual_branch="$(git -C "$APP_DIR" rev-parse --abbrev-ref HEAD)" +if [[ "$actual_branch" != "$BRANCH" ]]; then + echo "[ERROR] expected branch '$BRANCH', got '$actual_branch'" >&2 + exit 1 +fi + +"$LAUNCHER" --help >/tmp/seedpass-installer-smoke-help.txt + +echo "[INFO] Re-running installer to validate idempotence" +bash scripts/install.sh -b "$BRANCH" -m "$MODE" +"$LAUNCHER" --help >/tmp/seedpass-installer-smoke-help-2.txt + +echo "[SUCCESS] Installer smoke test passed (branch=$BRANCH mode=$MODE)" diff --git a/scripts/installer_smoke_windows.ps1 b/scripts/installer_smoke_windows.ps1 new file mode 100644 index 00000000..43df33bd --- /dev/null +++ b/scripts/installer_smoke_windows.ps1 @@ -0,0 +1,58 @@ +param( + [string]$Branch = "beta", + [ValidateSet("tui", "gui", "both")] + [string]$Mode = "tui" +) + +$ErrorActionPreference = "Stop" + +if (-not (Get-Command git -ErrorAction SilentlyContinue)) { + throw "git is required for installer smoke test" +} + +$TempHome = Join-Path $env:RUNNER_TEMP ("seedpass-installer-home-" + [guid]::NewGuid().ToString("N")) +New-Item -ItemType Directory -Path $TempHome -Force | Out-Null + +try { + $env:USERPROFILE = $TempHome + $env:HOME = $TempHome + + Write-Host "[INFO] Smoke install start: branch=$Branch mode=$Mode home=$TempHome" + + if ($Mode -eq "tui") { + & "$PSScriptRoot\install.ps1" -Branch $Branch + } else { + & "$PSScriptRoot\install.ps1" -Branch $Branch -IncludeGui + } + + $LauncherPath = Join-Path $env:USERPROFILE ".seedpass\app\bin\seedpass.cmd" + $AppDir = Join-Path $env:USERPROFILE ".seedpass\app" + if (-not (Test-Path $LauncherPath)) { + throw "launcher missing: $LauncherPath" + } + if (-not (Test-Path (Join-Path $AppDir ".git"))) { + throw "install dir missing git checkout: $AppDir" + } + + $ActualBranch = (git -C $AppDir rev-parse --abbrev-ref HEAD).Trim() + if ($ActualBranch -ne $Branch) { + throw "expected branch '$Branch', got '$ActualBranch'" + } + + cmd /c "`"$LauncherPath`" --help" | Out-Null + + Write-Host "[INFO] Re-running installer to validate idempotence" + if ($Mode -eq "tui") { + & "$PSScriptRoot\install.ps1" -Branch $Branch + } else { + & "$PSScriptRoot\install.ps1" -Branch $Branch -IncludeGui + } + cmd /c "`"$LauncherPath`" --help" | Out-Null + + Write-Host "[SUCCESS] Installer smoke test passed (branch=$Branch mode=$Mode)" +} +finally { + if (Test-Path $TempHome) { + Remove-Item -Recurse -Force $TempHome + } +} diff --git a/scripts/run_ci_tests.sh b/scripts/run_ci_tests.sh index 661aa47b..6441cbc9 100755 --- a/scripts/run_ci_tests.sh +++ b/scripts/run_ci_tests.sh @@ -1,6 +1,8 @@ #!/usr/bin/env bash set -eo pipefail +mkdir -p artifacts/coverage + pytest_args=(-vv) if [[ -n "${STRESS_ARGS:-}" ]]; then pytest_args+=(${STRESS_ARGS}) @@ -8,7 +10,14 @@ fi if [[ "${RUNNER_OS:-}" == "Windows" ]]; then pytest_args+=(-n 1) fi -pytest_args+=(--cov=src --cov-report=xml --cov-report=term-missing --cov-fail-under=20 src/tests) +pytest_args+=( + --cov=src + --cov-report=xml + --cov-report=term-missing + --cov-report=json:artifacts/coverage/coverage.json + --cov-fail-under=20 + src/tests +) timeout_bin="timeout" if ! command -v "$timeout_bin" >/dev/null 2>&1; then @@ -33,4 +42,7 @@ if [[ $status -eq 124 ]]; then tail -n 20 pytest.log exit 1 fi +if [[ $status -eq 0 && "${CRITICAL_COVERAGE_GATE:-0}" == "1" ]]; then + python scripts/check_critical_coverage.py artifacts/coverage/coverage.json +fi exit $status diff --git a/src/constants.py b/src/constants.py index 4843ecd1..0361d731 100644 --- a/src/constants.py +++ b/src/constants.py @@ -34,13 +34,9 @@ def initialize_app() -> None: """Ensure the application directory exists.""" try: APP_DIR.mkdir(exist_ok=True, parents=True) - if logger.isEnabledFor(logging.DEBUG): - logger.info(f"Application directory created at {APP_DIR}") + logger.debug("Application directory created at %s", APP_DIR) except Exception as exc: - if logger.isEnabledFor(logging.DEBUG): - logger.error( - f"Failed to create application directory: {exc}", exc_info=True - ) + logger.error("Failed to create application directory: %s", exc, exc_info=True) # ----------------------------------- diff --git a/src/local_bip85/__init__.py b/src/local_bip85/__init__.py index 2379252b..e1f44b1c 100644 --- a/src/local_bip85/__init__.py +++ b/src/local_bip85/__init__.py @@ -1,17 +1,15 @@ # bip85/__init__.py import logging -import traceback logger = logging.getLogger(__name__) try: from .bip85 import BIP85 - - if logger.isEnabledFor(logging.DEBUG): - logger.info("BIP85 module imported successfully.") -except Exception as e: - if logger.isEnabledFor(logging.DEBUG): - logger.error(f"Failed to import BIP85 module: {e}", exc_info=True) +except Exception as exc: + logger.error("Failed to import BIP85 module: %s", exc, exc_info=True) + raise ImportError( + "BIP85 dependencies are missing. Install 'bip_utils', 'cryptography', and 'colorama'." + ) from exc __all__ = ["BIP85"] diff --git a/src/local_bip85/bip85.py b/src/local_bip85/bip85.py index fff786e0..52b270e3 100644 --- a/src/local_bip85/bip85.py +++ b/src/local_bip85/bip85.py @@ -18,7 +18,8 @@ import hashlib import hmac import logging import os -import traceback +from typing import Union + from colorama import Fore from bip_utils import Bip32Slip10Secp256k1, Bip39MnemonicGenerator, Bip39Languages @@ -38,13 +39,19 @@ class Bip85Error(Exception): class BIP85: - def __init__(self, seed_bytes: bytes | str): - """Initialize from BIP39 seed bytes or BIP32 xprv string.""" + def __init__(self, seed_or_xprv: Union[bytes, str]): + """Initialize from seed bytes or an ``xprv`` string. + + Parameters: + seed_or_xprv (Union[bytes, str]): Either raw BIP39 seed bytes + or a BIP32 extended private key (``xprv``) string. + """ + try: - if isinstance(seed_bytes, (bytes, bytearray)): - self.bip32_ctx = Bip32Slip10Secp256k1.FromSeed(seed_bytes) + if isinstance(seed_or_xprv, (bytes, bytearray)): + self.bip32_ctx = Bip32Slip10Secp256k1.FromSeed(seed_or_xprv) else: - self.bip32_ctx = Bip32Slip10Secp256k1.FromExtendedKey(seed_bytes) + self.bip32_ctx = Bip32Slip10Secp256k1.FromExtendedKey(seed_or_xprv) logging.debug("BIP32 context initialized successfully.") except Exception as e: logging.error(f"Error initializing BIP32 context: {e}", exc_info=True) @@ -52,26 +59,36 @@ class BIP85: raise Bip85Error(f"Error initializing BIP32 context: {e}") def derive_entropy( - self, index: int, bytes_len: int, app_no: int = 39, words_len: int | None = None + self, + index: int, + entropy_bytes: int, + app_no: int = 39, + word_count: int | None = None, ) -> bytes: - """ - Derives entropy using BIP-85 HMAC-SHA512 method. + """Derive entropy using the BIP-85 HMAC-SHA512 method. Parameters: index (int): Index for the child entropy. - bytes_len (int): Number of bytes to derive for the entropy. - app_no (int): Application number (default 39 for BIP39) + entropy_bytes (int): Number of bytes of entropy to derive. + app_no (int): Application number (default 39 for BIP39). + word_count (int | None): Number of words used in the derivation path + for BIP39. If ``None`` and ``app_no`` is ``39``, ``word_count`` + defaults to ``entropy_bytes``. The final segment of the + derivation path becomes ``m/83696968'/39'/0'/word_count'/index'``. Returns: - bytes: Derived entropy. + bytes: Derived entropy of length ``entropy_bytes``. Raises: - SystemExit: If derivation fails or entropy length is invalid. + SystemExit: If derivation fails or the derived entropy length is + invalid. """ if app_no == 39: - if words_len is None: - words_len = bytes_len - path = f"m/83696968'/{app_no}'/0'/{words_len}'/{index}'" + if word_count is None: + word_count = entropy_bytes + path = f"m/83696968'/{app_no}'/0'/{word_count}'/{index}'" + elif app_no == 32: + path = f"m/83696968'/{app_no}'/{index}'" else: # Handle other app_no if necessary path = f"m/83696968'/{app_no}'/{index}'" @@ -85,17 +102,17 @@ class BIP85: hmac_result = hmac.new(hmac_key, k, hashlib.sha512).digest() logging.debug(f"HMAC-SHA512 result: {hmac_result.hex()}") - entropy = hmac_result[:bytes_len] + entropy = hmac_result[:entropy_bytes] - if len(entropy) != bytes_len: + if len(entropy) != entropy_bytes: logging.error( - f"Derived entropy length is {len(entropy)} bytes; expected {bytes_len} bytes." + f"Derived entropy length is {len(entropy)} bytes; expected {entropy_bytes} bytes." ) print( - f"{Fore.RED}Error: Derived entropy length is {len(entropy)} bytes; expected {bytes_len} bytes." + f"{Fore.RED}Error: Derived entropy length is {len(entropy)} bytes; expected {entropy_bytes} bytes." ) raise Bip85Error( - f"Derived entropy length is {len(entropy)} bytes; expected {bytes_len} bytes." + f"Derived entropy length is {len(entropy)} bytes; expected {entropy_bytes} bytes." ) logging.debug(f"Derived entropy: {entropy.hex()}") @@ -106,14 +123,17 @@ class BIP85: raise Bip85Error(f"Error deriving entropy: {e}") def derive_mnemonic(self, index: int, words_num: int) -> str: - bytes_len = {12: 16, 18: 24, 24: 32}.get(words_num) - if not bytes_len: + entropy_bytes = {12: 16, 18: 24, 24: 32}.get(words_num) + if not entropy_bytes: logging.error(f"Unsupported number of words: {words_num}") print(f"{Fore.RED}Error: Unsupported number of words: {words_num}") raise Bip85Error(f"Unsupported number of words: {words_num}") entropy = self.derive_entropy( - index=index, bytes_len=bytes_len, app_no=39, words_len=words_num + index=index, + entropy_bytes=entropy_bytes, + app_no=39, + word_count=words_num, ) try: mnemonic = Bip39MnemonicGenerator(Bip39Languages.ENGLISH).FromEntropy( @@ -129,7 +149,7 @@ class BIP85: def derive_symmetric_key(self, index: int = 0, app_no: int = 2) -> bytes: """Derive 32 bytes of entropy for symmetric key usage.""" try: - key = self.derive_entropy(index=index, bytes_len=32, app_no=app_no) + key = self.derive_entropy(index=index, entropy_bytes=32, app_no=app_no) logging.debug(f"Derived symmetric key: {key.hex()}") return key except Exception as e: diff --git a/src/main.py b/src/main.py index 19339de1..f21e1e55 100644 --- a/src/main.py +++ b/src/main.py @@ -11,20 +11,25 @@ import os import logging import signal import time +import queue import argparse -import asyncio -import gzip import tomli +from tomli import TOMLDecodeError from colorama import init as colorama_init from termcolor import colored from utils.color_scheme import color_text -import traceback +import importlib -from seedpass.core.manager import PasswordManager +from seedpass.core.manager import PasswordManager, restore_backup_index from nostr.client import NostrClient from seedpass.core.entry_types import EntryType +from seedpass.core.config_manager import ConfigManager from constants import INACTIVITY_TIMEOUT, initialize_app -from utils.password_prompt import PasswordPromptError +from utils.password_prompt import ( + PasswordPromptError, + prompt_existing_password, + prompt_new_password, +) from utils import ( timed_input, copy_to_clipboard, @@ -32,11 +37,36 @@ from utils import ( pause, clear_header_with_notification, ) -import queue +from utils.clipboard import ClipboardUnavailableError +from utils.atomic_write import atomic_write +from utils.logging_utils import ( + ConsolePauseFilter, + ChecksumWarningFilter, + pause_logging_for_ui, +) from local_bip85.bip85 import Bip85Error colorama_init() +OPTIONAL_DEPENDENCIES = { + "pyperclip": "clipboard support for secret mode", + "qrcode": "QR code generation for TOTP setup", + "toga": "desktop GUI features", +} + + +def _warn_missing_optional_dependencies() -> None: + """Log warnings for any optional packages that are not installed.""" + for module, feature in OPTIONAL_DEPENDENCIES.items(): + try: + importlib.import_module(module) + except ModuleNotFoundError: + logging.debug( + "Optional dependency '%s' is not installed; %s will be unavailable.", + module, + feature, + ) + def load_global_config() -> dict: """Load configuration from ~/.seedpass/config.toml if present.""" @@ -46,48 +76,44 @@ def load_global_config() -> dict: try: with open(config_path, "rb") as f: return tomli.load(f) - except Exception as exc: + except (OSError, TOMLDecodeError) as exc: logging.warning(f"Failed to read {config_path}: {exc}") return {} -def configure_logging(): - logger = logging.getLogger() - logger.setLevel(logging.DEBUG) # Keep this as DEBUG to capture all logs +def configure_logging() -> None: + """Configure application-wide logging handlers.""" - # Remove all handlers associated with the root logger object - for handler in logger.handlers[:]: - logger.removeHandler(handler) - - # Ensure the 'logs' directory exists log_directory = Path("logs") - if not log_directory.exists(): - log_directory.mkdir(parents=True, exist_ok=True) + log_directory.mkdir(parents=True, exist_ok=True) - # Create handlers - c_handler = logging.StreamHandler(sys.stdout) - f_handler = logging.FileHandler(log_directory / "main.log") + console_handler = logging.StreamHandler(sys.stderr) + console_handler.setLevel(logging.WARNING) + console_handler.addFilter(ConsolePauseFilter()) + console_handler.addFilter(ChecksumWarningFilter()) - # Set levels: only errors and critical messages will be shown in the console - c_handler.setLevel(logging.ERROR) - f_handler.setLevel(logging.DEBUG) + file_handler = logging.FileHandler(log_directory / "main.log") + file_handler.setLevel(logging.DEBUG) - # Create formatters and add them to handlers formatter = logging.Formatter( - "%(asctime)s [%(levelname)s] %(message)s [%(filename)s:%(lineno)d]" + "%(asctime)s [%(levelname)s] %(message)s [%(filename)s:%(lineno)d]", ) - c_handler.setFormatter(formatter) - f_handler.setFormatter(formatter) + console_handler.setFormatter(formatter) + file_handler.setFormatter(formatter) - # Add handlers to the logger - logger.addHandler(c_handler) - logger.addHandler(f_handler) + root_logger = logging.getLogger() + root_logger.setLevel(logging.DEBUG) + root_logger.handlers.clear() + root_logger.addHandler(console_handler) + root_logger.addHandler(file_handler) - # Set logging level for third-party libraries to WARNING to suppress their debug logs - logging.getLogger("monstr").setLevel(logging.WARNING) - logging.getLogger("nostr").setLevel(logging.WARNING) + logging.captureWarnings(True) + + logging.getLogger("monstr").setLevel(logging.ERROR) + logging.getLogger("nostr").setLevel(logging.ERROR) +@pause_logging_for_ui def confirm_action(prompt: str) -> bool: """ Prompts the user for confirmation. @@ -136,6 +162,7 @@ def get_notification_text(pm: PasswordManager) -> str: return color_text(getattr(note, "message", ""), category) +@pause_logging_for_ui def handle_switch_fingerprint(password_manager: PasswordManager): """ Handles switching the active fingerprint. @@ -164,6 +191,13 @@ def handle_switch_fingerprint(password_manager: PasswordManager): return selected_fingerprint = fingerprints[int(choice) - 1] + if selected_fingerprint == password_manager.current_fingerprint: + print( + colored( + f"Seed profile {selected_fingerprint} is already active.", "yellow" + ) + ) + return if password_manager.select_fingerprint(selected_fingerprint): print(colored(f"Switched to seed profile {selected_fingerprint}.", "green")) else: @@ -187,11 +221,7 @@ def handle_add_new_fingerprint(password_manager: PasswordManager): def handle_remove_fingerprint(password_manager: PasswordManager): - """ - Handles removing an existing seed profile. - - :param password_manager: An instance of PasswordManager. - """ + """Handle removing an existing seed profile.""" try: fingerprints = password_manager.fingerprint_manager.list_fingerprints() if not fingerprints: @@ -210,12 +240,24 @@ def handle_remove_fingerprint(password_manager: PasswordManager): selected_fingerprint = fingerprints[int(choice) - 1] confirm = confirm_action( - f"Are you sure you want to remove seed profile {selected_fingerprint}? This will delete all associated data. (Y/N): " + f"Are you sure you want to remove seed profile {selected_fingerprint}? This will delete all associated data. (Y/N):" ) if confirm: + + def _cleanup_and_exit() -> None: + password_manager.current_fingerprint = None + password_manager.is_dirty = False + getattr(password_manager, "cleanup", lambda: None)() + print(colored("All seed profiles removed. Exiting.", "yellow")) + sys.exit(0) + if password_manager.fingerprint_manager.remove_fingerprint( - selected_fingerprint + selected_fingerprint, _cleanup_and_exit ): + password_manager.current_fingerprint = ( + password_manager.fingerprint_manager.current_fingerprint + ) + password_manager.is_dirty = False print( colored( f"Seed profile {selected_fingerprint} removed successfully.", @@ -274,10 +316,9 @@ def handle_display_npub(password_manager: PasswordManager): def _display_live_stats( password_manager: PasswordManager, interval: float = 1.0 ) -> None: - """Continuously refresh stats until the user presses Enter. + """Display stats and wait for the user to continue. - Each refresh also triggers a background sync so the latest stats are - displayed if newer data exists on Nostr. + A background sync runs before rendering so the latest stats are shown. """ stats_mgr = getattr(password_manager, "stats_manager", None) @@ -304,28 +345,17 @@ def _display_live_stats( stats_mgr.reset() return - while True: - if callable(sync_fn): - try: - sync_fn() - except Exception: # pragma: no cover - sync best effort - logging.debug("Background sync failed during stats display") - clear_screen() - display_fn() - note = get_notification_text(password_manager) - if note: - print(note) - print(colored("Press Enter to continue.", "cyan")) - sys.stdout.flush() - try: - user_input = timed_input("", interval) - if user_input.strip() == "" or user_input.strip().lower() == "b": - break - except TimeoutError: - pass - except KeyboardInterrupt: - print() - break + clear_screen() + display_fn() + note = get_notification_text(password_manager) + if note: + print(note) + print(colored("Press Enter to continue.", "cyan")) + sys.stdout.flush() + try: + timed_input("", None) + except KeyboardInterrupt: + print() if stats_mgr is not None: stats_mgr.reset() @@ -403,34 +433,36 @@ def handle_post_to_nostr( def handle_retrieve_from_nostr(password_manager: PasswordManager): - """ - Handles the action of retrieving the encrypted password index from Nostr. - """ + """Retrieve the encrypted password index from Nostr.""" try: - password_manager.nostr_client.fingerprint = password_manager.current_fingerprint - result = asyncio.run(password_manager.nostr_client.fetch_latest_snapshot()) - if result: - manifest, chunks = result - encrypted = gzip.decompress(b"".join(chunks)) - if manifest.delta_since: - version = int(manifest.delta_since) - deltas = asyncio.run( - password_manager.nostr_client.fetch_deltas_since(version) - ) - if deltas: - encrypted = deltas[-1] - password_manager.encryption_manager.decrypt_and_save_index_from_nostr( - encrypted - ) - print(colored("Encrypted index retrieved and saved successfully.", "green")) - logging.info("Encrypted index retrieved and saved successfully from Nostr.") - else: + password_manager.sync_index_from_nostr() + if password_manager.nostr_client.last_error: msg = ( f"No Nostr events found for fingerprint" f" {password_manager.current_fingerprint}." + if "Snapshot not found" in password_manager.nostr_client.last_error + else password_manager.nostr_client.last_error ) print(colored(msg, "red")) logging.error(msg) + else: + try: + legacy_pub = ( + password_manager.nostr_client.key_manager.generate_legacy_nostr_keys().public_key_hex() + ) + if password_manager.nostr_client.keys.public_key_hex() == legacy_pub: + note = "Restored index from legacy Nostr backup." + print(colored(note, "yellow")) + logging.info(note) + except Exception: + pass + print( + colored( + "Encrypted index retrieved and saved successfully.", + "green", + ) + ) + logging.info("Encrypted index retrieved and saved successfully from Nostr.") except Exception as e: logging.error(f"Failed to retrieve from Nostr: {e}", exc_info=True) print(colored(f"Error: Failed to retrieve from Nostr: {e}", "red")) @@ -601,33 +633,49 @@ def handle_set_inactivity_timeout(password_manager: PasswordManager) -> None: def handle_set_kdf_iterations(password_manager: PasswordManager) -> None: - """Change the PBKDF2 iteration count.""" + """Interactive slider for PBKDF2 iteration strength with benchmarking.""" + import hashlib + import time + cfg_mgr = password_manager.config_manager if cfg_mgr is None: print(colored("Configuration manager unavailable.", "red")) return + levels = [ + ("1", "Very Fast", 10_000), + ("2", "Fast", 50_000), + ("3", "Balanced", 100_000), + ("4", "Slow", 200_000), + ("5", "Paranoid", 500_000), + ] try: current = cfg_mgr.get_kdf_iterations() - print(colored(f"Current iterations: {current}", "cyan")) except Exception as e: logging.error(f"Error loading iterations: {e}") print(colored(f"Error: {e}", "red")) return - value = input("Enter new iteration count: ").strip() - if not value: - print(colored("No iteration count entered.", "yellow")) + print(colored(f"Current iterations: {current}", "cyan")) + for key, label, iters in levels: + marker = "*" if iters == current else " " + print(colored(f"{key}. {label} ({iters}) {marker}", "menu")) + print(colored("b. Benchmark current setting", "menu")) + choice = input("Select strength or 'b' to benchmark: ").strip().lower() + if not choice: + print(colored("No change made.", "yellow")) + return + if choice == "b": + start = time.perf_counter() + hashlib.pbkdf2_hmac("sha256", b"bench", b"salt", current) + elapsed = time.perf_counter() - start + print(colored(f"{current} iterations took {elapsed:.2f}s", "green")) + return + selected = {k: v for k, _, v in levels}.get(choice) + if not selected: + print(colored("Invalid choice.", "red")) return try: - iterations = int(value) - if iterations <= 0: - print(colored("Iterations must be positive.", "red")) - return - except ValueError: - print(colored("Invalid number.", "red")) - return - try: - cfg_mgr.set_kdf_iterations(iterations) - print(colored("KDF iteration count updated.", "green")) + cfg_mgr.set_kdf_iterations(selected) + print(colored(f"KDF iteration count set to {selected}.", "green")) except Exception as e: logging.error(f"Error saving iterations: {e}") print(colored(f"Error: {e}", "red")) @@ -666,8 +714,7 @@ def handle_set_additional_backup_location(pm: PasswordManager) -> None: path = Path(value).expanduser() path.mkdir(parents=True, exist_ok=True) test_file = path / ".seedpass_write_test" - with open(test_file, "w") as f: - f.write("test") + atomic_write(test_file, lambda f: f.write("test")) test_file.unlink() except Exception as e: print(colored(f"Path not writable: {e}", "red")) @@ -706,8 +753,18 @@ def handle_toggle_secret_mode(pm: PasswordManager) -> None: """Toggle secret mode and adjust clipboard delay.""" cfg = pm.config_manager if cfg is None: - print(colored("Configuration manager unavailable.", "red")) - return + vault = getattr(pm, "vault", None) + fingerprint_dir = getattr(pm, "fingerprint_dir", None) + if vault is not None and fingerprint_dir is not None: + try: + cfg = pm.config_manager = ConfigManager(vault, fingerprint_dir) + except Exception as exc: + logging.error(f"Failed to initialize ConfigManager: {exc}") + print(colored("Configuration manager unavailable.", "red")) + return + else: + print(colored("Configuration manager unavailable.", "red")) + return try: enabled = cfg.get_secret_mode_enabled() delay = cfg.get_clipboard_clear_delay() @@ -747,8 +804,18 @@ def handle_toggle_quick_unlock(pm: PasswordManager) -> None: """Enable or disable Quick Unlock.""" cfg = pm.config_manager if cfg is None: - print(colored("Configuration manager unavailable.", "red")) - return + vault = getattr(pm, "vault", None) + fingerprint_dir = getattr(pm, "fingerprint_dir", None) + if vault is not None and fingerprint_dir is not None: + try: + cfg = pm.config_manager = ConfigManager(vault, fingerprint_dir) + except Exception as exc: + logging.error(f"Failed to initialize ConfigManager: {exc}") + print(colored("Configuration manager unavailable.", "red")) + return + else: + print(colored("Configuration manager unavailable.", "red")) + return try: enabled = cfg.get_quick_unlock() except Exception as exc: @@ -774,8 +841,18 @@ def handle_toggle_offline_mode(pm: PasswordManager) -> None: """Enable or disable offline mode.""" cfg = pm.config_manager if cfg is None: - print(colored("Configuration manager unavailable.", "red")) - return + vault = getattr(pm, "vault", None) + fingerprint_dir = getattr(pm, "fingerprint_dir", None) + if vault is not None and fingerprint_dir is not None: + try: + cfg = pm.config_manager = ConfigManager(vault, fingerprint_dir) + except Exception as exc: + logging.error(f"Failed to initialize ConfigManager: {exc}") + print(colored("Configuration manager unavailable.", "red")) + return + else: + print(colored("Configuration manager unavailable.", "red")) + return try: enabled = cfg.get_offline_mode() except Exception as exc: @@ -916,12 +993,12 @@ def handle_settings(password_manager: PasswordManager) -> None: print(color_text("8. Import database", "menu")) print(color_text("9. Export 2FA codes", "menu")) print(color_text("10. Set additional backup location", "menu")) - print(color_text("11. Set KDF iterations", "menu")) + print(color_text("11. KDF strength & benchmark", "menu")) print(color_text("12. Set inactivity timeout", "menu")) print(color_text("13. Lock Vault", "menu")) print(color_text("14. Stats", "menu")) print(color_text("15. Toggle Secret Mode", "menu")) - print(color_text("16. Toggle Offline Mode", "menu")) + print(color_text("16. Toggle Offline Mode (default ON)", "menu")) print(color_text("17. Toggle Quick Unlock", "menu")) choice = input("Select an option or press Enter to go back: ").strip() if choice == "1": @@ -929,7 +1006,16 @@ def handle_settings(password_manager: PasswordManager) -> None: elif choice == "2": handle_nostr_menu(password_manager) elif choice == "3": - password_manager.change_password() + try: + old_pw = prompt_existing_password("Enter your current password: ") + new_pw = prompt_new_password() + password_manager.change_password(old_pw, new_pw) + except ValueError: + print(colored("Incorrect password.", "red")) + except PasswordPromptError: + pass + except Exception as e: + print(colored(f"Error: {e}", "red")) pause() elif choice == "4": password_manager.handle_verify_checksum() @@ -1007,6 +1093,7 @@ def display_menu( getattr(password_manager, "start_background_relay_check", lambda: None)() _display_live_stats(password_manager) while True: + getattr(password_manager, "poll_background_errors", lambda: None)() fp, parent_fp, child_fp = getattr( password_manager, "header_fingerprint_args", @@ -1027,11 +1114,15 @@ def display_menu( getattr(password_manager, "start_background_relay_check", lambda: None)() continue # Periodically push updates to Nostr - if ( - password_manager.is_dirty - and time.time() - password_manager.last_update >= sync_interval - ): - handle_post_to_nostr(password_manager) + current_fp = getattr(password_manager, "current_fingerprint", None) + if current_fp: + if ( + password_manager.is_dirty + and time.time() - password_manager.last_update >= sync_interval + ): + handle_post_to_nostr(password_manager) + password_manager.is_dirty = False + else: password_manager.is_dirty = False # Flush logging handlers @@ -1121,17 +1212,6 @@ def display_menu( elif choice == "2": password_manager.update_activity() password_manager.handle_retrieve_entry() - fp, parent_fp, child_fp = getattr( - password_manager, - "header_fingerprint_args", - (getattr(password_manager, "current_fingerprint", None), None, None), - ) - clear_header_with_notification( - fp, - "Main Menu", - parent_fingerprint=parent_fp, - child_fingerprint=child_fp, - ) elif choice == "3": password_manager.update_activity() password_manager.handle_search_entries() @@ -1165,6 +1245,7 @@ def main(argv: list[str] | None = None, *, fingerprint: str | None = None) -> in Optional seed profile fingerprint to select automatically. """ configure_logging() + _warn_missing_optional_dependencies() initialize_app() logger = logging.getLogger(__name__) logger.info("Starting SeedPass Password Manager") @@ -1172,10 +1253,35 @@ def main(argv: list[str] | None = None, *, fingerprint: str | None = None) -> in load_global_config() parser = argparse.ArgumentParser() parser.add_argument("--fingerprint") + parser.add_argument( + "--restore-backup", + help="Restore index from backup file before starting", + ) + parser.add_argument( + "--no-clipboard", + action="store_true", + help="Disable clipboard support and print secrets", + ) + parser.add_argument( + "--deterministic-totp", + action="store_true", + help="Derive TOTP secrets deterministically", + ) + parser.add_argument( + "--max-prompt-attempts", + type=int, + default=None, + help="Maximum number of password/seed prompt attempts (0 to disable)", + ) sub = parser.add_subparsers(dest="command") exp = sub.add_parser("export") exp.add_argument("--file") + exp.add_argument( + "--unencrypted", + action="store_true", + help="Export without encryption", + ) imp = sub.add_parser("import") imp.add_argument("--file") @@ -1191,6 +1297,44 @@ def main(argv: list[str] | None = None, *, fingerprint: str | None = None) -> in args = parser.parse_args(argv) + if args.restore_backup: + fp_target = args.fingerprint or fingerprint + if fp_target is None: + print( + colored( + "Error: --fingerprint is required when using --restore-backup.", + "red", + ) + ) + return 1 + try: + restore_backup_index(Path(args.restore_backup), fp_target) + logger.info("Restored backup from %s", args.restore_backup) + except Exception as e: + logger.error(f"Failed to restore backup: {e}", exc_info=True) + print(colored(f"Error: Failed to restore backup: {e}", "red")) + return 1 + elif args.command is None: + print("Startup Options:") + print("1. Continue") + print("2. Restore from backup") + choice = input("Select an option: ").strip() + if choice == "2": + path = input("Enter backup file path: ").strip() + fp_target = args.fingerprint or fingerprint + if fp_target is None: + fp_target = input("Enter fingerprint for restore: ").strip() + try: + restore_backup_index(Path(path), fp_target) + logger.info("Restored backup from %s", path) + except Exception as e: + logger.error(f"Failed to restore backup: {e}", exc_info=True) + print(colored(f"Error: Failed to restore backup: {e}", "red")) + return 1 + + if args.max_prompt_attempts is not None: + os.environ["SEEDPASS_MAX_PROMPT_ATTEMPTS"] = str(args.max_prompt_attempts) + try: password_manager = PasswordManager(fingerprint=args.fingerprint or fingerprint) logger.info("PasswordManager initialized successfully.") @@ -1203,8 +1347,15 @@ def main(argv: list[str] | None = None, *, fingerprint: str | None = None) -> in print(colored(f"Error: Failed to initialize PasswordManager: {e}", "red")) return 1 + if args.no_clipboard: + password_manager.secret_mode_enabled = False + if args.deterministic_totp: + password_manager.deterministic_totp = True + if args.command == "export": - password_manager.handle_export_database(Path(args.file)) + password_manager.handle_export_database( + Path(args.file), encrypt=not args.unencrypted + ) return 0 if args.command == "import": password_manager.handle_import_database(Path(args.file)) @@ -1246,15 +1397,22 @@ def main(argv: list[str] | None = None, *, fingerprint: str | None = None) -> in if entry.get("type") != EntryType.TOTP.value: print(colored("Entry is not a TOTP entry.", "red")) return 1 - code = password_manager.entry_manager.get_totp_code( - idx, password_manager.parent_seed + key = getattr(password_manager, "KEY_TOTP_DET", None) or getattr( + password_manager, "parent_seed", None ) + code = password_manager.entry_manager.get_totp_code(idx, key) print(code) try: - copy_to_clipboard(code, password_manager.clipboard_clear_delay) - print(colored("Code copied to clipboard", "green")) - except Exception as exc: - logging.warning(f"Clipboard copy failed: {exc}") + if copy_to_clipboard(code, password_manager.clipboard_clear_delay): + print(colored("Code copied to clipboard", "green")) + except ClipboardUnavailableError as exc: + print( + colored( + f"Clipboard unavailable: {exc}\n" + "Re-run with '--no-clipboard' to print codes instead.", + "yellow", + ) + ) return 0 def signal_handler(sig, _frame): diff --git a/src/nostr/backup_models.py b/src/nostr/backup_models.py index b3c7e8cc..7918c5c1 100644 --- a/src/nostr/backup_models.py +++ b/src/nostr/backup_models.py @@ -25,3 +25,4 @@ class Manifest: algo: str chunks: List[ChunkMeta] delta_since: Optional[int] = None + nonce: Optional[str] = None diff --git a/src/nostr/client.py b/src/nostr/client.py index 0f87a68c..ecd8ab05 100644 --- a/src/nostr/client.py +++ b/src/nostr/client.py @@ -1,36 +1,39 @@ -# src/nostr/client.py - +import asyncio import base64 import json import logging import time -from typing import List, Optional, Tuple, TYPE_CHECKING -import hashlib -import asyncio -import gzip import threading -import websockets +from datetime import timedelta +from typing import List, Optional, TYPE_CHECKING -# Imports from the nostr-sdk library +import websockets from nostr_sdk import ( Client, - Keys, - NostrSigner, EventBuilder, Filter, Kind, KindStandard, + NostrSigner, Tag, RelayUrl, + PublicKey, ) -from datetime import timedelta -from nostr_sdk import EventId, Timestamp +from nostr_sdk import EventId, Keys, Timestamp -from .key_manager import KeyManager as SeedPassKeyManager -from .backup_models import Manifest, ChunkMeta, KIND_MANIFEST, KIND_SNAPSHOT_CHUNK -from seedpass.core.encryption import EncryptionManager from constants import MAX_RETRIES, RETRY_DELAY -from utils.file_lock import exclusive_lock +from seedpass.core.encryption import EncryptionManager + +from .backup_models import ( + ChunkMeta, + KIND_DELTA, + KIND_MANIFEST, + KIND_SNAPSHOT_CHUNK, + Manifest, +) +from .connection import ConnectionHandler, DEFAULT_RELAYS +from .key_manager import KeyManager as SeedPassKeyManager +from .snapshot import SnapshotHandler, prepare_snapshot if TYPE_CHECKING: # pragma: no cover - imported for type hints from seedpass.core.config_manager import ConfigManager @@ -42,56 +45,8 @@ ClientBuilder = Client logger = logging.getLogger(__name__) logger.setLevel(logging.WARNING) -DEFAULT_RELAYS = [ - "wss://relay.snort.social", - "wss://nostr.oxtr.dev", - "wss://relay.primal.net", -] -# Identifier prefix for replaceable manifest events -MANIFEST_ID_PREFIX = "seedpass-manifest-" - - -def prepare_snapshot( - encrypted_bytes: bytes, limit: int -) -> Tuple[Manifest, list[bytes]]: - """Compress and split the encrypted vault into chunks. - - Each chunk is hashed with SHA-256 and described in the returned - :class:`Manifest`. - - Parameters - ---------- - encrypted_bytes : bytes - The encrypted vault contents. - limit : int - Maximum chunk size in bytes. - - Returns - ------- - Tuple[Manifest, list[bytes]] - The manifest describing all chunks and the list of chunk bytes. - """ - - compressed = gzip.compress(encrypted_bytes) - chunks = [compressed[i : i + limit] for i in range(0, len(compressed), limit)] - - metas: list[ChunkMeta] = [] - for i, chunk in enumerate(chunks): - metas.append( - ChunkMeta( - id=f"seedpass-chunk-{i:04d}", - size=len(chunk), - hash=hashlib.sha256(chunk).hexdigest(), - event_id=None, - ) - ) - - manifest = Manifest(ver=1, algo="gzip", chunks=metas) - return manifest, chunks - - -class NostrClient: +class NostrClient(ConnectionHandler, SnapshotHandler): """Interact with the Nostr network using nostr-sdk.""" def __init__( @@ -102,6 +57,8 @@ class NostrClient: parent_seed: Optional[str] = None, offline_mode: bool = False, config_manager: Optional["ConfigManager"] = None, + key_index: bytes | None = None, + account_index: int | None = None, ) -> None: self.encryption_manager = encryption_manager self.fingerprint = fingerprint @@ -113,7 +70,7 @@ class NostrClient: parent_seed = self.encryption_manager.decrypt_parent_seed() # Use our project's KeyManager to derive the private key - self.key_manager = KeyManager(parent_seed, fingerprint) + self.key_manager = KeyManager(parent_seed, fingerprint, account_index) # Create a nostr-sdk Keys object from our derived private key private_key_hex = self.key_manager.keys.private_key_hex() @@ -144,6 +101,7 @@ class NostrClient: self.current_manifest: Manifest | None = None self.current_manifest_id: str | None = None self._delta_events: list[str] = [] + self.key_index = key_index or b"" # Configure and initialize the nostr-sdk Client signer = NostrSigner.keys(self.keys) @@ -151,555 +109,9 @@ class NostrClient: self._connected = False - def connect(self) -> None: - """Connect the client to all configured relays.""" - if self.offline_mode or not self.relays: - return - if not self._connected: - self.initialize_client_pool() - def initialize_client_pool(self) -> None: - """Add relays to the client and connect.""" - if self.offline_mode or not self.relays: - return - asyncio.run(self._initialize_client_pool()) - - async def _connect_async(self) -> None: - """Ensure the client is connected within an async context.""" - if self.offline_mode or not self.relays: - return - if not self._connected: - await self._initialize_client_pool() - - async def _initialize_client_pool(self) -> None: - if self.offline_mode or not self.relays: - return - - formatted = [] - for relay in self.relays: - if isinstance(relay, str): - try: - formatted.append(RelayUrl.parse(relay)) - except Exception: - logger.error("Invalid relay URL: %s", relay) - else: - formatted.append(relay) - - if hasattr(self.client, "add_relays"): - await self.client.add_relays(formatted) - else: - for relay in formatted: - await self.client.add_relay(relay) - - await self.client.connect() - self._connected = True - logger.info("NostrClient connected to relays: %s", formatted) - - async def _ping_relay(self, relay: str, timeout: float) -> bool: - """Attempt to retrieve the latest event from a single relay.""" - sub_id = "seedpass-health" - pubkey = self.keys.public_key().to_hex() - req = json.dumps( - ["REQ", sub_id, {"kinds": [1], "authors": [pubkey], "limit": 1}] - ) - try: - async with websockets.connect( - relay, open_timeout=timeout, close_timeout=timeout - ) as ws: - await ws.send(req) - while True: - msg = await asyncio.wait_for(ws.recv(), timeout=timeout) - data = json.loads(msg) - if data[0] in {"EVENT", "EOSE"}: - return True - except Exception: - return False - - async def _check_relay_health(self, min_relays: int, timeout: float) -> int: - tasks = [self._ping_relay(r, timeout) for r in self.relays] - results = await asyncio.gather(*tasks, return_exceptions=True) - healthy = sum(1 for r in results if r is True) - if healthy < min_relays: - logger.warning( - "Only %s relays responded with data; consider adding more.", healthy - ) - return healthy - - def check_relay_health(self, min_relays: int = 2, timeout: float = 5.0) -> int: - """Ping relays and return the count of those providing data.""" - if self.offline_mode or not self.relays: - return 0 - return asyncio.run(self._check_relay_health(min_relays, timeout)) - - def publish_json_to_nostr( - self, - encrypted_json: bytes, - to_pubkey: str | None = None, - alt_summary: str | None = None, - ) -> str | None: - """Builds and publishes a Kind 1 text note or direct message. - - Parameters - ---------- - encrypted_json : bytes - The encrypted index data to publish. - to_pubkey : str | None, optional - If provided, send as a direct message to this public key. - alt_summary : str | None, optional - If provided, include an ``alt`` tag so uploads can be - associated with a specific event like a password change. - """ - if self.offline_mode or not self.relays: - return None - self.connect() - self.last_error = None - try: - content = base64.b64encode(encrypted_json).decode("utf-8") - - if to_pubkey: - receiver = PublicKey.parse(to_pubkey) - event_output = self.client.send_private_msg_to( - self.relays, receiver, content - ) - else: - builder = EventBuilder.text_note(content) - if alt_summary: - builder = builder.tags([Tag.alt(alt_summary)]) - event = builder.build(self.keys.public_key()).sign_with_keys(self.keys) - event_output = self.publish_event(event) - - event_id_hex = ( - event_output.id.to_hex() - if hasattr(event_output, "id") - else str(event_output) - ) - logger.info(f"Successfully published event with ID: {event_id_hex}") - return event_id_hex - - except Exception as e: - self.last_error = str(e) - logger.error(f"Failed to publish JSON to Nostr: {e}") - return None - - def publish_event(self, event): - """Publish a prepared event to the configured relays.""" - if self.offline_mode or not self.relays: - return None - self.connect() - return asyncio.run(self._publish_event(event)) - - async def _publish_event(self, event): - if self.offline_mode or not self.relays: - return None - await self._connect_async() - return await self.client.send_event(event) - - def update_relays(self, new_relays: List[str]) -> None: - """Reconnect the client using a new set of relays.""" - self.close_client_pool() - self.relays = new_relays - signer = NostrSigner.keys(self.keys) - self.client = Client(signer) - self._connected = False - # Immediately reconnect using the updated relay list - self.initialize_client_pool() - - def retrieve_json_from_nostr_sync( - self, retries: int | None = None, delay: float | None = None - ) -> Optional[bytes]: - """Retrieve the latest Kind 1 event from the author with optional retries.""" - if self.offline_mode or not self.relays: - return None - - if retries is None or delay is None: - if self.config_manager is None: - from seedpass.core.config_manager import ConfigManager - from seedpass.core.vault import Vault - - cfg_mgr = ConfigManager( - Vault(self.encryption_manager, self.fingerprint_dir), - self.fingerprint_dir, - ) - else: - cfg_mgr = self.config_manager - cfg = cfg_mgr.load_config(require_pin=False) - retries = int(cfg.get("nostr_max_retries", MAX_RETRIES)) - delay = float(cfg.get("nostr_retry_delay", RETRY_DELAY)) - - self.connect() - self.last_error = None - for attempt in range(retries): - try: - result = asyncio.run(self._retrieve_json_from_nostr()) - if result is not None: - return result - except Exception as e: - self.last_error = str(e) - logger.error("Failed to retrieve events from Nostr: %s", e) - if attempt < retries - 1: - sleep_time = delay * (2**attempt) - time.sleep(sleep_time) - return None - - async def _retrieve_json_from_nostr(self) -> Optional[bytes]: - if self.offline_mode or not self.relays: - return None - await self._connect_async() - # Filter for the latest text note (Kind 1) from our public key - pubkey = self.keys.public_key() - f = Filter().author(pubkey).kind(Kind.from_std(KindStandard.TEXT_NOTE)).limit(1) - - timeout = timedelta(seconds=10) - events = (await self.client.fetch_events(f, timeout)).to_vec() - - if not events: - self.last_error = "No events found on relays for this user." - logger.warning(self.last_error) - return None - - latest_event = events[0] - content_b64 = latest_event.content() - - if content_b64: - return base64.b64decode(content_b64.encode("utf-8")) - self.last_error = "Latest event contained no content" - return None - - async def publish_snapshot( - self, encrypted_bytes: bytes, limit: int = 50_000 - ) -> tuple[Manifest, str]: - """Publish a compressed snapshot split into chunks. - - Parameters - ---------- - encrypted_bytes : bytes - Vault contents already encrypted with the user's key. - limit : int, optional - Maximum chunk size in bytes. Defaults to 50 kB. - """ - - start = time.perf_counter() - if self.offline_mode or not self.relays: - return Manifest(ver=1, algo="gzip", chunks=[]), "" - await self.ensure_manifest_is_current() - await self._connect_async() - manifest, chunks = prepare_snapshot(encrypted_bytes, limit) - for meta, chunk in zip(manifest.chunks, chunks): - content = base64.b64encode(chunk).decode("utf-8") - builder = EventBuilder(Kind(KIND_SNAPSHOT_CHUNK), content).tags( - [Tag.identifier(meta.id)] - ) - event = builder.build(self.keys.public_key()).sign_with_keys(self.keys) - result = await self.client.send_event(event) - try: - meta.event_id = ( - result.id.to_hex() if hasattr(result, "id") else str(result) - ) - except Exception: - meta.event_id = None - - manifest_json = json.dumps( - { - "ver": manifest.ver, - "algo": manifest.algo, - "chunks": [meta.__dict__ for meta in manifest.chunks], - "delta_since": manifest.delta_since, - } - ) - - manifest_identifier = f"{MANIFEST_ID_PREFIX}{self.fingerprint}" - manifest_event = ( - EventBuilder(Kind(KIND_MANIFEST), manifest_json) - .tags([Tag.identifier(manifest_identifier)]) - .build(self.keys.public_key()) - .sign_with_keys(self.keys) - ) - await self.client.send_event(manifest_event) - with self._state_lock: - self.current_manifest = manifest - self.current_manifest_id = manifest_identifier - # Record when this snapshot was published for future delta events - self.current_manifest.delta_since = int(time.time()) - self._delta_events = [] - if getattr(self, "verbose_timing", False): - duration = time.perf_counter() - start - logger.info("publish_snapshot completed in %.2f seconds", duration) - return manifest, manifest_identifier - - async def _fetch_single_chunk( - self, meta: ChunkMeta, pubkey, max_retries: int, delay: float - ) -> bytes | None: - """Fetch a single chunk with retries.""" - timeout = timedelta(seconds=10) - for attempt in range(max_retries): - cf = Filter().author(pubkey).kind(Kind(KIND_SNAPSHOT_CHUNK)) - if meta.event_id: - cf = cf.id(EventId.parse(meta.event_id)) - else: - cf = cf.identifier(meta.id) - cf = cf.limit(1) - cev = (await self.client.fetch_events(cf, timeout)).to_vec() - if cev: - candidate = base64.b64decode(cev[0].content().encode("utf-8")) - if hashlib.sha256(candidate).hexdigest() == meta.hash: - return candidate - if attempt < max_retries - 1: - await asyncio.sleep(delay * (2**attempt)) - return None - - async def _fetch_chunks_with_retry( - self, manifest_event - ) -> tuple[Manifest, list[bytes]] | None: - """Retrieve all chunks referenced by ``manifest_event`` with retries.""" - - pubkey = self.keys.public_key() - # timeout is used inside _fetch_single_chunk - - try: - data = json.loads(manifest_event.content()) - manifest = Manifest( - ver=data["ver"], - algo=data["algo"], - chunks=[ChunkMeta(**c) for c in data["chunks"]], - delta_since=( - int(data["delta_since"]) - if data.get("delta_since") is not None - else None - ), - ) - except Exception: - return None - - if self.config_manager is None: - from seedpass.core.config_manager import ConfigManager - from seedpass.core.vault import Vault - - cfg_mgr = ConfigManager( - Vault(self.encryption_manager, self.fingerprint_dir), - self.fingerprint_dir, - ) - else: - cfg_mgr = self.config_manager - cfg = cfg_mgr.load_config(require_pin=False) - max_retries = int(cfg.get("nostr_max_retries", MAX_RETRIES)) - delay = float(cfg.get("nostr_retry_delay", RETRY_DELAY)) - - # Limit concurrency to 10 to avoid overwhelming relays - semaphore = asyncio.Semaphore(10) - - async def fetch_with_semaphore(meta: ChunkMeta) -> bytes | None: - async with semaphore: - return await self._fetch_single_chunk(meta, pubkey, max_retries, delay) - - tasks = [fetch_with_semaphore(meta) for meta in manifest.chunks] - results = await asyncio.gather(*tasks) - - chunks: list[bytes] = [] - for res in results: - if res is None: - return None - chunks.append(res) - - ident = None - try: - tags_obj = manifest_event.tags() - ident = tags_obj.identifier() - except Exception: - tags = getattr(manifest_event, "tags", None) - if callable(tags): - tags = tags() - if tags: - tag = tags[0] - if hasattr(tag, "as_vec"): - vec = tag.as_vec() - if vec and len(vec) >= 2: - ident = vec[1] - elif isinstance(tag, (list, tuple)) and len(tag) >= 2: - ident = tag[1] - elif isinstance(tag, str): - ident = tag - with self._state_lock: - self.current_manifest = manifest - self.current_manifest_id = ident - return manifest, chunks - - async def fetch_latest_snapshot(self) -> Tuple[Manifest, list[bytes]] | None: - """Retrieve the latest manifest and all snapshot chunks.""" - if self.offline_mode or not self.relays: - return None - await self._connect_async() - - self.last_error = None - pubkey = self.keys.public_key() - ident = f"{MANIFEST_ID_PREFIX}{self.fingerprint}" - f = Filter().author(pubkey).kind(Kind(KIND_MANIFEST)).identifier(ident).limit(1) - timeout = timedelta(seconds=10) - try: - events = (await self.client.fetch_events(f, timeout)).to_vec() - except Exception as e: # pragma: no cover - network errors - self.last_error = str(e) - logger.error( - "Failed to fetch manifest from relays %s: %s", - self.relays, - e, - ) - return None - - if not events: - return None - - for manifest_event in events: - try: - result = await self._fetch_chunks_with_retry(manifest_event) - if result is not None: - return result - except Exception as e: # pragma: no cover - network errors - self.last_error = str(e) - logger.error( - "Error retrieving snapshot from relays %s: %s", - self.relays, - e, - ) - - if self.last_error is None: - self.last_error = "Snapshot not found on relays" - - return None - - async def ensure_manifest_is_current(self) -> None: - """Verify the local manifest is up to date before publishing.""" - if self.offline_mode or not self.relays: - return - await self._connect_async() - pubkey = self.keys.public_key() - ident = f"{MANIFEST_ID_PREFIX}{self.fingerprint}" - f = Filter().author(pubkey).kind(Kind(KIND_MANIFEST)).identifier(ident).limit(1) - timeout = timedelta(seconds=10) - try: - events = (await self.client.fetch_events(f, timeout)).to_vec() - except Exception: - return - if not events: - return - try: - data = json.loads(events[0].content()) - remote = data.get("delta_since") - if remote is not None: - remote = int(remote) - except Exception: - return - with self._state_lock: - local = self.current_manifest.delta_since if self.current_manifest else None - if remote is not None and (local is None or remote > local): - self.last_error = "Manifest out of date" - raise RuntimeError("Manifest out of date") - - async def publish_delta(self, delta_bytes: bytes, manifest_id: str) -> str: - """Publish a delta event referencing a manifest.""" - if self.offline_mode or not self.relays: - return "" - await self.ensure_manifest_is_current() - await self._connect_async() - - content = base64.b64encode(delta_bytes).decode("utf-8") - tag = Tag.event(EventId.parse(manifest_id)) - builder = EventBuilder(Kind(KIND_DELTA), content).tags([tag]) - event = builder.build(self.keys.public_key()).sign_with_keys(self.keys) - result = await self.client.send_event(event) - delta_id = result.id.to_hex() if hasattr(result, "id") else str(result) - created_at = getattr( - event, "created_at", getattr(event, "timestamp", int(time.time())) - ) - if hasattr(created_at, "secs"): - created_at = created_at.secs - manifest_event = None - with self._state_lock: - if self.current_manifest is not None: - self.current_manifest.delta_since = int(created_at) - manifest_json = json.dumps( - { - "ver": self.current_manifest.ver, - "algo": self.current_manifest.algo, - "chunks": [ - meta.__dict__ for meta in self.current_manifest.chunks - ], - "delta_since": self.current_manifest.delta_since, - } - ) - manifest_event = ( - EventBuilder(Kind(KIND_MANIFEST), manifest_json) - .tags([Tag.identifier(self.current_manifest_id)]) - .build(self.keys.public_key()) - .sign_with_keys(self.keys) - ) - self._delta_events.append(delta_id) - if manifest_event is not None: - await self.client.send_event(manifest_event) - return delta_id - - async def fetch_deltas_since(self, version: int) -> list[bytes]: - """Retrieve delta events newer than the given version.""" - if self.offline_mode or not self.relays: - return [] - await self._connect_async() - - pubkey = self.keys.public_key() - f = ( - Filter() - .author(pubkey) - .kind(Kind(KIND_DELTA)) - .since(Timestamp.from_secs(version)) - ) - timeout = timedelta(seconds=10) - events = (await self.client.fetch_events(f, timeout)).to_vec() - events.sort( - key=lambda ev: getattr(ev, "created_at", getattr(ev, "timestamp", 0)) - ) - deltas: list[bytes] = [] - for ev in events: - deltas.append(base64.b64decode(ev.content().encode("utf-8"))) - - manifest = self.get_current_manifest() - if manifest is not None: - snap_size = sum(c.size for c in manifest.chunks) - if ( - len(deltas) >= self.delta_threshold - or sum(len(d) for d in deltas) > snap_size - ): - # Publish a new snapshot to consolidate deltas - joined = b"".join(deltas) - await self.publish_snapshot(joined) - exp = Timestamp.from_secs(int(time.time())) - for ev in events: - exp_builder = EventBuilder(Kind(KIND_DELTA), ev.content()).tags( - [Tag.expiration(exp)] - ) - exp_event = exp_builder.build( - self.keys.public_key() - ).sign_with_keys(self.keys) - await self.client.send_event(exp_event) - return deltas - - def get_current_manifest(self) -> Manifest | None: - """Thread-safe access to ``current_manifest``.""" - with self._state_lock: - return self.current_manifest - - def get_current_manifest_id(self) -> str | None: - """Thread-safe access to ``current_manifest_id``.""" - with self._state_lock: - return self.current_manifest_id - - def get_delta_events(self) -> list[str]: - """Thread-safe snapshot of pending delta event IDs.""" - with self._state_lock: - return list(self._delta_events) - - def close_client_pool(self) -> None: - """Disconnects the client from all relays.""" - try: - asyncio.run(self.client.disconnect()) - self._connected = False - logger.info("NostrClient disconnected from relays.") - except Exception as e: - logger.error("Error during NostrClient shutdown: %s", e) +__all__ = [ + "NostrClient", + "prepare_snapshot", + "DEFAULT_RELAYS", +] diff --git a/src/nostr/coincurve_keys.py b/src/nostr/coincurve_keys.py index 99604acf..053059f4 100644 --- a/src/nostr/coincurve_keys.py +++ b/src/nostr/coincurve_keys.py @@ -27,7 +27,8 @@ class Keys: @staticmethod def hex_to_bech32(key_str: str, prefix: str = "npub") -> str: - data = convertbits(bytes.fromhex(key_str), 8, 5) + # Pad to align with 5-bit groups as expected for Bech32 encoding + data = convertbits(bytes.fromhex(key_str), 8, 5, True) return bech32_encode(prefix, data) @staticmethod diff --git a/src/nostr/connection.py b/src/nostr/connection.py new file mode 100644 index 00000000..262bf151 --- /dev/null +++ b/src/nostr/connection.py @@ -0,0 +1,232 @@ +import asyncio +import base64 +import json +import logging +from datetime import timedelta +from typing import List, Optional + +import websockets +from . import client as nostr_client +from constants import MAX_RETRIES, RETRY_DELAY + +logger = logging.getLogger("nostr.client") +logger.setLevel(logging.WARNING) + +DEFAULT_RELAYS = [ + "wss://relay.snort.social", + "wss://nostr.oxtr.dev", + "wss://relay.primal.net", +] + + +class ConnectionHandler: + """Mixin providing relay connection and retry logic.""" + + async def connect(self) -> None: + """Connect the client to all configured relays.""" + if self.offline_mode or not self.relays: + return + if not getattr(self, "_connected", False): + await self._initialize_client_pool() + + def initialize_client_pool(self) -> None: + """Add relays to the client and connect.""" + if self.offline_mode or not self.relays: + return + asyncio.run(self._initialize_client_pool()) + + async def _connect_async(self) -> None: + """Ensure the client is connected within an async context.""" + if self.offline_mode or not self.relays: + return + if not getattr(self, "_connected", False): + await self._initialize_client_pool() + + async def _initialize_client_pool(self) -> None: + if self.offline_mode or not self.relays: + return + + formatted = [] + for relay in self.relays: + if isinstance(relay, str): + try: + formatted.append(nostr_client.RelayUrl.parse(relay)) + except Exception: + logger.error("Invalid relay URL: %s", relay) + else: + formatted.append(relay) + + if hasattr(self.client, "add_relays"): + await self.client.add_relays(formatted) + else: + for relay in formatted: + await self.client.add_relay(relay) + + await self.client.connect() + self._connected = True + logger.info("NostrClient connected to relays: %s", formatted) + + async def _ping_relay(self, relay: str, timeout: float) -> bool: + """Attempt to retrieve the latest event from a single relay.""" + sub_id = "seedpass-health" + pubkey = self.keys.public_key().to_hex() + req = json.dumps( + [ + "REQ", + sub_id, + {"kinds": [1], "authors": [pubkey], "limit": 1}, + ] + ) + try: + async with websockets.connect( + relay, open_timeout=timeout, close_timeout=timeout + ) as ws: + await ws.send(req) + while True: + msg = await asyncio.wait_for(ws.recv(), timeout=timeout) + data = json.loads(msg) + if data[0] in {"EVENT", "EOSE"}: + return True + except Exception: + return False + + async def _check_relay_health(self, min_relays: int, timeout: float) -> int: + tasks = [self._ping_relay(r, timeout) for r in self.relays] + results = await asyncio.gather(*tasks, return_exceptions=True) + healthy = sum(1 for r in results if r is True) + if healthy < min_relays: + logger.warning( + "Only %s relays responded with data; consider adding more.", healthy + ) + return healthy + + def check_relay_health(self, min_relays: int = 2, timeout: float = 5.0) -> int: + """Ping relays and return the count of those providing data.""" + if self.offline_mode or not self.relays: + return 0 + return asyncio.run(self._check_relay_health(min_relays, timeout)) + + async def publish_json_to_nostr( + self, + encrypted_json: bytes, + to_pubkey: str | None = None, + alt_summary: str | None = None, + ) -> str | None: + """Build and publish a Kind 1 text note or direct message.""" + if self.offline_mode or not self.relays: + return None + await self.connect() + self.last_error = None + try: + content = base64.b64encode(encrypted_json).decode("utf-8") + + if to_pubkey: + receiver = nostr_client.PublicKey.parse(to_pubkey) + event_output = self.client.send_private_msg_to( + self.relays, receiver, content + ) + else: + builder = nostr_client.EventBuilder.text_note(content) + if alt_summary: + builder = builder.tags([nostr_client.Tag.alt(alt_summary)]) + event = builder.build(self.keys.public_key()).sign_with_keys(self.keys) + event_output = await self.publish_event(event) + + event_id_hex = ( + event_output.id.to_hex() + if hasattr(event_output, "id") + else str(event_output) + ) + logger.info("Successfully published event with ID: %s", event_id_hex) + return event_id_hex + + except Exception as e: + self.last_error = str(e) + logger.error("Failed to publish JSON to Nostr: %s", e) + return None + + async def publish_event(self, event): + """Publish a prepared event to the configured relays.""" + if self.offline_mode or not self.relays: + return None + await self.connect() + return await self.client.send_event(event) + + def update_relays(self, new_relays: List[str]) -> None: + """Reconnect the client using a new set of relays.""" + self.close_client_pool() + self.relays = new_relays + signer = nostr_client.NostrSigner.keys(self.keys) + self.client = nostr_client.Client(signer) + self._connected = False + self.initialize_client_pool() + + async def retrieve_json_from_nostr( + self, retries: int | None = None, delay: float | None = None + ) -> Optional[bytes]: + """Retrieve the latest Kind 1 event from the author with optional retries.""" + if self.offline_mode or not self.relays: + return None + + if retries is None or delay is None: + if self.config_manager is None: + from seedpass.core.config_manager import ConfigManager + from seedpass.core.vault import Vault + + cfg_mgr = ConfigManager( + Vault(self.encryption_manager, self.fingerprint_dir), + self.fingerprint_dir, + ) + else: + cfg_mgr = self.config_manager + cfg = cfg_mgr.load_config(require_pin=False) + retries = int(cfg.get("nostr_max_retries", MAX_RETRIES)) + delay = float(cfg.get("nostr_retry_delay", RETRY_DELAY)) + + await self.connect() + self.last_error = None + for attempt in range(retries): + try: + result = await self._retrieve_json_from_nostr() + if result is not None: + return result + except Exception as e: + self.last_error = str(e) + logger.error("Failed to retrieve events from Nostr: %s", e) + if attempt < retries - 1: + sleep_time = delay * (2**attempt) + await asyncio.sleep(sleep_time) + return None + + async def _retrieve_json_from_nostr(self) -> Optional[bytes]: + if self.offline_mode or not self.relays: + return None + await self._connect_async() + pubkey = self.keys.public_key() + f = ( + nostr_client.Filter() + .author(pubkey) + .kind(nostr_client.Kind.from_std(nostr_client.KindStandard.TEXT_NOTE)) + .limit(1) + ) + timeout = timedelta(seconds=10) + events = (await self.client.fetch_events(f, timeout)).to_vec() + if not events: + self.last_error = "No events found on relays for this user." + logger.warning(self.last_error) + return None + latest_event = events[0] + content_b64 = latest_event.content() + if content_b64: + return base64.b64decode(content_b64.encode("utf-8")) + self.last_error = "Latest event contained no content" + return None + + def close_client_pool(self) -> None: + """Disconnect the client from all relays.""" + try: + asyncio.run(self.client.disconnect()) + self._connected = False + logger.info("NostrClient disconnected from relays.") + except Exception as e: + logger.error("Error during NostrClient shutdown: %s", e) diff --git a/src/nostr/event_handler.py b/src/nostr/event_handler.py deleted file mode 100644 index 56a4b3af..00000000 --- a/src/nostr/event_handler.py +++ /dev/null @@ -1,52 +0,0 @@ -# nostr/event_handler.py - -import time -import logging -import traceback - -try: - from monstr.event.event import Event -except ImportError: # pragma: no cover - optional dependency - - class Event: # minimal placeholder for type hints when monstr is absent - id: str - created_at: int - content: str - - -# Instantiate the logger -logger = logging.getLogger(__name__) - - -class EventHandler: - """ - Handles incoming Nostr events. - """ - - def __init__(self): - pass # Initialize if needed - - def handle_new_event(self, evt: Event): - """ - Processes incoming events by logging their details. - - :param evt: The received Event object. - """ - try: - # Assuming evt.created_at is always an integer Unix timestamp - if isinstance(evt.created_at, int): - created_at_str = time.strftime( - "%Y-%m-%d %H:%M:%S", time.gmtime(evt.created_at) - ) - else: - # Handle unexpected types gracefully - created_at_str = str(evt.created_at) - - # Log the event details without extra newlines - logger.info( - f"[New Event] ID: {evt.id} | Created At: {created_at_str} | Content: {evt.content}" - ) - except Exception as e: - logger.error(f"Error handling new event: {e}", exc_info=True) - # Optionally, handle the exception without re-raising - # For example, continue processing other events diff --git a/src/nostr/key_manager.py b/src/nostr/key_manager.py index ed6ca88a..34aa2b9f 100644 --- a/src/nostr/key_manager.py +++ b/src/nostr/key_manager.py @@ -2,28 +2,36 @@ import hashlib import logging -import traceback from bech32 import bech32_encode, convertbits from local_bip85.bip85 import BIP85 from bip_utils import Bip39SeedGenerator from .coincurve_keys import Keys +# BIP-85 application numbers for Nostr key derivation +NOSTR_KEY_APP_ID = 1237 +LEGACY_NOSTR_KEY_APP_ID = 0 + logger = logging.getLogger(__name__) class KeyManager: - """ - Manages key generation, encoding, and derivation for NostrClient. - """ + """Manages key generation, encoding, and derivation for ``NostrClient``.""" - def __init__(self, parent_seed: str, fingerprint: str): - """ - Initializes the KeyManager with the provided parent_seed and fingerprint. + def __init__( + self, parent_seed: str, fingerprint: str, account_index: int | None = None + ): + """Initialize the key manager. - Parameters: - parent_seed (str): The parent seed used for key derivation. - fingerprint (str): The fingerprint to differentiate key derivations. + Parameters + ---------- + parent_seed: + The BIP-39 seed used as the root for derivations. + fingerprint: + Seed profile fingerprint used for legacy derivations and logging. + account_index: + Optional explicit index for BIP-85 Nostr key derivation. When ``None`` + the index defaults to ``0``. """ try: if not isinstance(parent_seed, str): @@ -37,12 +45,15 @@ class KeyManager: self.parent_seed = parent_seed self.fingerprint = fingerprint - logger.debug(f"KeyManager initialized with parent_seed and fingerprint.") + self.account_index = account_index + logger.debug( + "KeyManager initialized with parent_seed, fingerprint and account index." + ) # Initialize BIP85 self.bip85 = self.initialize_bip85() - # Generate Nostr keys using the fingerprint + # Generate Nostr keys using the provided account index self.keys = self.generate_nostr_keys() logger.debug("Nostr Keys initialized successfully.") @@ -67,33 +78,47 @@ class KeyManager: raise def generate_nostr_keys(self) -> Keys: - """ - Derives a unique Nostr key pair for the given fingerprint using BIP-85. - - Returns: - Keys: An instance of Keys containing the Nostr key pair. - """ + """Derive a Nostr key pair using the configured ``account_index``.""" try: - # Convert fingerprint to an integer index (using a hash function) - index = int(hashlib.sha256(self.fingerprint.encode()).hexdigest(), 16) % ( - 2**31 - ) + index = self.account_index if self.account_index is not None else 0 - # Derive entropy for Nostr key (32 bytes) entropy_bytes = self.bip85.derive_entropy( - index=index, - bytes_len=32, # Adjust parameter name and value as per your method signature + index=index, entropy_bytes=32, app_no=NOSTR_KEY_APP_ID ) - # Generate Nostr key pair from entropy private_key_hex = entropy_bytes.hex() keys = Keys(priv_k=private_key_hex) - logger.debug(f"Nostr keys generated for fingerprint {self.fingerprint}.") + logger.debug("Nostr keys generated for account index %s", index) return keys except Exception as e: logger.error(f"Failed to generate Nostr keys: {e}", exc_info=True) raise + def generate_v1_nostr_keys(self) -> Keys: + """Derive keys using the legacy fingerprint-hash method.""" + try: + index = int(hashlib.sha256(self.fingerprint.encode()).hexdigest(), 16) % ( + 2**31 + ) + entropy_bytes = self.bip85.derive_entropy( + index=index, entropy_bytes=32, app_no=NOSTR_KEY_APP_ID + ) + return Keys(priv_k=entropy_bytes.hex()) + except Exception as e: + logger.error(f"Failed to generate v1 Nostr keys: {e}", exc_info=True) + raise + + def generate_legacy_nostr_keys(self) -> Keys: + """Derive Nostr keys using the legacy application ID.""" + try: + entropy = self.bip85.derive_entropy( + index=0, entropy_bytes=32, app_no=LEGACY_NOSTR_KEY_APP_ID + ) + return Keys(priv_k=entropy.hex()) + except Exception as e: + logger.error(f"Failed to generate legacy Nostr keys: {e}", exc_info=True) + raise + def get_public_key_hex(self) -> str: """ Returns the public key in hexadecimal format. diff --git a/src/nostr/logging_config.py b/src/nostr/logging_config.py deleted file mode 100644 index def3e1a1..00000000 --- a/src/nostr/logging_config.py +++ /dev/null @@ -1,41 +0,0 @@ -# nostr/logging_config.py - -import logging -import os - -# Comment out or remove the configure_logging function to avoid conflicts -# def configure_logging(): -# """ -# Configures logging with both file and console handlers. -# Logs include the timestamp, log level, message, filename, and line number. -# Only ERROR and higher-level messages are shown in the terminal, while all messages -# are logged in the log file. -# """ -# logger = logging.getLogger() -# logger.setLevel(logging.DEBUG) # Set root logger to DEBUG -# -# # Prevent adding multiple handlers if configure_logging is called multiple times -# if not logger.handlers: -# # Create the 'logs' folder if it doesn't exist -# log_directory = 'logs' -# if not os.path.exists(log_directory): -# os.makedirs(log_directory) -# -# # Create handlers -# c_handler = logging.StreamHandler() -# f_handler = logging.FileHandler(os.path.join(log_directory, 'app.log')) -# -# # Set levels: only errors and critical messages will be shown in the console -# c_handler.setLevel(logging.ERROR) -# f_handler.setLevel(logging.DEBUG) -# -# # Create formatters and add them to handlers, include file and line number in log messages -# formatter = logging.Formatter( -# '%(asctime)s [%(levelname)s] %(message)s [%(filename)s:%(lineno)d]' -# ) -# c_handler.setFormatter(formatter) -# f_handler.setFormatter(formatter) -# -# # Add handlers to the logger -# logger.addHandler(c_handler) -# logger.addHandler(f_handler) diff --git a/src/nostr/snapshot.py b/src/nostr/snapshot.py new file mode 100644 index 00000000..1d4858eb --- /dev/null +++ b/src/nostr/snapshot.py @@ -0,0 +1,443 @@ +import asyncio +import base64 +import gzip +import hashlib +import hmac +import json +import logging +import os +import time +from datetime import timedelta +from typing import Tuple + +from . import client as nostr_client + +from constants import MAX_RETRIES, RETRY_DELAY + +from .backup_models import ( + ChunkMeta, + Manifest, + KIND_DELTA, + KIND_MANIFEST, + KIND_SNAPSHOT_CHUNK, +) + +logger = logging.getLogger("nostr.client") +logger.setLevel(logging.WARNING) + + +def prepare_snapshot( + encrypted_bytes: bytes, limit: int +) -> Tuple[Manifest, list[bytes]]: + """Compress and split the encrypted vault into chunks.""" + compressed = gzip.compress(encrypted_bytes) + chunks = [compressed[i : i + limit] for i in range(0, len(compressed), limit)] + metas: list[ChunkMeta] = [] + for i, chunk in enumerate(chunks): + metas.append( + ChunkMeta( + id=f"seedpass-chunk-{i:04d}", + size=len(chunk), + hash=hashlib.sha256(chunk).hexdigest(), + event_id=None, + ) + ) + manifest = Manifest(ver=1, algo="gzip", chunks=metas) + return manifest, chunks + + +def new_manifest_id(key_index: bytes) -> tuple[str, bytes]: + """Return a new manifest identifier and nonce. + + The identifier is computed as HMAC-SHA256 of ``b"manifest|" + nonce`` + using ``key_index`` as the HMAC key. The nonce is returned so it can be + embedded inside the manifest itself. + """ + + nonce = os.urandom(16) + digest = hmac.new(key_index, b"manifest|" + nonce, hashlib.sha256).hexdigest() + return digest, nonce + + +class SnapshotHandler: + """Mixin providing chunk and manifest handling.""" + + async def publish_snapshot( + self, encrypted_bytes: bytes, limit: int = 50_000 + ) -> tuple[Manifest, str]: + start = time.perf_counter() + if self.offline_mode or not self.relays: + return Manifest(ver=1, algo="gzip", chunks=[]), "" + await self.ensure_manifest_is_current() + await self._connect_async() + manifest, chunks = prepare_snapshot(encrypted_bytes, limit) + + existing: dict[str, str] = {} + if self.current_manifest: + for old in self.current_manifest.chunks: + if old.hash and old.event_id: + existing[old.hash] = old.event_id + + for meta, chunk in zip(manifest.chunks, chunks): + cached_id = existing.get(meta.hash) + if cached_id: + meta.event_id = cached_id + continue + content = base64.b64encode(chunk).decode("utf-8") + builder = nostr_client.EventBuilder( + nostr_client.Kind(KIND_SNAPSHOT_CHUNK), content + ).tags([nostr_client.Tag.identifier(meta.id)]) + event = builder.build(self.keys.public_key()).sign_with_keys(self.keys) + result = await self.client.send_event(event) + try: + meta.event_id = ( + result.id.to_hex() if hasattr(result, "id") else str(result) + ) + except Exception: + meta.event_id = None + + if ( + self.current_manifest_id + and self.current_manifest + and getattr(self.current_manifest, "nonce", None) + ): + manifest_id = self.current_manifest_id + manifest.nonce = self.current_manifest.nonce + else: + manifest_id, nonce = new_manifest_id(self.key_index) + manifest.nonce = base64.b64encode(nonce).decode("utf-8") + + manifest_json = json.dumps( + { + "ver": manifest.ver, + "algo": manifest.algo, + "chunks": [meta.__dict__ for meta in manifest.chunks], + "delta_since": manifest.delta_since, + "nonce": manifest.nonce, + } + ) + + manifest_event = ( + nostr_client.EventBuilder(nostr_client.Kind(KIND_MANIFEST), manifest_json) + .tags([nostr_client.Tag.identifier(manifest_id)]) + .build(self.keys.public_key()) + .sign_with_keys(self.keys) + ) + await self.client.send_event(manifest_event) + with self._state_lock: + self.current_manifest = manifest + self.current_manifest_id = manifest_id + self.current_manifest.delta_since = int(time.time()) + self._delta_events = [] + if getattr(self, "verbose_timing", False): + duration = time.perf_counter() - start + logger.info("publish_snapshot completed in %.2f seconds", duration) + return manifest, manifest_id + + async def _fetch_chunks_with_retry( + self, manifest_event + ) -> tuple[Manifest, list[bytes]] | None: + pubkey = self.keys.public_key() + timeout = timedelta(seconds=10) + try: + data = json.loads(manifest_event.content()) + manifest = Manifest( + ver=data["ver"], + algo=data["algo"], + chunks=[ChunkMeta(**c) for c in data["chunks"]], + delta_since=( + int(data["delta_since"]) + if data.get("delta_since") is not None + else None + ), + nonce=data.get("nonce"), + ) + except Exception: + return None + + if self.config_manager is None: + from seedpass.core.config_manager import ConfigManager + from seedpass.core.vault import Vault + + cfg_mgr = ConfigManager( + Vault(self.encryption_manager, self.fingerprint_dir), + self.fingerprint_dir, + ) + else: + cfg_mgr = self.config_manager + cfg = cfg_mgr.load_config(require_pin=False) + max_retries = int(cfg.get("nostr_max_retries", MAX_RETRIES)) + delay = float(cfg.get("nostr_retry_delay", RETRY_DELAY)) + + chunks: list[bytes] = [] + for meta in manifest.chunks: + chunk_bytes: bytes | None = None + for attempt in range(max_retries): + cf = ( + nostr_client.Filter() + .author(pubkey) + .kind(nostr_client.Kind(KIND_SNAPSHOT_CHUNK)) + ) + if meta.event_id: + cf = cf.id(nostr_client.EventId.parse(meta.event_id)) + else: + cf = cf.identifier(meta.id) + cf = cf.limit(1) + cev = (await self.client.fetch_events(cf, timeout)).to_vec() + if cev: + candidate = base64.b64decode(cev[0].content().encode("utf-8")) + if hashlib.sha256(candidate).hexdigest() == meta.hash: + chunk_bytes = candidate + break + if attempt < max_retries - 1: + await asyncio.sleep(delay * (2**attempt)) + if chunk_bytes is None: + return None + chunks.append(chunk_bytes) + + ident = None + try: + tags_obj = manifest_event.tags() + ident = tags_obj.identifier() + except Exception: + tags = getattr(manifest_event, "tags", None) + if callable(tags): + tags = tags() + if tags: + tag = tags[0] + if hasattr(tag, "as_vec"): + vec = tag.as_vec() + if vec and len(vec) >= 2: + ident = vec[1] + elif isinstance(tag, (list, tuple)) and len(tag) >= 2: + ident = tag[1] + elif isinstance(tag, str): + ident = tag + with self._state_lock: + self.current_manifest = manifest + self.current_manifest_id = ident + return manifest, chunks + + async def _fetch_manifest_with_keys( + self, keys_obj: nostr_client.Keys + ) -> tuple[Manifest, list[bytes]] | None: + """Retrieve the manifest and chunks using ``keys_obj``.""" + self.keys = keys_obj + pubkey = self.keys.public_key() + timeout = timedelta(seconds=10) + + ident = self.current_manifest_id + f = nostr_client.Filter().author(pubkey).kind(nostr_client.Kind(KIND_MANIFEST)) + if ident: + f = f.identifier(ident) + f = f.limit(1) + try: + events = (await self.client.fetch_events(f, timeout)).to_vec() + except Exception as e: # pragma: no cover - network errors + self.last_error = str(e) + logger.error( + "Failed to fetch manifest from relays %s: %s", + self.relays, + e, + ) + return None + + if not events and ident: + f = ( + nostr_client.Filter() + .author(pubkey) + .kind(nostr_client.Kind(KIND_MANIFEST)) + .limit(1) + ) + try: + events = (await self.client.fetch_events(f, timeout)).to_vec() + except Exception as e: # pragma: no cover - network errors + self.last_error = str(e) + logger.error( + "Failed to fetch manifest from relays %s: %s", + self.relays, + e, + ) + return None + if not events: + return None + + for manifest_event in events: + try: + result = await self._fetch_chunks_with_retry(manifest_event) + if result is not None: + return result + except Exception as e: # pragma: no cover - network errors + self.last_error = str(e) + logger.error( + "Error retrieving snapshot from relays %s: %s", + self.relays, + e, + ) + return None + + async def fetch_latest_snapshot(self) -> Tuple[Manifest, list[bytes]] | None: + """Retrieve the latest manifest and all snapshot chunks.""" + if self.offline_mode or not self.relays: + return None + await self._connect_async() + self.last_error = None + logger.debug("Searching for backup with current keys...") + try: + primary_keys = nostr_client.Keys.parse( + self.key_manager.keys.private_key_hex() + ) + except Exception: + primary_keys = self.keys + result = await self._fetch_manifest_with_keys(primary_keys) + if result is not None: + return result + logger.warning( + "No backup found with current keys. Falling back to legacy key derivation..." + ) + try: + legacy_keys = self.key_manager.generate_legacy_nostr_keys() + legacy_sdk_keys = nostr_client.Keys.parse(legacy_keys.private_key_hex()) + except Exception as e: + self.last_error = str(e) + return None + result = await self._fetch_manifest_with_keys(legacy_sdk_keys) + if result is not None: + logger.info("Found legacy backup with old key derivation.") + return result + if self.last_error is None: + self.last_error = "No backup found on Nostr relays." + return None + + async def ensure_manifest_is_current(self) -> None: + """Verify the local manifest is up to date before publishing.""" + if self.offline_mode or not self.relays: + return + await self._connect_async() + pubkey = self.keys.public_key() + ident = self.current_manifest_id + if ident is None: + return + f = ( + nostr_client.Filter() + .author(pubkey) + .kind(nostr_client.Kind(KIND_MANIFEST)) + .identifier(ident) + .limit(1) + ) + timeout = timedelta(seconds=10) + try: + events = (await self.client.fetch_events(f, timeout)).to_vec() + except Exception: + return + if not events: + return + try: + data = json.loads(events[0].content()) + remote = data.get("delta_since") + if remote is not None: + remote = int(remote) + except Exception: + return + with self._state_lock: + local = self.current_manifest.delta_since if self.current_manifest else None + if remote is not None and (local is None or remote > local): + self.last_error = "Manifest out of date" + raise RuntimeError("Manifest out of date") + + async def publish_delta(self, delta_bytes: bytes, manifest_id: str) -> str: + if self.offline_mode or not self.relays: + return "" + await self.ensure_manifest_is_current() + await self._connect_async() + content = base64.b64encode(delta_bytes).decode("utf-8") + tag = nostr_client.Tag.event(nostr_client.EventId.parse(manifest_id)) + builder = nostr_client.EventBuilder( + nostr_client.Kind(KIND_DELTA), content + ).tags([tag]) + event = builder.build(self.keys.public_key()).sign_with_keys(self.keys) + result = await self.client.send_event(event) + delta_id = result.id.to_hex() if hasattr(result, "id") else str(result) + created_at = getattr( + event, "created_at", getattr(event, "timestamp", int(time.time())) + ) + if hasattr(created_at, "secs"): + created_at = created_at.secs + manifest_event = None + with self._state_lock: + if self.current_manifest is not None: + self.current_manifest.delta_since = int(created_at) + manifest_json = json.dumps( + { + "ver": self.current_manifest.ver, + "algo": self.current_manifest.algo, + "chunks": [ + meta.__dict__ for meta in self.current_manifest.chunks + ], + "delta_since": self.current_manifest.delta_since, + "nonce": self.current_manifest.nonce, + } + ) + manifest_event = ( + nostr_client.EventBuilder( + nostr_client.Kind(KIND_MANIFEST), manifest_json + ) + .tags([nostr_client.Tag.identifier(self.current_manifest_id)]) + .build(self.keys.public_key()) + .sign_with_keys(self.keys) + ) + self._delta_events.append(delta_id) + if manifest_event is not None: + await self.client.send_event(manifest_event) + return delta_id + + async def fetch_deltas_since(self, version: int) -> list[bytes]: + if self.offline_mode or not self.relays: + return [] + await self._connect_async() + pubkey = self.keys.public_key() + f = ( + nostr_client.Filter() + .author(pubkey) + .kind(nostr_client.Kind(KIND_DELTA)) + .since(nostr_client.Timestamp.from_secs(version)) + ) + timeout = timedelta(seconds=10) + events = (await self.client.fetch_events(f, timeout)).to_vec() + events.sort( + key=lambda ev: getattr(ev, "created_at", getattr(ev, "timestamp", 0)) + ) + deltas: list[bytes] = [] + for ev in events: + deltas.append(base64.b64decode(ev.content().encode("utf-8"))) + manifest = self.get_current_manifest() + if manifest is not None: + snap_size = sum(c.size for c in manifest.chunks) + if ( + len(deltas) >= self.delta_threshold + or sum(len(d) for d in deltas) > snap_size + ): + joined = b"".join(deltas) + await self.publish_snapshot(joined) + exp = nostr_client.Timestamp.from_secs(int(time.time())) + for ev in events: + exp_builder = nostr_client.EventBuilder( + nostr_client.Kind(KIND_DELTA), ev.content() + ).tags([nostr_client.Tag.expiration(exp)]) + exp_event = exp_builder.build( + self.keys.public_key() + ).sign_with_keys(self.keys) + await self.client.send_event(exp_event) + return deltas + + def get_current_manifest(self) -> Manifest | None: + with self._state_lock: + return self.current_manifest + + def get_current_manifest_id(self) -> str | None: + with self._state_lock: + return self.current_manifest_id + + def get_delta_events(self) -> list[str]: + with self._state_lock: + return list(self._delta_events) diff --git a/src/nostr/utils.py b/src/nostr/utils.py deleted file mode 100644 index 6485a82b..00000000 --- a/src/nostr/utils.py +++ /dev/null @@ -1,8 +0,0 @@ -# nostr/utils.py - -import logging - - -# Example utility function (if any specific to nostr package) -def some_helper_function(): - pass # Implement as needed diff --git a/src/repo-context.txt b/src/repo-context.txt index 30f018d4..86ff7ca8 100644 --- a/src/repo-context.txt +++ b/src/repo-context.txt @@ -28,7 +28,6 @@ Generated on: 2025-04-06 β”œβ”€β”€ encryption_manager.py β”œβ”€β”€ event_handler.py β”œβ”€β”€ key_manager.py - β”œβ”€β”€ logging_config.py β”œβ”€β”€ utils.py β”œβ”€β”€ utils/ β”œβ”€β”€ __init__.py @@ -3082,98 +3081,6 @@ __all__ = ['NostrClient'] ``` -## nostr/logging_config.py -```python -# nostr/logging_config.py - -import logging -import os - -# Comment out or remove the configure_logging function to avoid conflicts -# def configure_logging(): -# """ -# Configures logging with both file and console handlers. -# Logs include the timestamp, log level, message, filename, and line number. -# Only ERROR and higher-level messages are shown in the terminal, while all messages -# are logged in the log file. -# """ -# logger = logging.getLogger() -# logger.setLevel(logging.DEBUG) # Set root logger to DEBUG -# -# # Prevent adding multiple handlers if configure_logging is called multiple times -# if not logger.handlers: -# # Create the 'logs' folder if it doesn't exist -# log_directory = 'logs' -# if not os.path.exists(log_directory): -# os.makedirs(log_directory) -# -# # Create handlers -# c_handler = logging.StreamHandler() -# f_handler = logging.FileHandler(os.path.join(log_directory, 'app.log')) -# -# # Set levels: only errors and critical messages will be shown in the console -# c_handler.setLevel(logging.ERROR) -# f_handler.setLevel(logging.DEBUG) -# -# # Create formatters and add them to handlers, include file and line number in log messages -# formatter = logging.Formatter( -# '%(asctime)s [%(levelname)s] %(message)s [%(filename)s:%(lineno)d]' -# ) -# c_handler.setFormatter(formatter) -# f_handler.setFormatter(formatter) -# -# # Add handlers to the logger -# logger.addHandler(c_handler) -# logger.addHandler(f_handler) - -``` - -## nostr/event_handler.py -```python -# nostr/event_handler.py - -import time -import logging -import traceback -from monstr.event.event import Event - -# Instantiate the logger -logger = logging.getLogger(__name__) - -class EventHandler: - """ - Handles incoming Nostr events. - """ - - def __init__(self): - pass # Initialize if needed - - def handle_new_event(self, evt: Event): - """ - Processes incoming events by logging their details. - - :param evt: The received Event object. - """ - try: - # Assuming evt.created_at is always an integer Unix timestamp - if isinstance(evt.created_at, int): - created_at_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(evt.created_at)) - else: - # Handle unexpected types gracefully - created_at_str = str(evt.created_at) - - # Log the event details without extra newlines - logger.info( - f"[New Event] ID: {evt.id} | Created At: {created_at_str} | Content: {evt.content}" - ) - except Exception as e: - logger.error(f"Error handling new event: {e}") - logger.error(traceback.format_exc()) - # Optionally, handle the exception without re-raising - # For example, continue processing other events - -``` - ## nostr/encryption_manager.py ```python # nostr/encryption_manager.py @@ -3323,7 +3230,6 @@ import fcntl from .key_manager import KeyManager from .encryption_manager import EncryptionManager -from .event_handler import EventHandler from constants import APP_DIR from utils.file_lock import lock_file @@ -3373,7 +3279,6 @@ class NostrClient: ) # Initialize event handler and client pool - self.event_handler = EventHandler() self.relays = relays if relays else DEFAULT_RELAYS self.client_pool = ClientPool(self.relays) self.subscriptions = {} @@ -3629,7 +3534,6 @@ class NostrClient: try: await asyncio.gather( self.do_post_async(text), - self.subscribe_feed_async(self.event_handler.handle_new_event) ) except Exception as e: logger.error(f"An error occurred in publish_and_subscribe_async: {e}", exc_info=True) diff --git a/src/requirements.txt b/src/requirements.txt index b4f5c960..18294ce1 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -1,38 +1,42 @@ -colorama>=0.4.6 -termcolor>=1.1.0 -cryptography>=40.0.2 -bip-utils>=2.5.0 -bech32==1.2.0 -coincurve>=18.0.0 -mnemonic -aiohttp>=3.12.14 -bcrypt -pytest>=7.0 -pytest-cov -pytest-xdist -portalocker>=2.8 -nostr-sdk>=0.43 -websocket-client==1.7.0 +colorama>=0.4.6,<1 +termcolor>=1.1.0,<4 +cryptography>=40.0.2,<46 +bip-utils>=2.5.0,<3 +bech32>=1.2,<2 +coincurve>=18.0.0,<22 +mnemonic>=0.21,<1 +aiohttp>=3.9,<4 +bcrypt>=4,<5 +pytest>=7,<9 +pytest-cov>=4,<7 +pytest-xdist>=3,<4 +portalocker>=2.8,<4 +nostr-sdk>=0.43,<1 +websocket-client>=1.7,<2 -websockets>=15.0.0 -tomli -hypothesis -mutmut==2.4.4 -pgpy==0.6.0 -pyotp>=2.8.0 +websockets>=15,<16 +tomli>=2,<3 +hypothesis>=6,<7 +mutmut>=2.4.4,<4 +pgpy>=0.6,<1 +pyotp>=2.8,<3 -freezegun -pyperclip -qrcode>=8.2 -typer>=0.12.3 -fastapi>=0.116.1 -uvicorn>=0.35.0 -starlette>=0.47.2 -httpx>=0.28.1 -requests>=2.32 -python-multipart -orjson -argon2-cffi -toga-core>=0.5.2 -pillow -toga-dummy>=0.5.2 # for headless GUI tests +freezegun>=1.5.4,<2 +typer>=0.12.3,<1 + +# Optional dependencies - install as needed for additional features +pyperclip>=1.9,<2 # Clipboard support for secret mode +qrcode>=8.2,<9 # Generate QR codes for TOTP setup +fastapi>=0.110,<1 # API server +uvicorn>=0.29,<1 # API server +starlette>=0.47.2,<1 # API server +httpx>=0.28.1,<1 # API server +requests>=2.32,<3 # API server +python-multipart>=0.0.20,<0.1 # API server file uploads +PyJWT>=2.10.1,<3 # JWT authentication for API server +orjson>=3.11.1,<4 # Fast JSON serialization for API server +argon2-cffi>=21,<26 # Password hashing for API server +toga-core>=0.5.2,<1 # Desktop GUI +pillow>=11.3,<12 # Image support for GUI +toga-dummy>=0.5.2,<1 # Headless GUI tests +slowapi>=0.1.9,<1 # Rate limiting for API server diff --git a/src/runtime_requirements.txt b/src/runtime_requirements.txt index 3f0d4f29..d6b79c60 100644 --- a/src/runtime_requirements.txt +++ b/src/runtime_requirements.txt @@ -1,30 +1,35 @@ # Runtime dependencies for vendoring/packaging only # Generated from requirements.txt with all test-only packages removed -colorama>=0.4.6 -termcolor>=1.1.0 -cryptography>=40.0.2 -bip-utils>=2.5.0 -bech32==1.2.0 -coincurve>=18.0.0 -mnemonic -aiohttp>=3.12.14 -bcrypt -portalocker>=2.8 -nostr-sdk>=0.43 -websocket-client==1.7.0 +colorama>=0.4.6,<1 +termcolor>=1.1.0,<4 +cryptography>=40.0.2,<46 +bip-utils>=2.5.0,<3 +bech32>=1.2,<2 +coincurve>=18.0.0,<22 +mnemonic>=0.21,<1 +aiohttp>=3.9,<4 +bcrypt>=4,<5 +portalocker>=2.8,<4 +nostr-sdk>=0.43,<1 +websocket-client>=1.7,<2 -websockets>=15.0.0 -tomli -pgpy==0.6.0 -pyotp>=2.8.0 -pyperclip -qrcode>=8.2 -typer>=0.12.3 -fastapi>=0.116.0 -uvicorn>=0.35.0 -httpx>=0.28.1 -requests>=2.32 -python-multipart -orjson -argon2-cffi -toga-core>=0.5.2 +websockets>=15,<16 +tomli>=2,<3 +pgpy>=0.6,<1 +pyotp>=2.8,<3 +pyperclip>=1.9,<2 +qrcode>=8.2,<9 +typer>=0.12.3,<1 +fastapi>=0.110,<1 +uvicorn>=0.29,<1 +starlette>=0.47.2,<1 +httpx>=0.28.1,<1 +requests>=2.32,<3 +python-multipart>=0.0.20,<0.1 +PyJWT>=2.10.1,<3 +orjson>=3.11.1,<4 +argon2-cffi>=21,<26 +toga-core>=0.5.2,<1 +pillow>=11.3,<12 +toga-dummy>=0.5.2,<1 +slowapi>=0.1.9,<1 diff --git a/src/saved_config.yaml b/src/saved_config.yaml index 02e8ae65..85585a69 100644 --- a/src/saved_config.yaml +++ b/src/saved_config.yaml @@ -3,4 +3,3 @@ selected_directories: - utils/ - nostr/ - local_bip85/ -- password_manager/ diff --git a/src/seedpass/__init__.py b/src/seedpass/__init__.py index e69de29b..82da73d9 100644 --- a/src/seedpass/__init__.py +++ b/src/seedpass/__init__.py @@ -0,0 +1,3 @@ +"""SeedPass package initialization.""" + +# Optionally re-export selected symbols here. diff --git a/src/seedpass/api.py b/src/seedpass/api.py index a22ff7bd..c9dd7e9b 100644 --- a/src/seedpass/api.py +++ b/src/seedpass/api.py @@ -7,81 +7,143 @@ import tempfile from pathlib import Path import secrets import queue +import time +from collections import defaultdict, deque from typing import Any, List, Optional +import hashlib + +import logging from fastapi import FastAPI, Header, HTTPException, Request, Response import asyncio import sys -from fastapi.middleware.cors import CORSMiddleware + +import bcrypt from seedpass.core.manager import PasswordManager from seedpass.core.entry_types import EntryType from seedpass.core.api import UtilityService +_RATE_LIMIT = int(os.getenv("SEEDPASS_RATE_LIMIT", "100")) +_RATE_WINDOW = int(os.getenv("SEEDPASS_RATE_WINDOW", "60")) +_RATE_LIMIT_STR = f"{_RATE_LIMIT}/{_RATE_WINDOW} seconds" +_MAX_IMPORT_BYTES = int(os.getenv("SEEDPASS_MAX_IMPORT_BYTES", str(10 * 1024 * 1024))) + app = FastAPI() -_pm: Optional[PasswordManager] = None -_token: str = "" +logger = logging.getLogger(__name__) -def _check_token(auth: str | None) -> None: - expected = f"Bearer {_token}" - if auth is None or not secrets.compare_digest(auth, expected): +@app.middleware("http") +async def dynamic_cors_headers(request: Request, call_next): + response = await call_next(request) + origins = { + o.strip() for o in os.getenv("SEEDPASS_CORS_ORIGINS", "").split(",") if o.strip() + } + request_origin = request.headers.get("origin") + if request_origin and request_origin in origins: + response.headers["access-control-allow-origin"] = request_origin + response.headers["vary"] = "Origin" + return response + + +def _get_pm(request: Request) -> PasswordManager: + pm = getattr(request.app.state, "pm", None) + if pm is None: + raise HTTPException(status_code=503, detail="Server not initialized") + return pm + + +def _check_token(request: Request, auth: str | None) -> None: + if auth is None or not auth.startswith("Bearer "): raise HTTPException(status_code=401, detail="Unauthorized") + raw_token = auth.split(" ", 1)[1] + token = raw_token.encode() + token_hash = getattr(request.app.state, "token_hash", b"") + if not token_hash or not bcrypt.checkpw(token, token_hash): + raise HTTPException(status_code=401, detail="Unauthorized") + _enforce_rate_limit(request, raw_token) -def _reload_relays(relays: list[str]) -> None: +def _enforce_rate_limit(request: Request, raw_token: str) -> None: + now = time.monotonic() + client = request.client.host if request.client else "unknown" + token_tag = hashlib.blake2s(raw_token.encode("utf-8"), digest_size=8).hexdigest() + key = f"{client}:{token_tag}" + buckets = getattr(request.app.state, "rate_limit_buckets", None) + if buckets is None: + buckets = defaultdict(deque) + request.app.state.rate_limit_buckets = buckets + bucket = buckets[key] + while bucket and (now - bucket[0]) > _RATE_WINDOW: + bucket.popleft() + if len(bucket) >= _RATE_LIMIT: + raise HTTPException( + status_code=429, + detail=f"Rate limit exceeded ({_RATE_LIMIT_STR})", + ) + bucket.append(now) + + +def _reload_relays(request: Request, relays: list[str]) -> None: """Reload the Nostr client with a new relay list.""" - assert _pm is not None + pm = _get_pm(request) try: - _pm.nostr_client.close_client_pool() - except Exception: - pass + pm.nostr_client.close_client_pool() + except (OSError, RuntimeError, ValueError) as exc: + logger.warning("Failed to close NostrClient pool: %s", exc) try: - _pm.nostr_client.relays = relays - _pm.nostr_client.initialize_client_pool() - except Exception: - pass + pm.nostr_client.relays = relays + pm.nostr_client.initialize_client_pool() + except (OSError, RuntimeError, ValueError) as exc: + logger.error("Failed to initialize NostrClient with relays %s: %s", relays, exc) -def start_server(fingerprint: str | None = None, token: str | None = None) -> str: - """Initialize global state and return the API token. +def start_server(fingerprint: str | None = None) -> str: + """Initialize global state and return a random API token. Parameters ---------- fingerprint: Optional seed profile fingerprint to select before starting the server. - token: - Optional API token to use. If omitted, it checks the - ``SEEDPASS_API_TOKEN`` environment variable, or generates a new one. """ - global _pm, _token if fingerprint is None: - _pm = PasswordManager() + pm = PasswordManager() else: - _pm = PasswordManager(fingerprint=fingerprint) + pm = PasswordManager(fingerprint=fingerprint) + app.state.pm = pm + raw_token = secrets.token_urlsafe(32) + app.state.token_hash = bcrypt.hashpw(raw_token.encode(), bcrypt.gensalt()) + app.state.rate_limit_buckets = defaultdict(deque) + return raw_token - _token = token or os.getenv("SEEDPASS_API_TOKEN") or secrets.token_urlsafe(16) - origins = [ - o.strip() - for o in os.getenv("SEEDPASS_CORS_ORIGINS", "").split(",") - if o.strip() - ] - if origins and app.middleware_stack is None: - app.add_middleware( - CORSMiddleware, - allow_origins=origins, - allow_methods=["*"], - allow_headers=["*"], - ) - return _token + +def _require_password(request: Request, password: str | None) -> None: + pm = _get_pm(request) + if password is None or not pm.verify_password(password): + raise HTTPException(status_code=401, detail="Invalid password") + + +def _validate_encryption_path(request: Request, path: Path) -> Path: + """Validate and normalize ``path`` within the active fingerprint directory. + + Returns the resolved absolute path if validation succeeds. + """ + + pm = _get_pm(request) + try: + return pm.encryption_manager.resolve_relative_path(path) + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) @app.get("/api/v1/entry") -def search_entry(query: str, authorization: str | None = Header(None)) -> List[Any]: - _check_token(authorization) - assert _pm is not None - results = _pm.entry_manager.search_entries(query) +async def search_entry( + request: Request, query: str, authorization: str | None = Header(None) +) -> List[Any]: + _check_token(request, authorization) + pm = _get_pm(request) + results = pm.entry_manager.search_entries(query) return [ { "id": idx, @@ -96,17 +158,24 @@ def search_entry(query: str, authorization: str | None = Header(None)) -> List[A @app.get("/api/v1/entry/{entry_id}") -def get_entry(entry_id: int, authorization: str | None = Header(None)) -> Any: - _check_token(authorization) - assert _pm is not None - entry = _pm.entry_manager.retrieve_entry(entry_id) +async def get_entry( + request: Request, + entry_id: int, + authorization: str | None = Header(None), + password: str | None = Header(None, alias="X-SeedPass-Password"), +) -> Any: + _check_token(request, authorization) + _require_password(request, password) + pm = _get_pm(request) + entry = pm.entry_manager.retrieve_entry(entry_id) if entry is None: raise HTTPException(status_code=404, detail="Not found") return entry @app.post("/api/v1/entry") -def create_entry( +async def create_entry( + request: Request, entry: dict, authorization: str | None = Header(None), ) -> dict[str, Any]: @@ -116,8 +185,8 @@ def create_entry( on, the corresponding entry type is created. When omitted or set to ``password`` the behaviour matches the legacy password-entry API. """ - _check_token(authorization) - assert _pm is not None + _check_token(request, authorization) + pm = _get_pm(request) etype = (entry.get("type") or entry.get("kind") or "password").lower() @@ -133,7 +202,8 @@ def create_entry( "min_special", ] kwargs = {k: entry.get(k) for k in policy_keys if entry.get(k) is not None} - index = _pm.entry_manager.add_entry( + + index = pm.entry_manager.add_entry( entry.get("label"), int(entry.get("length", 12)), entry.get("username"), @@ -143,23 +213,25 @@ def create_entry( return {"id": index} if etype == "totp": - index = _pm.entry_manager.get_next_index() - uri = _pm.entry_manager.add_totp( + index = pm.entry_manager.get_next_index() + + uri = pm.entry_manager.add_totp( entry.get("label"), - _pm.parent_seed, + pm.KEY_TOTP_DET if entry.get("deterministic", False) else None, secret=entry.get("secret"), index=entry.get("index"), period=int(entry.get("period", 30)), digits=int(entry.get("digits", 6)), notes=entry.get("notes", ""), archived=entry.get("archived", False), + deterministic=entry.get("deterministic", False), ) return {"id": index, "uri": uri} if etype == "ssh": - index = _pm.entry_manager.add_ssh_key( + index = pm.entry_manager.add_ssh_key( entry.get("label"), - _pm.parent_seed, + pm.parent_seed, index=entry.get("index"), notes=entry.get("notes", ""), archived=entry.get("archived", False), @@ -167,9 +239,9 @@ def create_entry( return {"id": index} if etype == "pgp": - index = _pm.entry_manager.add_pgp_key( + index = pm.entry_manager.add_pgp_key( entry.get("label"), - _pm.parent_seed, + pm.parent_seed, index=entry.get("index"), key_type=entry.get("key_type", "ed25519"), user_id=entry.get("user_id", ""), @@ -179,9 +251,9 @@ def create_entry( return {"id": index} if etype == "nostr": - index = _pm.entry_manager.add_nostr_key( + index = pm.entry_manager.add_nostr_key( entry.get("label"), - _pm.parent_seed, + pm.parent_seed, index=entry.get("index"), notes=entry.get("notes", ""), archived=entry.get("archived", False), @@ -189,7 +261,7 @@ def create_entry( return {"id": index} if etype == "key_value": - index = _pm.entry_manager.add_key_value( + index = pm.entry_manager.add_key_value( entry.get("label"), entry.get("key"), entry.get("value"), @@ -199,13 +271,13 @@ def create_entry( if etype in {"seed", "managed_account"}: func = ( - _pm.entry_manager.add_seed + pm.entry_manager.add_seed if etype == "seed" - else _pm.entry_manager.add_managed_account + else pm.entry_manager.add_managed_account ) index = func( entry.get("label"), - _pm.parent_seed, + pm.parent_seed, index=entry.get("index"), notes=entry.get("notes", ""), ) @@ -216,6 +288,7 @@ def create_entry( @app.put("/api/v1/entry/{entry_id}") def update_entry( + request: Request, entry_id: int, entry: dict, authorization: str | None = Header(None), @@ -225,10 +298,10 @@ def update_entry( Additional fields like ``period``, ``digits`` and ``value`` are forwarded for specialized entry types (e.g. TOTP or key/value entries). """ - _check_token(authorization) - assert _pm is not None + _check_token(request, authorization) + pm = _get_pm(request) try: - _pm.entry_manager.modify_entry( + pm.entry_manager.modify_entry( entry_id, username=entry.get("username"), url=entry.get("url"), @@ -246,31 +319,34 @@ def update_entry( @app.post("/api/v1/entry/{entry_id}/archive") def archive_entry( - entry_id: int, authorization: str | None = Header(None) + request: Request, entry_id: int, authorization: str | None = Header(None) ) -> dict[str, str]: """Archive an entry.""" - _check_token(authorization) - assert _pm is not None - _pm.entry_manager.archive_entry(entry_id) + _check_token(request, authorization) + pm = _get_pm(request) + pm.entry_manager.archive_entry(entry_id) return {"status": "archived"} @app.post("/api/v1/entry/{entry_id}/unarchive") def unarchive_entry( - entry_id: int, authorization: str | None = Header(None) + request: Request, entry_id: int, authorization: str | None = Header(None) ) -> dict[str, str]: """Restore an archived entry.""" - _check_token(authorization) - assert _pm is not None - _pm.entry_manager.restore_entry(entry_id) + _check_token(request, authorization) + pm = _get_pm(request) + pm.entry_manager.restore_entry(entry_id) return {"status": "active"} @app.get("/api/v1/config/{key}") -def get_config(key: str, authorization: str | None = Header(None)) -> Any: - _check_token(authorization) - assert _pm is not None - value = _pm.config_manager.load_config(require_pin=False).get(key) +def get_config( + request: Request, key: str, authorization: str | None = Header(None) +) -> Any: + _check_token(request, authorization) + pm = _get_pm(request) + value = pm.config_manager.load_config(require_pin=False).get(key) + if value is None: raise HTTPException(status_code=404, detail="Not found") return {"key": key, "value": value} @@ -278,12 +354,15 @@ def get_config(key: str, authorization: str | None = Header(None)) -> Any: @app.put("/api/v1/config/{key}") def update_config( - key: str, data: dict, authorization: str | None = Header(None) + request: Request, + key: str, + data: dict, + authorization: str | None = Header(None), ) -> dict[str, str]: """Update a configuration setting.""" - _check_token(authorization) - assert _pm is not None - cfg = _pm.config_manager + _check_token(request, authorization) + pm = _get_pm(request) + cfg = pm.config_manager mapping = { "relays": lambda v: cfg.set_relays(v, require_pin=False), "pin": cfg.set_pin, @@ -296,6 +375,7 @@ def update_config( } action = mapping.get(key) + if action is None: raise HTTPException(status_code=400, detail="Unknown key") @@ -308,84 +388,105 @@ def update_config( @app.post("/api/v1/secret-mode") def set_secret_mode( - data: dict, authorization: str | None = Header(None) + request: Request, data: dict, authorization: str | None = Header(None) ) -> dict[str, str]: """Enable/disable secret mode and set the clipboard delay.""" - _check_token(authorization) - assert _pm is not None + _check_token(request, authorization) + pm = _get_pm(request) enabled = data.get("enabled") + delay = data.get("delay") + if enabled is None or delay is None: raise HTTPException(status_code=400, detail="Missing fields") - cfg = _pm.config_manager + cfg = pm.config_manager cfg.set_secret_mode_enabled(bool(enabled)) cfg.set_clipboard_clear_delay(int(delay)) - _pm.secret_mode_enabled = bool(enabled) - _pm.clipboard_clear_delay = int(delay) + pm.secret_mode_enabled = bool(enabled) + pm.clipboard_clear_delay = int(delay) return {"status": "ok"} @app.get("/api/v1/fingerprint") -def list_fingerprints(authorization: str | None = Header(None)) -> List[str]: - _check_token(authorization) - assert _pm is not None - return _pm.fingerprint_manager.list_fingerprints() +def list_fingerprints( + request: Request, authorization: str | None = Header(None) +) -> List[str]: + _check_token(request, authorization) + pm = _get_pm(request) + return pm.fingerprint_manager.list_fingerprints() @app.post("/api/v1/fingerprint") -def add_fingerprint(authorization: str | None = Header(None)) -> dict[str, str]: +def add_fingerprint( + request: Request, authorization: str | None = Header(None) +) -> dict[str, str]: """Create a new seed profile.""" - _check_token(authorization) - assert _pm is not None - _pm.add_new_fingerprint() + _check_token(request, authorization) + pm = _get_pm(request) + pm.add_new_fingerprint() return {"status": "ok"} @app.delete("/api/v1/fingerprint/{fingerprint}") def remove_fingerprint( - fingerprint: str, authorization: str | None = Header(None) + request: Request, fingerprint: str, authorization: str | None = Header(None) ) -> dict[str, str]: """Remove a seed profile.""" - _check_token(authorization) - assert _pm is not None - _pm.fingerprint_manager.remove_fingerprint(fingerprint) + _check_token(request, authorization) + pm = _get_pm(request) + pm.fingerprint_manager.remove_fingerprint(fingerprint) return {"status": "deleted"} @app.post("/api/v1/fingerprint/select") def select_fingerprint( - data: dict, authorization: str | None = Header(None) + request: Request, data: dict, authorization: str | None = Header(None) ) -> dict[str, str]: """Switch the active seed profile.""" - _check_token(authorization) - assert _pm is not None + _check_token(request, authorization) + pm = _get_pm(request) fp = data.get("fingerprint") + if not fp: raise HTTPException(status_code=400, detail="Missing fingerprint") - _pm.select_fingerprint(fp) + pm.select_fingerprint(fp) return {"status": "ok"} @app.get("/api/v1/totp/export") -def export_totp(authorization: str | None = Header(None)) -> dict: +def export_totp( + request: Request, + authorization: str | None = Header(None), + password: str | None = Header(None, alias="X-SeedPass-Password"), +) -> dict: """Return all stored TOTP entries in JSON format.""" - _check_token(authorization) - assert _pm is not None - return _pm.entry_manager.export_totp_entries(_pm.parent_seed) + _check_token(request, authorization) + _require_password(request, password) + pm = _get_pm(request) + key = getattr(pm, "KEY_TOTP_DET", None) or getattr(pm, "parent_seed", None) + return pm.entry_manager.export_totp_entries(key) @app.get("/api/v1/totp") -def get_totp_codes(authorization: str | None = Header(None)) -> dict: +def get_totp_codes( + request: Request, + authorization: str | None = Header(None), + password: str | None = Header(None, alias="X-SeedPass-Password"), +) -> dict: """Return active TOTP codes with remaining seconds.""" - _check_token(authorization) - assert _pm is not None - entries = _pm.entry_manager.list_entries( - filter_kind=EntryType.TOTP.value, include_archived=False + _check_token(request, authorization) + _require_password(request, password) + pm = _get_pm(request) + entries = pm.entry_manager.list_entries( + filter_kinds=[EntryType.TOTP.value], include_archived=False ) codes = [] for idx, label, _u, _url, _arch in entries: - code = _pm.entry_manager.get_totp_code(idx, _pm.parent_seed) - rem = _pm.entry_manager.get_totp_time_remaining(idx) + key = getattr(pm, "KEY_TOTP_DET", None) or getattr(pm, "parent_seed", None) + code = pm.entry_manager.get_totp_code(idx, key) + + rem = pm.entry_manager.get_totp_time_remaining(idx) + codes.append( {"id": idx, "label": label, "code": code, "seconds_remaining": rem} ) @@ -393,132 +494,138 @@ def get_totp_codes(authorization: str | None = Header(None)) -> dict: @app.get("/api/v1/stats") -def get_profile_stats(authorization: str | None = Header(None)) -> dict: +def get_profile_stats( + request: Request, authorization: str | None = Header(None) +) -> dict: """Return statistics about the active seed profile.""" - _check_token(authorization) - assert _pm is not None - return _pm.get_profile_stats() + _check_token(request, authorization) + pm = _get_pm(request) + return pm.get_profile_stats() @app.get("/api/v1/notifications") -def get_notifications(authorization: str | None = Header(None)) -> List[dict]: +def get_notifications( + request: Request, authorization: str | None = Header(None) +) -> List[dict]: """Return and clear queued notifications.""" - _check_token(authorization) - assert _pm is not None + _check_token(request, authorization) + pm = _get_pm(request) notes = [] while True: try: - note = _pm.notifications.get_nowait() + note = pm.notifications.get_nowait() except queue.Empty: break notes.append({"level": note.level, "message": note.message}) return notes -@app.get("/api/v1/parent-seed") -def get_parent_seed( - authorization: str | None = Header(None), file: str | None = None -) -> dict: - """Return the parent seed or save it as an encrypted backup.""" - _check_token(authorization) - assert _pm is not None - if file: - path = Path(file) - _pm.encryption_manager.encrypt_and_save_file( - _pm.parent_seed.encode("utf-8"), path - ) - return {"status": "saved", "path": str(path)} - return {"seed": _pm.parent_seed} - - @app.get("/api/v1/nostr/pubkey") -def get_nostr_pubkey(authorization: str | None = Header(None)) -> Any: - _check_token(authorization) - assert _pm is not None - return {"npub": _pm.nostr_client.key_manager.get_npub()} +def get_nostr_pubkey(request: Request, authorization: str | None = Header(None)) -> Any: + _check_token(request, authorization) + pm = _get_pm(request) + return {"npub": pm.nostr_client.key_manager.get_npub()} @app.get("/api/v1/relays") -def list_relays(authorization: str | None = Header(None)) -> dict: +def list_relays(request: Request, authorization: str | None = Header(None)) -> dict: """Return the configured Nostr relays.""" - _check_token(authorization) - assert _pm is not None - cfg = _pm.config_manager.load_config(require_pin=False) + _check_token(request, authorization) + pm = _get_pm(request) + cfg = pm.config_manager.load_config(require_pin=False) return {"relays": cfg.get("relays", [])} @app.post("/api/v1/relays") -def add_relay(data: dict, authorization: str | None = Header(None)) -> dict[str, str]: +def add_relay( + request: Request, data: dict, authorization: str | None = Header(None) +) -> dict[str, str]: """Add a relay URL to the configuration.""" - _check_token(authorization) - assert _pm is not None + _check_token(request, authorization) + pm = _get_pm(request) url = data.get("url") + if not url: raise HTTPException(status_code=400, detail="Missing url") - cfg = _pm.config_manager.load_config(require_pin=False) + cfg = pm.config_manager.load_config(require_pin=False) relays = cfg.get("relays", []) + if url in relays: raise HTTPException(status_code=400, detail="Relay already present") relays.append(url) - _pm.config_manager.set_relays(relays, require_pin=False) - _reload_relays(relays) + pm.config_manager.set_relays(relays, require_pin=False) + _reload_relays(request, relays) return {"status": "ok"} @app.delete("/api/v1/relays/{idx}") -def remove_relay(idx: int, authorization: str | None = Header(None)) -> dict[str, str]: +def remove_relay( + request: Request, idx: int, authorization: str | None = Header(None) +) -> dict[str, str]: """Remove a relay by its index (1-based).""" - _check_token(authorization) - assert _pm is not None - cfg = _pm.config_manager.load_config(require_pin=False) + _check_token(request, authorization) + pm = _get_pm(request) + cfg = pm.config_manager.load_config(require_pin=False) relays = cfg.get("relays", []) + if not (1 <= idx <= len(relays)): raise HTTPException(status_code=400, detail="Invalid index") if len(relays) == 1: raise HTTPException(status_code=400, detail="At least one relay required") relays.pop(idx - 1) - _pm.config_manager.set_relays(relays, require_pin=False) - _reload_relays(relays) + pm.config_manager.set_relays(relays, require_pin=False) + _reload_relays(request, relays) return {"status": "ok"} @app.post("/api/v1/relays/reset") -def reset_relays(authorization: str | None = Header(None)) -> dict[str, str]: +def reset_relays( + request: Request, authorization: str | None = Header(None) +) -> dict[str, str]: """Reset relay list to defaults.""" - _check_token(authorization) - assert _pm is not None + _check_token(request, authorization) + pm = _get_pm(request) from nostr.client import DEFAULT_RELAYS relays = list(DEFAULT_RELAYS) - _pm.config_manager.set_relays(relays, require_pin=False) - _reload_relays(relays) + pm.config_manager.set_relays(relays, require_pin=False) + _reload_relays(request, relays) return {"status": "ok"} @app.post("/api/v1/checksum/verify") -def verify_checksum(authorization: str | None = Header(None)) -> dict[str, str]: +def verify_checksum( + request: Request, authorization: str | None = Header(None) +) -> dict[str, str]: """Verify the SeedPass script checksum.""" - _check_token(authorization) - assert _pm is not None - _pm.handle_verify_checksum() + _check_token(request, authorization) + pm = _get_pm(request) + pm.handle_verify_checksum() return {"status": "ok"} @app.post("/api/v1/checksum/update") -def update_checksum(authorization: str | None = Header(None)) -> dict[str, str]: +def update_checksum( + request: Request, authorization: str | None = Header(None) +) -> dict[str, str]: """Regenerate the script checksum file.""" - _check_token(authorization) - assert _pm is not None - _pm.handle_update_script_checksum() + _check_token(request, authorization) + pm = _get_pm(request) + pm.handle_update_script_checksum() return {"status": "ok"} @app.post("/api/v1/vault/export") -def export_vault(authorization: str | None = Header(None)): +def export_vault( + request: Request, + authorization: str | None = Header(None), + password: str | None = Header(None, alias="X-SeedPass-Password"), +): """Export the vault and return the encrypted file.""" - _check_token(authorization) - assert _pm is not None - path = _pm.handle_export_database() + _check_token(request, authorization) + _require_password(request, password) + pm = _get_pm(request) + path = pm.handle_export_database() if path is None: raise HTTPException(status_code=500, detail="Export failed") data = Path(path).read_bytes() @@ -530,75 +637,96 @@ async def import_vault( request: Request, authorization: str | None = Header(None) ) -> dict[str, str]: """Import a vault backup from a file upload or a server path.""" - _check_token(authorization) - assert _pm is not None + _check_token(request, authorization) + pm = _get_pm(request) ctype = request.headers.get("content-type", "") + if ctype.startswith("multipart/form-data"): form = await request.form() file = form.get("file") + if file is None: raise HTTPException(status_code=400, detail="Missing file") - data = await file.read() - with tempfile.NamedTemporaryFile(delete=False, suffix=".json.enc") as tmp: + data = await file.read(_MAX_IMPORT_BYTES + 1) + if len(data) > _MAX_IMPORT_BYTES: + raise HTTPException( + status_code=413, + detail=f"Uploaded file exceeds max size of {_MAX_IMPORT_BYTES} bytes", + ) + with tempfile.NamedTemporaryFile(delete=False) as tmp: tmp.write(data) tmp_path = Path(tmp.name) try: - _pm.handle_import_database(tmp_path) + pm.handle_import_database(tmp_path) finally: os.unlink(tmp_path) else: body = await request.json() - path = body.get("path") - if not path: + path_str = body.get("path") + + if not path_str: raise HTTPException(status_code=400, detail="Missing file or path") - p = Path(path) - if p.is_absolute() or ".." in p.parts: - raise HTTPException(status_code=400, detail="Invalid path") - full_path = _pm.fingerprint_dir / p - _pm.handle_import_database(full_path) - _pm.sync_vault() + + path = _validate_encryption_path(request, Path(path_str)) + if not str(path).endswith(".json.enc"): + raise HTTPException( + status_code=400, + detail="Selected file must be a '.json.enc' backup", + ) + + pm.handle_import_database(path) + pm.sync_vault() return {"status": "ok"} @app.post("/api/v1/vault/backup-parent-seed") def backup_parent_seed( - data: dict | None = None, authorization: str | None = Header(None) + request: Request, + data: dict, + authorization: str | None = Header(None), + password: str | None = Header(None, alias="X-SeedPass-Password"), ) -> dict[str, str]: - """Backup and reveal the parent seed.""" - _check_token(authorization) - assert _pm is not None - path = None - if data is not None: - p = data.get("path") - if p: - # Prevent directory traversal - if "/" in p or "\\" in p or ".." in p: - raise HTTPException(status_code=400, detail="Invalid filename") - path = Path(p) - _pm.handle_backup_reveal_parent_seed(path) - return {"status": "ok"} + """Create an encrypted backup of the parent seed after confirmation.""" + _check_token(request, authorization) + _require_password(request, password) + pm = _get_pm(request) + + if not data.get("confirm"): + + raise HTTPException(status_code=400, detail="Confirmation required") + + path_str = data.get("path") + + if not path_str: + raise HTTPException(status_code=400, detail="Missing path") + path = Path(path_str) + _validate_encryption_path(request, path) + pm.encryption_manager.encrypt_and_save_file(pm.parent_seed.encode("utf-8"), path) + return {"status": "saved", "path": str(path)} @app.post("/api/v1/change-password") def change_password( - data: dict, authorization: str | None = Header(None) + request: Request, data: dict, authorization: str | None = Header(None) ) -> dict[str, str]: """Change the master password for the active profile.""" - _check_token(authorization) - assert _pm is not None - _pm.change_password(data.get("old", ""), data.get("new", "")) + _check_token(request, authorization) + pm = _get_pm(request) + pm.change_password(data.get("old", ""), data.get("new", "")) + return {"status": "ok"} @app.post("/api/v1/password") def generate_password( - data: dict, authorization: str | None = Header(None) + request: Request, data: dict, authorization: str | None = Header(None) ) -> dict[str, str]: """Generate a password using optional policy overrides.""" - _check_token(authorization) - assert _pm is not None + _check_token(request, authorization) + pm = _get_pm(request) length = int(data.get("length", 12)) + policy_keys = [ "include_special_chars", "allowed_special_chars", @@ -610,22 +738,28 @@ def generate_password( "min_special", ] kwargs = {k: data.get(k) for k in policy_keys if data.get(k) is not None} - util = UtilityService(_pm) + + util = UtilityService(pm) password = util.generate_password(length, **kwargs) return {"password": password} @app.post("/api/v1/vault/lock") -def lock_vault(authorization: str | None = Header(None)) -> dict[str, str]: +def lock_vault( + request: Request, authorization: str | None = Header(None) +) -> dict[str, str]: """Lock the vault and clear sensitive data from memory.""" - _check_token(authorization) - assert _pm is not None - _pm.lock_vault() + _check_token(request, authorization) + pm = _get_pm(request) + pm.lock_vault() return {"status": "locked"} @app.post("/api/v1/shutdown") -async def shutdown_server(authorization: str | None = Header(None)) -> dict[str, str]: - _check_token(authorization) +async def shutdown_server( + request: Request, authorization: str | None = Header(None) +) -> dict[str, str]: + _check_token(request, authorization) asyncio.get_event_loop().call_soon(sys.exit, 0) + return {"status": "shutting down"} diff --git a/src/seedpass/cli.py b/src/seedpass/cli.py deleted file mode 100644 index a3f03d97..00000000 --- a/src/seedpass/cli.py +++ /dev/null @@ -1,886 +0,0 @@ -from pathlib import Path -from typing import Optional, List -import json -import os - -import typer -import sys - -from seedpass.core.manager import PasswordManager -from seedpass.core.entry_types import EntryType -from seedpass.core.api import ( - VaultService, - ProfileService, - SyncService, - EntryService, - ConfigService, - UtilityService, - NostrService, - ChangePasswordRequest, - UnlockRequest, - BackupParentSeedRequest, - ProfileSwitchRequest, - ProfileRemoveRequest, -) -import uvicorn -from . import api as api_module - -import importlib -import importlib.util -import subprocess - -app = typer.Typer( - help="SeedPass command line interface", - invoke_without_command=True, -) - -# Global option shared across all commands -fingerprint_option = typer.Option( - None, - "--fingerprint", - "-f", - help="Specify which seed profile to use", -) - -# Sub command groups -entry_app = typer.Typer(help="Manage individual entries") -vault_app = typer.Typer(help="Manage the entire vault") -nostr_app = typer.Typer(help="Interact with Nostr relays") -config_app = typer.Typer(help="Get or set configuration values") -fingerprint_app = typer.Typer(help="Manage seed profiles") -util_app = typer.Typer(help="Utility commands") -api_app = typer.Typer(help="Run the API server") - -app.add_typer(entry_app, name="entry") -app.add_typer(vault_app, name="vault") -app.add_typer(nostr_app, name="nostr") -app.add_typer(config_app, name="config") -app.add_typer(fingerprint_app, name="fingerprint") -app.add_typer(util_app, name="util") -app.add_typer(api_app, name="api") - - -def _get_pm(ctx: typer.Context) -> PasswordManager: - """Return a PasswordManager optionally selecting a fingerprint.""" - fp = ctx.obj.get("fingerprint") - if fp is None: - pm = PasswordManager() - else: - pm = PasswordManager(fingerprint=fp) - return pm - - -def _get_services( - ctx: typer.Context, -) -> tuple[VaultService, ProfileService, SyncService]: - """Return service layer instances for the current context.""" - - pm = _get_pm(ctx) - return VaultService(pm), ProfileService(pm), SyncService(pm) - - -def _get_entry_service(ctx: typer.Context) -> EntryService: - pm = _get_pm(ctx) - return EntryService(pm) - - -def _get_config_service(ctx: typer.Context) -> ConfigService: - pm = _get_pm(ctx) - return ConfigService(pm) - - -def _get_util_service(ctx: typer.Context) -> UtilityService: - pm = _get_pm(ctx) - return UtilityService(pm) - - -def _get_nostr_service(ctx: typer.Context) -> NostrService: - pm = _get_pm(ctx) - return NostrService(pm) - - -def _gui_backend_available() -> bool: - """Return True if a platform-specific BeeWare backend is installed.""" - for pkg in ("toga_gtk", "toga_winforms", "toga_cocoa"): - if importlib.util.find_spec(pkg) is not None: - return True - return False - - -@app.callback(invoke_without_command=True) -def main(ctx: typer.Context, fingerprint: Optional[str] = fingerprint_option) -> None: - """SeedPass CLI entry point. - - When called without a subcommand this launches the interactive TUI. - """ - ctx.obj = {"fingerprint": fingerprint} - if ctx.invoked_subcommand is None: - tui = importlib.import_module("main") - raise typer.Exit(tui.main(fingerprint=fingerprint)) - - -@entry_app.command("list") -def entry_list( - ctx: typer.Context, - sort: str = typer.Option( - "index", "--sort", help="Sort by 'index', 'label', or 'updated'" - ), - kind: Optional[str] = typer.Option(None, "--kind", help="Filter by entry type"), - archived: bool = typer.Option(False, "--archived", help="Include archived"), -) -> None: - """List entries in the vault.""" - service = _get_entry_service(ctx) - entries = service.list_entries( - sort_by=sort, filter_kind=kind, include_archived=archived - ) - for idx, label, username, url, is_archived in entries: - line = f"{idx}: {label}" - if username: - line += f" ({username})" - if url: - line += f" {url}" - if is_archived: - line += " [archived]" - typer.echo(line) - - -@entry_app.command("search") -def entry_search( - ctx: typer.Context, - query: str, - kind: List[str] = typer.Option( - None, - "--kind", - "-k", - help="Filter by entry kinds (can be repeated)", - ), -) -> None: - """Search entries.""" - service = _get_entry_service(ctx) - kinds = list(kind) if kind else None - results = service.search_entries(query, kinds=kinds) - if not results: - typer.echo("No matching entries found") - return - for idx, label, username, url, _arch, etype in results: - line = f"{idx}: {etype.value.replace('_', ' ').title()} - {label}" - if username: - line += f" ({username})" - if url: - line += f" {url}" - typer.echo(line) - - -@entry_app.command("get") -def entry_get(ctx: typer.Context, query: str) -> None: - """Retrieve a single entry's secret.""" - service = _get_entry_service(ctx) - matches = service.search_entries(query) - if len(matches) == 0: - typer.echo("No matching entries found") - raise typer.Exit(code=1) - if len(matches) > 1: - typer.echo("Matches:") - for idx, label, username, _url, _arch, etype in matches: - name = f"{idx}: {etype.value.replace('_', ' ').title()} - {label}" - if username: - name += f" ({username})" - typer.echo(name) - raise typer.Exit(code=1) - - index = matches[0][0] - entry = service.retrieve_entry(index) - etype = entry.get("type", entry.get("kind")) - if etype == EntryType.PASSWORD.value: - length = int(entry.get("length", 12)) - password = service.generate_password(length, index) - typer.echo(password) - elif etype == EntryType.TOTP.value: - code = service.get_totp_code(index) - typer.echo(code) - else: - typer.echo("Unsupported entry type") - raise typer.Exit(code=1) - - -@entry_app.command("add") -def entry_add( - ctx: typer.Context, - label: str, - length: int = typer.Option(12, "--length"), - username: Optional[str] = typer.Option(None, "--username"), - url: Optional[str] = typer.Option(None, "--url"), - no_special: bool = typer.Option( - False, "--no-special", help="Exclude special characters", is_flag=True - ), - allowed_special_chars: Optional[str] = typer.Option( - None, "--allowed-special-chars", help="Explicit set of special characters" - ), - special_mode: Optional[str] = typer.Option( - None, - "--special-mode", - help="Special character mode", - ), - exclude_ambiguous: bool = typer.Option( - False, - "--exclude-ambiguous", - help="Exclude ambiguous characters", - is_flag=True, - ), - min_uppercase: Optional[int] = typer.Option(None, "--min-uppercase"), - min_lowercase: Optional[int] = typer.Option(None, "--min-lowercase"), - min_digits: Optional[int] = typer.Option(None, "--min-digits"), - min_special: Optional[int] = typer.Option(None, "--min-special"), -) -> None: - """Add a new password entry and output its index.""" - service = _get_entry_service(ctx) - kwargs = {} - if no_special: - kwargs["include_special_chars"] = False - if allowed_special_chars is not None: - kwargs["allowed_special_chars"] = allowed_special_chars - if special_mode is not None: - kwargs["special_mode"] = special_mode - if exclude_ambiguous: - kwargs["exclude_ambiguous"] = True - if min_uppercase is not None: - kwargs["min_uppercase"] = min_uppercase - if min_lowercase is not None: - kwargs["min_lowercase"] = min_lowercase - if min_digits is not None: - kwargs["min_digits"] = min_digits - if min_special is not None: - kwargs["min_special"] = min_special - - index = service.add_entry(label, length, username, url, **kwargs) - typer.echo(str(index)) - - -@entry_app.command("add-totp") -def entry_add_totp( - ctx: typer.Context, - label: str, - index: Optional[int] = typer.Option(None, "--index", help="Derivation index"), - secret: Optional[str] = typer.Option(None, "--secret", help="Import secret"), - period: int = typer.Option(30, "--period", help="TOTP period in seconds"), - digits: int = typer.Option(6, "--digits", help="Number of TOTP digits"), -) -> None: - """Add a TOTP entry and output the otpauth URI.""" - service = _get_entry_service(ctx) - uri = service.add_totp( - label, - index=index, - secret=secret, - period=period, - digits=digits, - ) - typer.echo(uri) - - -@entry_app.command("add-ssh") -def entry_add_ssh( - ctx: typer.Context, - label: str, - index: Optional[int] = typer.Option(None, "--index", help="Derivation index"), - notes: str = typer.Option("", "--notes", help="Entry notes"), -) -> None: - """Add an SSH key entry and output its index.""" - service = _get_entry_service(ctx) - idx = service.add_ssh_key( - label, - index=index, - notes=notes, - ) - typer.echo(str(idx)) - - -@entry_app.command("add-pgp") -def entry_add_pgp( - ctx: typer.Context, - label: str, - index: Optional[int] = typer.Option(None, "--index", help="Derivation index"), - key_type: str = typer.Option("ed25519", "--key-type", help="Key type"), - user_id: str = typer.Option("", "--user-id", help="User ID"), - notes: str = typer.Option("", "--notes", help="Entry notes"), -) -> None: - """Add a PGP key entry and output its index.""" - service = _get_entry_service(ctx) - idx = service.add_pgp_key( - label, - index=index, - key_type=key_type, - user_id=user_id, - notes=notes, - ) - typer.echo(str(idx)) - - -@entry_app.command("add-nostr") -def entry_add_nostr( - ctx: typer.Context, - label: str, - index: Optional[int] = typer.Option(None, "--index", help="Derivation index"), - notes: str = typer.Option("", "--notes", help="Entry notes"), -) -> None: - """Add a Nostr key entry and output its index.""" - service = _get_entry_service(ctx) - idx = service.add_nostr_key( - label, - index=index, - notes=notes, - ) - typer.echo(str(idx)) - - -@entry_app.command("add-seed") -def entry_add_seed( - ctx: typer.Context, - label: str, - index: Optional[int] = typer.Option(None, "--index", help="Derivation index"), - words: int = typer.Option(24, "--words", help="Word count"), - notes: str = typer.Option("", "--notes", help="Entry notes"), -) -> None: - """Add a derived seed phrase entry and output its index.""" - service = _get_entry_service(ctx) - idx = service.add_seed( - label, - index=index, - words=words, - notes=notes, - ) - typer.echo(str(idx)) - - -@entry_app.command("add-key-value") -def entry_add_key_value( - ctx: typer.Context, - label: str, - key: str = typer.Option(..., "--key", help="Key name"), - value: str = typer.Option(..., "--value", help="Stored value"), - notes: str = typer.Option("", "--notes", help="Entry notes"), -) -> None: - """Add a key/value entry and output its index.""" - service = _get_entry_service(ctx) - idx = service.add_key_value(label, key, value, notes=notes) - typer.echo(str(idx)) - - -@entry_app.command("add-managed-account") -def entry_add_managed_account( - ctx: typer.Context, - label: str, - index: Optional[int] = typer.Option(None, "--index", help="Derivation index"), - notes: str = typer.Option("", "--notes", help="Entry notes"), -) -> None: - """Add a managed account seed entry and output its index.""" - service = _get_entry_service(ctx) - idx = service.add_managed_account( - label, - index=index, - notes=notes, - ) - typer.echo(str(idx)) - - -@entry_app.command("modify") -def entry_modify( - ctx: typer.Context, - entry_id: int, - label: Optional[str] = typer.Option(None, "--label"), - username: Optional[str] = typer.Option(None, "--username"), - url: Optional[str] = typer.Option(None, "--url"), - notes: Optional[str] = typer.Option(None, "--notes"), - period: Optional[int] = typer.Option( - None, "--period", help="TOTP period in seconds" - ), - digits: Optional[int] = typer.Option(None, "--digits", help="TOTP digits"), - key: Optional[str] = typer.Option(None, "--key", help="New key"), - value: Optional[str] = typer.Option(None, "--value", help="New value"), -) -> None: - """Modify an existing entry.""" - service = _get_entry_service(ctx) - try: - service.modify_entry( - entry_id, - username=username, - url=url, - notes=notes, - label=label, - period=period, - digits=digits, - key=key, - value=value, - ) - except ValueError as e: - typer.echo(str(e)) - sys.stdout.flush() - raise typer.Exit(code=1) - - -@entry_app.command("archive") -def entry_archive(ctx: typer.Context, entry_id: int) -> None: - """Archive an entry.""" - service = _get_entry_service(ctx) - service.archive_entry(entry_id) - typer.echo(str(entry_id)) - - -@entry_app.command("unarchive") -def entry_unarchive(ctx: typer.Context, entry_id: int) -> None: - """Restore an archived entry.""" - service = _get_entry_service(ctx) - service.restore_entry(entry_id) - typer.echo(str(entry_id)) - - -@entry_app.command("totp-codes") -def entry_totp_codes(ctx: typer.Context) -> None: - """Display all current TOTP codes.""" - service = _get_entry_service(ctx) - service.display_totp_codes() - - -@entry_app.command("export-totp") -def entry_export_totp( - ctx: typer.Context, file: str = typer.Option(..., help="Output file") -) -> None: - """Export all TOTP secrets to a JSON file.""" - service = _get_entry_service(ctx) - data = service.export_totp_entries() - Path(file).write_text(json.dumps(data, indent=2)) - typer.echo(str(file)) - - -@vault_app.command("export") -def vault_export( - ctx: typer.Context, file: str = typer.Option(..., help="Output file") -) -> None: - """Export the vault profile to an encrypted file.""" - vault_service, _profile, _sync = _get_services(ctx) - data = vault_service.export_profile() - Path(file).write_bytes(data) - typer.echo(str(file)) - - -@vault_app.command("import") -def vault_import( - ctx: typer.Context, file: str = typer.Option(..., help="Input file") -) -> None: - """Import a vault profile from an encrypted file.""" - vault_service, _profile, _sync = _get_services(ctx) - data = Path(file).read_bytes() - vault_service.import_profile(data) - typer.echo(str(file)) - - -@vault_app.command("change-password") -def vault_change_password(ctx: typer.Context) -> None: - """Change the master password used for encryption.""" - vault_service, _profile, _sync = _get_services(ctx) - old_pw = typer.prompt("Current password", hide_input=True) - new_pw = typer.prompt("New password", hide_input=True, confirmation_prompt=True) - try: - vault_service.change_password( - ChangePasswordRequest(old_password=old_pw, new_password=new_pw) - ) - except Exception as exc: # pragma: no cover - pass through errors - typer.echo(f"Error: {exc}") - raise typer.Exit(code=1) - typer.echo("Password updated") - - -@vault_app.command("unlock") -def vault_unlock(ctx: typer.Context) -> None: - """Unlock the vault for the active profile.""" - vault_service, _profile, _sync = _get_services(ctx) - password = typer.prompt("Master password", hide_input=True) - try: - resp = vault_service.unlock(UnlockRequest(password=password)) - except Exception as exc: # pragma: no cover - pass through errors - typer.echo(f"Error: {exc}") - raise typer.Exit(code=1) - typer.echo(f"Unlocked in {resp.duration:.2f}s") - - -@vault_app.command("lock") -def vault_lock(ctx: typer.Context) -> None: - """Lock the vault and clear sensitive data from memory.""" - vault_service, _profile, _sync = _get_services(ctx) - vault_service.lock() - typer.echo("locked") - - -@app.command("lock") -def root_lock(ctx: typer.Context) -> None: - """Lock the vault for the active profile.""" - vault_service, _profile, _sync = _get_services(ctx) - vault_service.lock() - typer.echo("locked") - - -@vault_app.command("stats") -def vault_stats(ctx: typer.Context) -> None: - """Display statistics about the current seed profile.""" - vault_service, _profile, _sync = _get_services(ctx) - stats = vault_service.stats() - typer.echo(json.dumps(stats, indent=2)) - - -@vault_app.command("reveal-parent-seed") -def vault_reveal_parent_seed( - ctx: typer.Context, - file: Optional[str] = typer.Option( - None, "--file", help="Save encrypted seed to this path" - ), -) -> None: - """Display the parent seed and optionally write an encrypted backup file.""" - vault_service, _profile, _sync = _get_services(ctx) - password = typer.prompt("Master password", hide_input=True) - vault_service.backup_parent_seed( - BackupParentSeedRequest(path=Path(file) if file else None, password=password) - ) - - -@nostr_app.command("sync") -def nostr_sync(ctx: typer.Context) -> None: - """Sync with configured Nostr relays.""" - _vault, _profile, sync_service = _get_services(ctx) - model = sync_service.sync() - if model: - typer.echo("Event IDs:") - typer.echo(f"- manifest: {model.manifest_id}") - for cid in model.chunk_ids: - typer.echo(f"- chunk: {cid}") - for did in model.delta_ids: - typer.echo(f"- delta: {did}") - else: - typer.echo("Error: Failed to sync vault") - - -@nostr_app.command("get-pubkey") -def nostr_get_pubkey(ctx: typer.Context) -> None: - """Display the active profile's npub.""" - service = _get_nostr_service(ctx) - npub = service.get_pubkey() - typer.echo(npub) - - -@nostr_app.command("list-relays") -def nostr_list_relays(ctx: typer.Context) -> None: - """Display configured Nostr relays.""" - service = _get_nostr_service(ctx) - relays = service.list_relays() - for i, r in enumerate(relays, 1): - typer.echo(f"{i}: {r}") - - -@nostr_app.command("add-relay") -def nostr_add_relay(ctx: typer.Context, url: str) -> None: - """Add a relay URL.""" - service = _get_nostr_service(ctx) - try: - service.add_relay(url) - except Exception as exc: # pragma: no cover - pass through errors - typer.echo(f"Error: {exc}") - raise typer.Exit(code=1) - typer.echo("Added") - - -@nostr_app.command("remove-relay") -def nostr_remove_relay(ctx: typer.Context, idx: int) -> None: - """Remove a relay by index (1-based).""" - service = _get_nostr_service(ctx) - try: - service.remove_relay(idx) - except Exception as exc: # pragma: no cover - pass through errors - typer.echo(f"Error: {exc}") - raise typer.Exit(code=1) - typer.echo("Removed") - - -@config_app.command("get") -def config_get(ctx: typer.Context, key: str) -> None: - """Get a configuration value.""" - service = _get_config_service(ctx) - value = service.get(key) - if value is None: - typer.echo("Key not found") - else: - typer.echo(str(value)) - - -@config_app.command("set") -def config_set(ctx: typer.Context, key: str, value: str) -> None: - """Set a configuration value.""" - service = _get_config_service(ctx) - - try: - val = ( - [r.strip() for r in value.split(",") if r.strip()] - if key == "relays" - else value - ) - service.set(key, val) - except KeyError: - typer.echo("Unknown key") - raise typer.Exit(code=1) - except Exception as exc: # pragma: no cover - pass through errors - typer.echo(f"Error: {exc}") - raise typer.Exit(code=1) - - typer.echo("Updated") - - -@config_app.command("toggle-secret-mode") -def config_toggle_secret_mode(ctx: typer.Context) -> None: - """Interactively enable or disable secret mode. - - When enabled, newly generated and retrieved passwords are copied to the - clipboard instead of printed to the screen. - """ - service = _get_config_service(ctx) - try: - enabled = service.get_secret_mode_enabled() - delay = service.get_clipboard_clear_delay() - except Exception as exc: # pragma: no cover - pass through errors - typer.echo(f"Error loading settings: {exc}") - raise typer.Exit(code=1) - - typer.echo(f"Secret mode is currently {'ON' if enabled else 'OFF'}") - choice = ( - typer.prompt( - "Enable secret mode? (y/n, blank to keep)", default="", show_default=False - ) - .strip() - .lower() - ) - if choice in ("y", "yes"): - enabled = True - elif choice in ("n", "no"): - enabled = False - - inp = typer.prompt( - f"Clipboard clear delay in seconds [{delay}]", default="", show_default=False - ).strip() - if inp: - try: - delay = int(inp) - if delay <= 0: - typer.echo("Delay must be positive") - raise typer.Exit(code=1) - except ValueError: - typer.echo("Invalid number") - raise typer.Exit(code=1) - - try: - service.set_secret_mode(enabled, delay) - except Exception as exc: # pragma: no cover - pass through errors - typer.echo(f"Error: {exc}") - raise typer.Exit(code=1) - - status = "enabled" if enabled else "disabled" - typer.echo(f"Secret mode {status}.") - - -@config_app.command("toggle-offline") -def config_toggle_offline(ctx: typer.Context) -> None: - """Enable or disable offline mode.""" - service = _get_config_service(ctx) - try: - enabled = service.get_offline_mode() - except Exception as exc: # pragma: no cover - pass through errors - typer.echo(f"Error loading settings: {exc}") - raise typer.Exit(code=1) - - typer.echo(f"Offline mode is currently {'ON' if enabled else 'OFF'}") - choice = ( - typer.prompt( - "Enable offline mode? (y/n, blank to keep)", default="", show_default=False - ) - .strip() - .lower() - ) - if choice in ("y", "yes"): - enabled = True - elif choice in ("n", "no"): - enabled = False - - try: - service.set_offline_mode(enabled) - except Exception as exc: # pragma: no cover - pass through errors - typer.echo(f"Error: {exc}") - raise typer.Exit(code=1) - - status = "enabled" if enabled else "disabled" - typer.echo(f"Offline mode {status}.") - - -@fingerprint_app.command("list") -def fingerprint_list(ctx: typer.Context) -> None: - """List available seed profiles.""" - _vault, profile_service, _sync = _get_services(ctx) - for fp in profile_service.list_profiles(): - typer.echo(fp) - - -@fingerprint_app.command("add") -def fingerprint_add(ctx: typer.Context) -> None: - """Create a new seed profile.""" - _vault, profile_service, _sync = _get_services(ctx) - profile_service.add_profile() - - -@fingerprint_app.command("remove") -def fingerprint_remove(ctx: typer.Context, fingerprint: str) -> None: - """Remove a seed profile.""" - _vault, profile_service, _sync = _get_services(ctx) - profile_service.remove_profile(ProfileRemoveRequest(fingerprint=fingerprint)) - - -@fingerprint_app.command("switch") -def fingerprint_switch(ctx: typer.Context, fingerprint: str) -> None: - """Switch to another seed profile.""" - _vault, profile_service, _sync = _get_services(ctx) - password = typer.prompt("Master password", hide_input=True) - profile_service.switch_profile( - ProfileSwitchRequest(fingerprint=fingerprint, password=password) - ) - - -@util_app.command("generate-password") -def generate_password( - ctx: typer.Context, - length: int = 24, - no_special: bool = typer.Option( - False, "--no-special", help="Exclude special characters", is_flag=True - ), - allowed_special_chars: Optional[str] = typer.Option( - None, "--allowed-special-chars", help="Explicit set of special characters" - ), - special_mode: Optional[str] = typer.Option( - None, - "--special-mode", - help="Special character mode", - ), - exclude_ambiguous: bool = typer.Option( - False, - "--exclude-ambiguous", - help="Exclude ambiguous characters", - is_flag=True, - ), - min_uppercase: Optional[int] = typer.Option(None, "--min-uppercase"), - min_lowercase: Optional[int] = typer.Option(None, "--min-lowercase"), - min_digits: Optional[int] = typer.Option(None, "--min-digits"), - min_special: Optional[int] = typer.Option(None, "--min-special"), -) -> None: - """Generate a strong password.""" - service = _get_util_service(ctx) - kwargs = {} - if no_special: - kwargs["include_special_chars"] = False - if allowed_special_chars is not None: - kwargs["allowed_special_chars"] = allowed_special_chars - if special_mode is not None: - kwargs["special_mode"] = special_mode - if exclude_ambiguous: - kwargs["exclude_ambiguous"] = True - if min_uppercase is not None: - kwargs["min_uppercase"] = min_uppercase - if min_lowercase is not None: - kwargs["min_lowercase"] = min_lowercase - if min_digits is not None: - kwargs["min_digits"] = min_digits - if min_special is not None: - kwargs["min_special"] = min_special - - password = service.generate_password(length, **kwargs) - typer.echo(password) - - -@util_app.command("verify-checksum") -def verify_checksum(ctx: typer.Context) -> None: - """Verify the SeedPass script checksum.""" - service = _get_util_service(ctx) - service.verify_checksum() - - -@util_app.command("update-checksum") -def update_checksum(ctx: typer.Context) -> None: - """Regenerate the script checksum file.""" - service = _get_util_service(ctx) - service.update_checksum() - - -@api_app.command("start") -def api_start( - ctx: typer.Context, - host: str = "127.0.0.1", - port: int = 8000, - token: Optional[str] = typer.Option(None, "--token", help="API token"), -) -> None: - """Start the SeedPass API server.""" - actual_token = api_module.start_server(ctx.obj.get("fingerprint"), token=token) - if not os.getenv("SEEDPASS_API_TOKEN") and token is None: - typer.echo(f"API token: {actual_token}", err=True) - uvicorn.run(api_module.app, host=host, port=port) - - -@api_app.command("stop") -def api_stop(ctx: typer.Context, host: str = "127.0.0.1", port: int = 8000) -> None: - """Stop the SeedPass API server.""" - import requests - - token = os.getenv("SEEDPASS_API_TOKEN", api_module._token) - try: - requests.post( - f"http://{host}:{port}/api/v1/shutdown", - headers={"Authorization": f"Bearer {token}"}, - timeout=2, - ) - except Exception as exc: # pragma: no cover - best effort - typer.echo(f"Failed to stop server: {exc}") - - -@app.command() -def gui() -> None: - """Launch the BeeWare GUI. - - If the platform specific backend is missing, attempt to install it and - retry launching the GUI. - """ - if not _gui_backend_available(): - if sys.platform.startswith("linux"): - pkg = "toga-gtk" - elif sys.platform == "win32": - pkg = "toga-winforms" - elif sys.platform == "darwin": - pkg = "toga-cocoa" - else: - typer.echo( - f"Unsupported platform '{sys.platform}' for BeeWare GUI.", - err=True, - ) - raise typer.Exit(1) - - typer.echo(f"Attempting to install {pkg} for GUI support...") - try: - subprocess.check_call([sys.executable, "-m", "pip", "install", pkg]) - typer.echo(f"Successfully installed {pkg}.") - except subprocess.CalledProcessError as exc: - typer.echo(f"Failed to install {pkg}: {exc}", err=True) - raise typer.Exit(1) - - if not _gui_backend_available(): - typer.echo( - "BeeWare GUI backend still unavailable after installation attempt.", - err=True, - ) - raise typer.Exit(1) - - from seedpass_gui.app import main - - main() - - -if __name__ == "__main__": - app() diff --git a/src/seedpass/cli/__init__.py b/src/seedpass/cli/__init__.py new file mode 100644 index 00000000..1e6d66ab --- /dev/null +++ b/src/seedpass/cli/__init__.py @@ -0,0 +1,185 @@ +from __future__ import annotations + +import importlib +import importlib.util +import subprocess +import sys +from typing import Optional + +import typer + +from .common import _get_services +from seedpass.core.errors import SeedPassError + +app = typer.Typer( + help="SeedPass command line interface", + invoke_without_command=True, +) + +# Global option shared across all commands +fingerprint_option = typer.Option( + None, + "--fingerprint", + "-f", + help="Specify which seed profile to use", +) + +no_clipboard_option = typer.Option( + False, + "--no-clipboard", + help="Disable clipboard support and print secrets instead", +) + +deterministic_totp_option = typer.Option( + False, + "--deterministic-totp", + help="Derive TOTP secrets deterministically", +) + +# Sub command groups +from . import entry, vault, nostr, config, fingerprint, util, api, agent + +app.add_typer(entry.app, name="entry") +app.add_typer(vault.app, name="vault") +app.add_typer(nostr.app, name="nostr") +app.add_typer(config.app, name="config") +app.add_typer(fingerprint.app, name="fingerprint") +app.add_typer(util.app, name="util") +app.add_typer(api.app, name="api") +app.add_typer(agent.app, name="agent") + + +def run() -> None: + """Invoke the CLI, handling SeedPass errors gracefully.""" + try: + app() + except SeedPassError as exc: + typer.echo(str(exc), err=True) + raise typer.Exit(1) from exc + + +def _gui_backend_available() -> bool: + """Return True if a platform-specific BeeWare backend is installed.""" + for pkg in ("toga_gtk", "toga_winforms", "toga_cocoa"): + if importlib.util.find_spec(pkg) is not None: + return True + return False + + +@app.callback(invoke_without_command=True) +def main( + ctx: typer.Context, + fingerprint: Optional[str] = fingerprint_option, + no_clipboard: bool = no_clipboard_option, + deterministic_totp: bool = deterministic_totp_option, +) -> None: + """SeedPass CLI entry point. + + When called without a subcommand this launches the interactive TUI. + """ + ctx.obj = { + "fingerprint": fingerprint, + "no_clipboard": no_clipboard, + "deterministic_totp": deterministic_totp, + } + if ctx.invoked_subcommand is None: + tui = importlib.import_module("main") + raise typer.Exit(tui.main(fingerprint=fingerprint)) + + +@app.command("lock") +def root_lock(ctx: typer.Context) -> None: + """Lock the vault for the active profile.""" + vault_service, _profile, _sync = _get_services(ctx) + vault_service.lock() + typer.echo("locked") + + +@app.command() +def gui( + install: bool = typer.Option( + False, + "--install", + help="Attempt to install the BeeWare GUI backend if missing", + ) +) -> None: + """Launch the BeeWare GUI. + + If a platform specific backend is missing, inform the user how to + install it. Using ``--install`` will attempt installation after + confirmation. + """ + if not _gui_backend_available(): + if sys.platform.startswith("linux"): + pkg = "toga-gtk" + version = "0.5.2" + sha256 = "15b346ac1a2584de5effe5e73a3888f055c68c93300aeb111db9d64186b31646" + elif sys.platform == "win32": + pkg = "toga-winforms" + version = "0.5.2" + sha256 = "83181309f204bcc4a34709d23fdfd68467ae8ecc39c906d13c661cb9a0ef581b" + elif sys.platform == "darwin": + pkg = "toga-cocoa" + version = "0.5.2" + sha256 = "a4d5d1546bf92372a6fb1b450164735fb107b2ee69d15bf87421fec3c78465f9" + else: + typer.echo( + f"Unsupported platform '{sys.platform}' for BeeWare GUI.", + err=True, + ) + raise typer.Exit(1) + + if not install: + typer.echo( + f"BeeWare GUI backend not found. Please install {pkg} manually or rerun " + "with '--install'.", + err=True, + ) + raise typer.Exit(1) + + if not typer.confirm( + f"Install {pkg}=={version} with hash verification?", default=False + ): + typer.echo("Installation cancelled.", err=True) + raise typer.Exit(1) + + typer.echo( + "SeedPass uses pinned versions and SHA256 hashes to verify the GUI backend " + "and protect against tampered packages." + ) + + try: + subprocess.check_call( + [ + sys.executable, + "-m", + "pip", + "install", + "--require-hashes", + f"{pkg}=={version}", + f"--hash=sha256:{sha256}", + ] + ) + typer.echo(f"Successfully installed {pkg}=={version}.") + except subprocess.CalledProcessError as exc: + typer.echo( + "Secure installation failed. Please install the package manually " + f"from a trusted source. Details: {exc}", + err=True, + ) + raise typer.Exit(1) + + if not _gui_backend_available(): + typer.echo( + "BeeWare GUI backend still unavailable after installation attempt.", + err=True, + ) + raise typer.Exit(1) + + from seedpass_gui.app import main + + main() + + +if __name__ == "__main__": # pragma: no cover + run() diff --git a/src/seedpass/cli/agent.py b/src/seedpass/cli/agent.py new file mode 100644 index 00000000..ad7b2ce4 --- /dev/null +++ b/src/seedpass/cli/agent.py @@ -0,0 +1,378 @@ +from __future__ import annotations + +import json +import os +from datetime import UTC, datetime, timedelta +from pathlib import Path +from typing import Optional + +import bcrypt +import click +import typer +from bip_utils import Bip39Languages, Bip39MnemonicGenerator, Bip39WordsNum +from mnemonic import Mnemonic + +from constants import APP_DIR, initialize_app +from seedpass.core.api import EntryService +from seedpass.core.entry_types import ALL_ENTRY_TYPES, EntryType +from seedpass.core.encryption import EncryptionManager +from seedpass.core.manager import PasswordManager +from seedpass.core.vault import Vault +from seedpass.core.config_manager import ConfigManager +from utils.fingerprint import generate_fingerprint +from utils.fingerprint_manager import FingerprintManager +from utils.key_derivation import derive_index_key, derive_key_from_password + +app = typer.Typer(help="Agent-first non-interactive workflows") + +PRIVATE_KINDS = { + EntryType.SEED.value, + EntryType.SSH.value, + EntryType.PGP.value, + EntryType.NOSTR.value, + EntryType.MANAGED_ACCOUNT.value, +} +DEFAULT_POLICY = { + "allow_kinds": [ + EntryType.PASSWORD.value, + EntryType.TOTP.value, + EntryType.KEY_VALUE.value, + ], + "deny_private_reveal": sorted(PRIVATE_KINDS), + "allow_export_import": False, +} + + +def _policy_path() -> Path: + return APP_DIR / "agent_policy.json" + + +def _deny_all_policy() -> dict: + return { + "allow_kinds": [], + "deny_private_reveal": list(ALL_ENTRY_TYPES), + "allow_export_import": False, + } + + +def _load_policy(*, strict: bool = False) -> dict: + path = _policy_path() + if not path.exists(): + return dict(DEFAULT_POLICY) + try: + data = json.loads(path.read_text(encoding="utf-8")) + except Exception as exc: + if strict: + raise ValueError("agent policy file is not valid JSON") from exc + return _deny_all_policy() + + if not isinstance(data, dict): + if strict: + raise ValueError("agent policy file must be a JSON object") + return _deny_all_policy() + + policy = dict(DEFAULT_POLICY) + if isinstance(data.get("allow_kinds"), list): + allow_kinds = [str(v) for v in data["allow_kinds"]] + invalid = [v for v in allow_kinds if v not in ALL_ENTRY_TYPES] + if invalid and strict: + raise ValueError(f"agent policy has invalid allow_kinds entries: {invalid}") + policy["allow_kinds"] = [v for v in allow_kinds if v in ALL_ENTRY_TYPES] + if isinstance(data.get("deny_private_reveal"), list): + deny_private = [str(v) for v in data["deny_private_reveal"]] + invalid = [v for v in deny_private if v not in ALL_ENTRY_TYPES] + if invalid and strict: + raise ValueError( + f"agent policy has invalid deny_private_reveal entries: {invalid}" + ) + policy["deny_private_reveal"] = [v for v in deny_private if v in ALL_ENTRY_TYPES] + if isinstance(data.get("allow_export_import"), bool): + policy["allow_export_import"] = data["allow_export_import"] + return policy + + +def _save_policy(policy: dict) -> None: + path = _policy_path() + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(policy, indent=2), encoding="utf-8") + os.chmod(path, 0o600) + + +def _password_from_env(var_name: str) -> str: + value = os.getenv(var_name) + if not value: + raise typer.BadParameter( + f"Missing password env var '{var_name}'. Export it before running this command." + ) + return value + + +def _seed_from_inputs( + seed: Optional[str], + seed_file: Optional[Path], + generate_seed: bool, +) -> tuple[str, bool]: + choices = int(bool(seed)) + int(bool(seed_file)) + int(bool(generate_seed)) + if choices != 1: + raise typer.BadParameter( + "Provide exactly one of --seed, --seed-file, or --generate-seed." + ) + if seed_file: + seed = seed_file.read_text(encoding="utf-8").strip() + elif generate_seed: + seed = ( + Bip39MnemonicGenerator(Bip39Languages.ENGLISH) + .FromWordsNumber(Bip39WordsNum.WORDS_NUM_12) + .ToStr() + ) + assert seed is not None + if not Mnemonic("english").check(seed): + raise typer.BadParameter("Invalid BIP-39 seed phrase.") + return seed, bool(generate_seed) + + +@app.command("init") +def agent_init( + seed: Optional[str] = typer.Option( + None, "--seed", help="BIP-39 seed phrase (avoid shell history for secrets)" + ), + seed_file: Optional[Path] = typer.Option( + None, "--seed-file", help="Path to a file containing the seed phrase" + ), + generate_seed: bool = typer.Option( + False, "--generate-seed", help="Generate a fresh 12-word seed" + ), + password_env: str = typer.Option( + "SEEDPASS_PASSWORD", "--password-env", help="Env var containing master password" + ), + switch_existing: bool = typer.Option( + False, + "--switch-existing", + help="Switch to existing profile if the seed fingerprint already exists", + ), + kdf_iterations: int = typer.Option( + 100_000, "--kdf-iterations", help="PBKDF2 iterations for profile setup" + ), + print_seed: bool = typer.Option( + False, "--print-seed", help="Include generated seed in JSON output" + ), +) -> None: + """Initialize a profile non-interactively for agent workflows.""" + initialize_app() + password = _password_from_env(password_env) + seed_phrase, generated = _seed_from_inputs(seed, seed_file, generate_seed) + + fp_mgr = FingerprintManager(APP_DIR) + fingerprint = None + created = False + try: + fingerprint = fp_mgr.add_fingerprint(seed_phrase) + created = True + except ValueError: + fingerprint = generate_fingerprint(seed_phrase) + if not switch_existing: + raise typer.BadParameter( + "Seed profile already exists. Use --switch-existing to reuse it." + ) + + assert fingerprint is not None + profile_dir = fp_mgr.get_fingerprint_directory(fingerprint) + if profile_dir is None: + raise typer.BadParameter("Could not resolve profile directory for fingerprint.") + profile_dir.mkdir(parents=True, exist_ok=True) + + seed_key = derive_key_from_password( + password, fingerprint, iterations=kdf_iterations + ) + seed_mgr = EncryptionManager(seed_key, profile_dir) + seed_mgr.encrypt_parent_seed(seed_phrase) + + index_key = derive_index_key(seed_phrase) + enc_mgr = EncryptionManager(index_key, profile_dir) + vault = Vault(enc_mgr, profile_dir) + cfg = ConfigManager(vault=vault, fingerprint_dir=profile_dir) + cfg.set_password_hash(bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()) + cfg.set_kdf_iterations(kdf_iterations) + cfg.set_offline_mode(True) + cfg.set_secret_mode_enabled(False) + cfg.set_quick_unlock(False) + + if not _policy_path().exists(): + _save_policy(dict(DEFAULT_POLICY)) + + payload = { + "status": "ok", + "created": created, + "fingerprint": fingerprint, + "profile_dir": str(profile_dir), + "generated_seed": seed_phrase if generated and print_seed else None, + } + typer.echo(json.dumps(payload, indent=2)) + + +@app.command("policy-show") +def agent_policy_show() -> None: + """Show the active agent policy.""" + try: + policy = _load_policy(strict=True) + except ValueError as exc: + raise typer.BadParameter(str(exc)) + typer.echo(json.dumps(policy, indent=2)) + + +@app.command("policy-set") +def agent_policy_set( + allow_kind: list[str] = typer.Option( + None, + "--allow-kind", + help="Allowed entry kind for agent retrieval (repeatable)", + click_type=click.Choice(ALL_ENTRY_TYPES), + ), + deny_private_kind: list[str] = typer.Option( + None, + "--deny-private-kind", + help="Kind denied from agent reveal (repeatable)", + click_type=click.Choice(ALL_ENTRY_TYPES), + ), + allow_export_import: bool = typer.Option( + False, + "--allow-export-import", + help="Allow export/import operations in agent mode", + ), +) -> None: + """Set policy flags used by agent commands.""" + policy = _load_policy(strict=False) + if allow_kind: + policy["allow_kinds"] = list(allow_kind) + if deny_private_kind: + policy["deny_private_reveal"] = list(deny_private_kind) + policy["allow_export_import"] = bool(allow_export_import) + _save_policy(policy) + typer.echo(json.dumps(policy, indent=2)) + + +@app.command("get") +def agent_get( + ctx: typer.Context, + query: str = typer.Argument(..., help="Entry label or index query"), + password_env: str = typer.Option( + "SEEDPASS_PASSWORD", "--password-env", help="Env var containing master password" + ), + ttl: int = typer.Option( + 30, + "--ttl", + min=1, + help="Lease time in seconds for the returned secret metadata", + ), +) -> None: + """Retrieve one secret as JSON with policy enforcement.""" + fingerprint = (ctx.obj or {}).get("fingerprint") + if not fingerprint: + raise typer.BadParameter("Specify target profile with --fingerprint.") + password = _password_from_env(password_env) + try: + policy = _load_policy(strict=True) + except ValueError as exc: + typer.echo( + json.dumps( + { + "status": "denied", + "reason": "invalid_policy", + "detail": str(exc), + }, + indent=2, + ) + ) + raise typer.Exit(1) + + pm = PasswordManager(fingerprint=fingerprint, password=password) + service = EntryService(pm) + matches = service.search_entries(query) + if len(matches) != 1: + payload = { + "status": "error", + "reason": "ambiguous_or_missing", + "match_count": len(matches), + "matches": [ + { + "index": idx, + "label": label, + "kind": etype.value, + "username": username, + "url": url, + "archived": archived, + } + for idx, label, username, url, archived, etype in matches + ], + } + typer.echo(json.dumps(payload, indent=2)) + raise typer.Exit(1) + + index = matches[0][0] + entry = service.retrieve_entry(index) + kind = entry.get("type", entry.get("kind")) + if kind is None: + raise typer.BadParameter("Entry kind missing.") + + allow_kinds = set(policy.get("allow_kinds", [])) + deny_private = set(policy.get("deny_private_reveal", [])) + if allow_kinds and kind not in allow_kinds: + typer.echo( + json.dumps( + { + "status": "denied", + "reason": "kind_not_allowed", + "kind": kind, + "policy": policy, + }, + indent=2, + ) + ) + raise typer.Exit(1) + if kind in deny_private: + typer.echo( + json.dumps( + { + "status": "denied", + "reason": "private_kind_blocked", + "kind": kind, + "policy": policy, + }, + indent=2, + ) + ) + raise typer.Exit(1) + + secret: Optional[str] = None + if kind == EntryType.PASSWORD.value: + secret = service.generate_password(int(entry.get("length", 12)), index) + elif kind == EntryType.TOTP.value: + secret = service.get_totp_code(index) + elif kind == EntryType.KEY_VALUE.value: + secret = entry.get("value") + else: + typer.echo( + json.dumps( + { + "status": "error", + "reason": "unsupported_kind_for_agent_get", + "kind": kind, + }, + indent=2, + ) + ) + raise typer.Exit(1) + + now = datetime.now(UTC) + payload = { + "status": "ok", + "fingerprint": fingerprint, + "index": index, + "kind": kind, + "label": entry.get("label"), + "lease_ttl_sec": ttl, + "issued_at_utc": now.isoformat(), + "expires_at_utc": (now + timedelta(seconds=ttl)).isoformat(), + "secret": secret, + } + typer.echo(json.dumps(payload, indent=2)) diff --git a/src/seedpass/cli/api.py b/src/seedpass/cli/api.py new file mode 100644 index 00000000..618d8d9a --- /dev/null +++ b/src/seedpass/cli/api.py @@ -0,0 +1,37 @@ +from __future__ import annotations + +import typer +import uvicorn + +from .. import api as api_module + +app = typer.Typer(help="Run the API server") + + +@app.command("start") +def api_start(ctx: typer.Context, host: str = "127.0.0.1", port: int = 8000) -> None: + """Start the SeedPass API server.""" + token = api_module.start_server(ctx.obj.get("fingerprint")) + typer.echo( + f"API token: {token}\nWARNING: Store this token securely; it cannot be recovered." + ) + uvicorn.run(api_module.app, host=host, port=port) + + +@app.command("stop") +def api_stop( + token: str = typer.Option(..., help="API token"), + host: str = "127.0.0.1", + port: int = 8000, +) -> None: + """Stop the SeedPass API server.""" + import requests + + try: + requests.post( + f"http://{host}:{port}/api/v1/shutdown", + headers={"Authorization": f"Bearer {token}"}, + timeout=2, + ) + except Exception as exc: # pragma: no cover - best effort + typer.echo(f"Failed to stop server: {exc}") diff --git a/src/seedpass/cli/common.py b/src/seedpass/cli/common.py new file mode 100644 index 00000000..114d5961 --- /dev/null +++ b/src/seedpass/cli/common.py @@ -0,0 +1,63 @@ +from __future__ import annotations + +import typer + +from seedpass.core.manager import PasswordManager +from seedpass.core.entry_types import EntryType +from seedpass.core.api import ( + VaultService, + ProfileService, + SyncService, + EntryService, + ConfigService, + UtilityService, + NostrService, + ChangePasswordRequest, + UnlockRequest, + BackupParentSeedRequest, + ProfileSwitchRequest, + ProfileRemoveRequest, +) + + +def _get_pm(ctx: typer.Context) -> PasswordManager: + """Return a PasswordManager optionally selecting a fingerprint.""" + fp = ctx.obj.get("fingerprint") + if fp is None: + pm = PasswordManager() + else: + pm = PasswordManager(fingerprint=fp) + if ctx.obj.get("no_clipboard"): + pm.secret_mode_enabled = False + if ctx.obj.get("deterministic_totp"): + pm.deterministic_totp = True + return pm + + +def _get_services( + ctx: typer.Context, +) -> tuple[VaultService, ProfileService, SyncService]: + """Return service layer instances for the current context.""" + + pm = _get_pm(ctx) + return VaultService(pm), ProfileService(pm), SyncService(pm) + + +def _get_entry_service(ctx: typer.Context) -> EntryService: + pm = _get_pm(ctx) + return EntryService(pm) + + +def _get_config_service(ctx: typer.Context) -> ConfigService: + pm = _get_pm(ctx) + return ConfigService(pm) + + +def _get_util_service(ctx: typer.Context) -> UtilityService: + pm = _get_pm(ctx) + return UtilityService(pm) + + +def _get_nostr_service(ctx: typer.Context) -> NostrService: + pm = _get_pm(ctx) + return NostrService(pm) diff --git a/src/seedpass/cli/config.py b/src/seedpass/cli/config.py new file mode 100644 index 00000000..4d58e5d3 --- /dev/null +++ b/src/seedpass/cli/config.py @@ -0,0 +1,124 @@ +from __future__ import annotations + +import typer + +from .common import _get_config_service + +app = typer.Typer(help="Get or set configuration values") + + +@app.command("get") +def config_get(ctx: typer.Context, key: str) -> None: + """Get a configuration value.""" + service = _get_config_service(ctx) + value = service.get(key) + if value is None: + typer.echo("Key not found") + else: + typer.echo(str(value)) + + +@app.command("set") +def config_set(ctx: typer.Context, key: str, value: str) -> None: + """Set a configuration value.""" + service = _get_config_service(ctx) + + try: + val = ( + [r.strip() for r in value.split(",") if r.strip()] + if key == "relays" + else value + ) + service.set(key, val) + except KeyError: + typer.echo("Unknown key") + raise typer.Exit(code=1) + except Exception as exc: # pragma: no cover - pass through errors + typer.echo(f"Error: {exc}") + raise typer.Exit(code=1) + + typer.echo("Updated") + + +@app.command("toggle-secret-mode") +def config_toggle_secret_mode(ctx: typer.Context) -> None: + """Interactively enable or disable secret mode. + + When enabled, newly generated and retrieved passwords are copied to the + clipboard instead of printed to the screen. + """ + service = _get_config_service(ctx) + try: + enabled = service.get_secret_mode_enabled() + delay = service.get_clipboard_clear_delay() + except Exception as exc: # pragma: no cover - pass through errors + typer.echo(f"Error loading settings: {exc}") + raise typer.Exit(code=1) + + typer.echo(f"Secret mode is currently {'ON' if enabled else 'OFF'}") + choice = ( + typer.prompt( + "Enable secret mode? (y/n, blank to keep)", default="", show_default=False + ) + .strip() + .lower() + ) + if choice in ("y", "yes"): + enabled = True + elif choice in ("n", "no"): + enabled = False + + inp = typer.prompt( + f"Clipboard clear delay in seconds [{delay}]", default="", show_default=False + ).strip() + if inp: + try: + delay = int(inp) + if delay <= 0: + typer.echo("Delay must be positive") + raise typer.Exit(code=1) + except ValueError: + typer.echo("Invalid number") + raise typer.Exit(code=1) + + try: + service.set_secret_mode(enabled, delay) + except Exception as exc: # pragma: no cover - pass through errors + typer.echo(f"Error: {exc}") + raise typer.Exit(code=1) + + status = "enabled" if enabled else "disabled" + typer.echo(f"Secret mode {status}.") + + +@app.command("toggle-offline") +def config_toggle_offline(ctx: typer.Context) -> None: + """Enable or disable offline mode.""" + service = _get_config_service(ctx) + try: + enabled = service.get_offline_mode() + except Exception as exc: # pragma: no cover - pass through errors + typer.echo(f"Error loading settings: {exc}") + raise typer.Exit(code=1) + + typer.echo(f"Offline mode is currently {'ON' if enabled else 'OFF'}") + choice = ( + typer.prompt( + "Enable offline mode? (y/n, blank to keep)", default="", show_default=False + ) + .strip() + .lower() + ) + if choice in ("y", "yes"): + enabled = True + elif choice in ("n", "no"): + enabled = False + + try: + service.set_offline_mode(enabled) + except Exception as exc: # pragma: no cover - pass through errors + typer.echo(f"Error: {exc}") + raise typer.Exit(code=1) + + status = "enabled" if enabled else "disabled" + typer.echo(f"Offline mode {status}.") diff --git a/src/seedpass/cli/entry.py b/src/seedpass/cli/entry.py new file mode 100644 index 00000000..1474cdfb --- /dev/null +++ b/src/seedpass/cli/entry.py @@ -0,0 +1,366 @@ +from __future__ import annotations + +import json +import sys +from pathlib import Path +from typing import List, Optional + +import typer +import click + +from .common import _get_entry_service, EntryType +from seedpass.core.entry_types import ALL_ENTRY_TYPES +from utils.clipboard import ClipboardUnavailableError + +app = typer.Typer(help="Manage individual entries") + + +@app.command("list") +def entry_list( + ctx: typer.Context, + sort: str = typer.Option( + "index", "--sort", help="Sort by 'index', 'label', or 'updated'" + ), + kind: Optional[str] = typer.Option( + None, + "--kind", + help="Filter by entry type", + click_type=click.Choice(ALL_ENTRY_TYPES), + ), + archived: bool = typer.Option(False, "--archived", help="Include archived"), +) -> None: + """List entries in the vault.""" + service = _get_entry_service(ctx) + entries = service.list_entries( + sort_by=sort, + filter_kinds=[kind] if kind else None, + include_archived=archived, + ) + for idx, label, username, url, is_archived in entries: + line = f"{idx}: {label}" + if username: + line += f" ({username})" + if url: + line += f" {url}" + if is_archived: + line += " [archived]" + typer.echo(line) + + +@app.command("search") +def entry_search( + ctx: typer.Context, + query: str, + kinds: List[str] = typer.Option( + None, + "--kind", + "-k", + help="Filter by entry kinds (can be repeated)", + click_type=click.Choice(ALL_ENTRY_TYPES), + ), +) -> None: + """Search entries.""" + service = _get_entry_service(ctx) + kinds = list(kinds) if kinds else None + results = service.search_entries(query, kinds=kinds) + if not results: + typer.echo("No matching entries found") + return + for idx, label, username, url, _arch, etype in results: + line = f"{idx}: {etype.value.replace('_', ' ').title()} - {label}" + if username: + line += f" ({username})" + if url: + line += f" {url}" + typer.echo(line) + + +@app.command("get") +def entry_get(ctx: typer.Context, query: str) -> None: + """Retrieve a single entry's secret.""" + service = _get_entry_service(ctx) + try: + matches = service.search_entries(query) + if len(matches) == 0: + typer.echo("No matching entries found") + raise typer.Exit(code=1) + if len(matches) > 1: + typer.echo("Matches:") + for idx, label, username, _url, _arch, etype in matches: + name = f"{idx}: {etype.value.replace('_', ' ').title()} - {label}" + if username: + name += f" ({username})" + typer.echo(name) + raise typer.Exit(code=1) + + index = matches[0][0] + entry = service.retrieve_entry(index) + etype = entry.get("type", entry.get("kind")) + if etype == EntryType.PASSWORD.value: + length = int(entry.get("length", 12)) + password = service.generate_password(length, index) + typer.echo(password) + elif etype == EntryType.TOTP.value: + code = service.get_totp_code(index) + typer.echo(code) + else: + typer.echo("Unsupported entry type") + raise typer.Exit(code=1) + except ClipboardUnavailableError as exc: + typer.echo( + f"Clipboard unavailable: {exc}\n" + "Re-run with '--no-clipboard' to print secrets instead.", + err=True, + ) + raise typer.Exit(code=1) + + +@app.command("add") +def entry_add( + ctx: typer.Context, + label: str, + length: int = typer.Option(12, "--length"), + username: Optional[str] = typer.Option(None, "--username"), + url: Optional[str] = typer.Option(None, "--url"), + no_special: bool = typer.Option( + False, "--no-special", help="Exclude special characters" + ), + allowed_special_chars: Optional[str] = typer.Option( + None, "--allowed-special-chars", help="Explicit set of special characters" + ), + special_mode: Optional[str] = typer.Option( + None, + "--special-mode", + help="Special character mode", + ), + exclude_ambiguous: bool = typer.Option( + False, + "--exclude-ambiguous", + help="Exclude ambiguous characters", + ), + min_uppercase: Optional[int] = typer.Option(None, "--min-uppercase"), + min_lowercase: Optional[int] = typer.Option(None, "--min-lowercase"), + min_digits: Optional[int] = typer.Option(None, "--min-digits"), + min_special: Optional[int] = typer.Option(None, "--min-special"), +) -> None: + """Add a new password entry and output its index.""" + service = _get_entry_service(ctx) + kwargs = {} + if no_special: + kwargs["include_special_chars"] = False + if allowed_special_chars is not None: + kwargs["allowed_special_chars"] = allowed_special_chars + if special_mode is not None: + kwargs["special_mode"] = special_mode + if exclude_ambiguous: + kwargs["exclude_ambiguous"] = True + if min_uppercase is not None: + kwargs["min_uppercase"] = min_uppercase + if min_lowercase is not None: + kwargs["min_lowercase"] = min_lowercase + if min_digits is not None: + kwargs["min_digits"] = min_digits + if min_special is not None: + kwargs["min_special"] = min_special + + index = service.add_entry(label, length, username, url, **kwargs) + typer.echo(str(index)) + + +@app.command("add-totp") +def entry_add_totp( + ctx: typer.Context, + label: str, + index: Optional[int] = typer.Option(None, "--index", help="Derivation index"), + secret: Optional[str] = typer.Option(None, "--secret", help="Import secret"), + period: int = typer.Option(30, "--period", help="TOTP period in seconds"), + digits: int = typer.Option(6, "--digits", help="Number of TOTP digits"), + deterministic_totp: bool = typer.Option( + False, "--deterministic-totp", help="Derive secret deterministically" + ), +) -> None: + """Add a TOTP entry and output the otpauth URI.""" + service = _get_entry_service(ctx) + uri = service.add_totp( + label, + index=index, + secret=secret, + period=period, + digits=digits, + deterministic=deterministic_totp, + ) + typer.echo(uri) + + +@app.command("add-ssh") +def entry_add_ssh( + ctx: typer.Context, + label: str, + index: Optional[int] = typer.Option(None, "--index", help="Derivation index"), + notes: str = typer.Option("", "--notes", help="Entry notes"), +) -> None: + """Add an SSH key entry and output its index.""" + service = _get_entry_service(ctx) + idx = service.add_ssh_key( + label, + index=index, + notes=notes, + ) + typer.echo(str(idx)) + + +@app.command("add-pgp") +def entry_add_pgp( + ctx: typer.Context, + label: str, + index: Optional[int] = typer.Option(None, "--index", help="Derivation index"), + key_type: str = typer.Option("ed25519", "--key-type", help="Key type"), + user_id: str = typer.Option("", "--user-id", help="User ID"), + notes: str = typer.Option("", "--notes", help="Entry notes"), +) -> None: + """Add a PGP key entry and output its index.""" + service = _get_entry_service(ctx) + idx = service.add_pgp_key( + label, + index=index, + key_type=key_type, + user_id=user_id, + notes=notes, + ) + typer.echo(str(idx)) + + +@app.command("add-nostr") +def entry_add_nostr( + ctx: typer.Context, + label: str, + index: Optional[int] = typer.Option(None, "--index", help="Derivation index"), + notes: str = typer.Option("", "--notes", help="Entry notes"), +) -> None: + """Add a Nostr key entry and output its index.""" + service = _get_entry_service(ctx) + idx = service.add_nostr_key( + label, + index=index, + notes=notes, + ) + typer.echo(str(idx)) + + +@app.command("add-seed") +def entry_add_seed( + ctx: typer.Context, + label: str, + index: Optional[int] = typer.Option(None, "--index", help="Derivation index"), + words: int = typer.Option(24, "--words", help="Word count"), + notes: str = typer.Option("", "--notes", help="Entry notes"), +) -> None: + """Add a derived seed phrase entry and output its index.""" + service = _get_entry_service(ctx) + idx = service.add_seed( + label, + index=index, + words=words, + notes=notes, + ) + typer.echo(str(idx)) + + +@app.command("add-key-value") +def entry_add_key_value( + ctx: typer.Context, + label: str, + key: str = typer.Option(..., "--key", help="Key name"), + value: str = typer.Option(..., "--value", help="Stored value"), + notes: str = typer.Option("", "--notes", help="Entry notes"), +) -> None: + """Add a key/value entry and output its index.""" + service = _get_entry_service(ctx) + idx = service.add_key_value(label, key, value, notes=notes) + typer.echo(str(idx)) + + +@app.command("add-managed-account") +def entry_add_managed_account( + ctx: typer.Context, + label: str, + index: Optional[int] = typer.Option(None, "--index", help="Derivation index"), + notes: str = typer.Option("", "--notes", help="Entry notes"), +) -> None: + """Add a managed account seed entry and output its index.""" + service = _get_entry_service(ctx) + idx = service.add_managed_account( + label, + index=index, + notes=notes, + ) + typer.echo(str(idx)) + + +@app.command("modify") +def entry_modify( + ctx: typer.Context, + entry_id: int, + label: Optional[str] = typer.Option(None, "--label"), + username: Optional[str] = typer.Option(None, "--username"), + url: Optional[str] = typer.Option(None, "--url"), + notes: Optional[str] = typer.Option(None, "--notes"), + period: Optional[int] = typer.Option( + None, "--period", help="TOTP period in seconds" + ), + digits: Optional[int] = typer.Option(None, "--digits", help="TOTP digits"), + key: Optional[str] = typer.Option(None, "--key", help="New key"), + value: Optional[str] = typer.Option(None, "--value", help="New value"), +) -> None: + """Modify an existing entry.""" + service = _get_entry_service(ctx) + try: + service.modify_entry( + entry_id, + username=username, + url=url, + notes=notes, + label=label, + period=period, + digits=digits, + key=key, + value=value, + ) + except ValueError as e: + typer.echo(str(e)) + sys.stdout.flush() + raise typer.Exit(code=1) + + +@app.command("archive") +def entry_archive(ctx: typer.Context, entry_id: int) -> None: + """Archive an entry.""" + service = _get_entry_service(ctx) + service.archive_entry(entry_id) + typer.echo(str(entry_id)) + + +@app.command("unarchive") +def entry_unarchive(ctx: typer.Context, entry_id: int) -> None: + """Restore an archived entry.""" + service = _get_entry_service(ctx) + service.restore_entry(entry_id) + typer.echo(str(entry_id)) + + +@app.command("totp-codes") +def entry_totp_codes(ctx: typer.Context) -> None: + """Display all current TOTP codes.""" + service = _get_entry_service(ctx) + service.display_totp_codes() + + +@app.command("export-totp") +def entry_export_totp( + ctx: typer.Context, file: str = typer.Option(..., help="Output file") +) -> None: + """Export all TOTP secrets to a JSON file.""" + service = _get_entry_service(ctx) + data = service.export_totp_entries() + Path(file).write_text(json.dumps(data, indent=2)) + typer.echo(str(file)) diff --git a/src/seedpass/cli/fingerprint.py b/src/seedpass/cli/fingerprint.py new file mode 100644 index 00000000..630cead1 --- /dev/null +++ b/src/seedpass/cli/fingerprint.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +import typer + +from .common import _get_services, ProfileRemoveRequest, ProfileSwitchRequest + +app = typer.Typer(help="Manage seed profiles") + + +@app.command("list") +def fingerprint_list(ctx: typer.Context) -> None: + """List available seed profiles.""" + _vault, profile_service, _sync = _get_services(ctx) + for fp in profile_service.list_profiles(): + typer.echo(fp) + + +@app.command("add") +def fingerprint_add(ctx: typer.Context) -> None: + """Create a new seed profile.""" + _vault, profile_service, _sync = _get_services(ctx) + profile_service.add_profile() + + +@app.command("remove") +def fingerprint_remove(ctx: typer.Context, fingerprint: str) -> None: + """Remove a seed profile.""" + _vault, profile_service, _sync = _get_services(ctx) + profile_service.remove_profile(ProfileRemoveRequest(fingerprint=fingerprint)) + + +@app.command("switch") +def fingerprint_switch(ctx: typer.Context, fingerprint: str) -> None: + """Switch to another seed profile.""" + _vault, profile_service, _sync = _get_services(ctx) + password = typer.prompt("Master password", hide_input=True) + profile_service.switch_profile( + ProfileSwitchRequest(fingerprint=fingerprint, password=password) + ) diff --git a/src/seedpass/cli/nostr.py b/src/seedpass/cli/nostr.py new file mode 100644 index 00000000..07a1b113 --- /dev/null +++ b/src/seedpass/cli/nostr.py @@ -0,0 +1,66 @@ +from __future__ import annotations + +import typer + +from .common import _get_services, _get_nostr_service + +app = typer.Typer( + help="Interact with Nostr relays. See docs/nostr_setup.md for configuration and troubleshooting." +) + + +@app.command("sync") +def nostr_sync(ctx: typer.Context) -> None: + """Sync with configured Nostr relays.""" + _vault, _profile, sync_service = _get_services(ctx) + model = sync_service.sync() + if model: + typer.echo("Event IDs:") + typer.echo(f"- manifest: {model.manifest_id}") + for cid in model.chunk_ids: + typer.echo(f"- chunk: {cid}") + for did in model.delta_ids: + typer.echo(f"- delta: {did}") + else: + typer.echo("Error: Failed to sync vault") + + +@app.command("get-pubkey") +def nostr_get_pubkey(ctx: typer.Context) -> None: + """Display the active profile's npub.""" + service = _get_nostr_service(ctx) + npub = service.get_pubkey() + typer.echo(npub) + + +@app.command("list-relays") +def nostr_list_relays(ctx: typer.Context) -> None: + """Display configured Nostr relays.""" + service = _get_nostr_service(ctx) + relays = service.list_relays() + for i, r in enumerate(relays, 1): + typer.echo(f"{i}: {r}") + + +@app.command("add-relay") +def nostr_add_relay(ctx: typer.Context, url: str) -> None: + """Add a relay URL.""" + service = _get_nostr_service(ctx) + try: + service.add_relay(url) + except Exception as exc: # pragma: no cover - pass through errors + typer.echo(f"Error: {exc}") + raise typer.Exit(code=1) + typer.echo("Added") + + +@app.command("remove-relay") +def nostr_remove_relay(ctx: typer.Context, idx: int) -> None: + """Remove a relay by index (1-based).""" + service = _get_nostr_service(ctx) + try: + service.remove_relay(idx) + except Exception as exc: # pragma: no cover - pass through errors + typer.echo(f"Error: {exc}") + raise typer.Exit(code=1) + typer.echo("Removed") diff --git a/src/seedpass/cli/util.py b/src/seedpass/cli/util.py new file mode 100644 index 00000000..77314944 --- /dev/null +++ b/src/seedpass/cli/util.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +from typing import Optional + +import typer + +from .common import _get_util_service + +app = typer.Typer(help="Utility commands") + + +@app.command("generate-password") +def generate_password( + ctx: typer.Context, + length: int = 24, + no_special: bool = typer.Option( + False, "--no-special", help="Exclude special characters" + ), + allowed_special_chars: Optional[str] = typer.Option( + None, "--allowed-special-chars", help="Explicit set of special characters" + ), + special_mode: Optional[str] = typer.Option( + None, + "--special-mode", + help="Special character mode", + ), + exclude_ambiguous: bool = typer.Option( + False, + "--exclude-ambiguous", + help="Exclude ambiguous characters", + ), + min_uppercase: Optional[int] = typer.Option(None, "--min-uppercase"), + min_lowercase: Optional[int] = typer.Option(None, "--min-lowercase"), + min_digits: Optional[int] = typer.Option(None, "--min-digits"), + min_special: Optional[int] = typer.Option(None, "--min-special"), +) -> None: + """Generate a strong password.""" + service = _get_util_service(ctx) + kwargs = {} + if no_special: + kwargs["include_special_chars"] = False + if allowed_special_chars is not None: + kwargs["allowed_special_chars"] = allowed_special_chars + if special_mode is not None: + kwargs["special_mode"] = special_mode + if exclude_ambiguous: + kwargs["exclude_ambiguous"] = True + if min_uppercase is not None: + kwargs["min_uppercase"] = min_uppercase + if min_lowercase is not None: + kwargs["min_lowercase"] = min_lowercase + if min_digits is not None: + kwargs["min_digits"] = min_digits + if min_special is not None: + kwargs["min_special"] = min_special + + password = service.generate_password(length, **kwargs) + typer.echo(password) + + +@app.command("verify-checksum") +def verify_checksum(ctx: typer.Context) -> None: + """Verify the SeedPass script checksum.""" + service = _get_util_service(ctx) + service.verify_checksum() + + +@app.command("update-checksum") +def update_checksum(ctx: typer.Context) -> None: + """Regenerate the script checksum file.""" + service = _get_util_service(ctx) + service.update_checksum() diff --git a/src/seedpass/cli/vault.py b/src/seedpass/cli/vault.py new file mode 100644 index 00000000..a5269340 --- /dev/null +++ b/src/seedpass/cli/vault.py @@ -0,0 +1,98 @@ +from __future__ import annotations + +import json +from pathlib import Path +from typing import Optional + +import typer + +from .common import ( + _get_services, + ChangePasswordRequest, + UnlockRequest, + BackupParentSeedRequest, +) + +app = typer.Typer(help="Manage the entire vault") + + +@app.command("export") +def vault_export( + ctx: typer.Context, file: str = typer.Option(..., help="Output file") +) -> None: + """Export the vault profile to an encrypted file.""" + vault_service, _profile, _sync = _get_services(ctx) + data = vault_service.export_profile() + Path(file).write_bytes(data) + typer.echo(str(file)) + + +@app.command("import") +def vault_import( + ctx: typer.Context, file: str = typer.Option(..., help="Input file") +) -> None: + """Import a vault profile from an encrypted file.""" + vault_service, _profile, _sync = _get_services(ctx) + data = Path(file).read_bytes() + vault_service.import_profile(data) + typer.echo(str(file)) + + +@app.command("change-password") +def vault_change_password(ctx: typer.Context) -> None: + """Change the master password used for encryption.""" + vault_service, _profile, _sync = _get_services(ctx) + old_pw = typer.prompt("Current password", hide_input=True) + new_pw = typer.prompt("New password", hide_input=True, confirmation_prompt=True) + try: + vault_service.change_password( + ChangePasswordRequest(old_password=old_pw, new_password=new_pw) + ) + except Exception as exc: # pragma: no cover - pass through errors + typer.echo(f"Error: {exc}") + raise typer.Exit(code=1) + typer.echo("Password updated") + + +@app.command("unlock") +def vault_unlock(ctx: typer.Context) -> None: + """Unlock the vault for the active profile.""" + vault_service, _profile, _sync = _get_services(ctx) + password = typer.prompt("Master password", hide_input=True) + try: + resp = vault_service.unlock(UnlockRequest(password=password)) + except Exception as exc: # pragma: no cover - pass through errors + typer.echo(f"Error: {exc}") + raise typer.Exit(code=1) + typer.echo(f"Unlocked in {resp.duration:.2f}s") + + +@app.command("lock") +def vault_lock(ctx: typer.Context) -> None: + """Lock the vault and clear sensitive data from memory.""" + vault_service, _profile, _sync = _get_services(ctx) + vault_service.lock() + typer.echo("locked") + + +@app.command("stats") +def vault_stats(ctx: typer.Context) -> None: + """Display statistics about the current seed profile.""" + vault_service, _profile, _sync = _get_services(ctx) + stats = vault_service.stats() + typer.echo(json.dumps(stats, indent=2)) + + +@app.command("reveal-parent-seed") +def vault_reveal_parent_seed( + ctx: typer.Context, + file: Optional[str] = typer.Option( + None, "--file", help="Save encrypted seed to this path" + ), +) -> None: + """Display the parent seed and optionally write an encrypted backup file.""" + vault_service, _profile, _sync = _get_services(ctx) + password = typer.prompt("Master password", hide_input=True) + vault_service.backup_parent_seed( + BackupParentSeedRequest(path=Path(file) if file else None, password=password) + ) diff --git a/src/seedpass/core/api.py b/src/seedpass/core/api.py index f6c1d538..80747053 100644 --- a/src/seedpass/core/api.py +++ b/src/seedpass/core/api.py @@ -148,7 +148,9 @@ class VaultService: """Restore a profile from ``data`` and sync.""" with self._lock: - decrypted = self._manager.vault.encryption_manager.decrypt_data(data) + decrypted = self._manager.vault.encryption_manager.decrypt_data( + data, context="profile" + ) index = json.loads(decrypted.decode("utf-8")) self._manager.vault.save_index(index) self._manager.sync_vault() @@ -263,13 +265,13 @@ class EntryService: def list_entries( self, sort_by: str = "index", - filter_kind: str | None = None, + filter_kinds: list[str] | None = None, include_archived: bool = False, ): with self._lock: return self._manager.entry_manager.list_entries( sort_by=sort_by, - filter_kind=filter_kind, + filter_kinds=filter_kinds, include_archived=include_archived, ) @@ -303,9 +305,10 @@ class EntryService: def get_totp_code(self, entry_id: int) -> str: with self._lock: - return self._manager.entry_manager.get_totp_code( - entry_id, self._manager.parent_seed + key = getattr(self._manager, "KEY_TOTP_DET", None) or getattr( + self._manager, "parent_seed", None ) + return self._manager.entry_manager.get_totp_code(entry_id, key) def get_totp_secret(self, entry_id: int) -> str: """Return the TOTP secret (base32) for the given entry.""" @@ -367,15 +370,18 @@ class EntryService: secret: str | None = None, period: int = 30, digits: int = 6, + deterministic: bool = False, ) -> str: with self._lock: + key = self._manager.KEY_TOTP_DET if deterministic else None uri = self._manager.entry_manager.add_totp( label, - self._manager.parent_seed, + key, index=index, secret=secret, period=period, digits=digits, + deterministic=deterministic, ) self._manager.start_background_vault_sync() return uri @@ -520,9 +526,10 @@ class EntryService: def export_totp_entries(self) -> dict: with self._lock: - return self._manager.entry_manager.export_totp_entries( - self._manager.parent_seed + key = getattr(self._manager, "KEY_TOTP_DET", None) or getattr( + self._manager, "parent_seed", None ) + return self._manager.entry_manager.export_totp_entries(key) def display_totp_codes(self) -> None: with self._lock: diff --git a/src/seedpass/core/backup.py b/src/seedpass/core/backup.py index 3431051b..1cb3107c 100644 --- a/src/seedpass/core/backup.py +++ b/src/seedpass/core/backup.py @@ -15,7 +15,6 @@ import logging import os import shutil import time -import traceback from pathlib import Path from termcolor import colored @@ -146,6 +145,28 @@ class BackupManager: ) ) + def restore_from_backup(self, backup_path: str) -> None: + """Restore the index file from a user-specified backup path.""" + try: + src = Path(backup_path) + if not src.exists(): + logger.error(f"Backup file '{src}' does not exist.") + print(colored(f"Error: Backup file '{src}' does not exist.", "red")) + return + shutil.copy2(src, self.index_file) + os.chmod(self.index_file, 0o600) + logger.info(f"Index file restored from backup '{src}'.") + print(colored(f"[+] Index file restored from backup '{src}'.", "green")) + except Exception as e: + logger.error( + f"Failed to restore from backup '{backup_path}': {e}", exc_info=True + ) + print( + colored( + f"Error: Failed to restore from backup '{backup_path}': {e}", "red" + ) + ) + def list_backups(self) -> None: try: backup_files = sorted( diff --git a/src/seedpass/core/config_manager.py b/src/seedpass/core/config_manager.py index 31b469c5..f02e6a77 100644 --- a/src/seedpass/core/config_manager.py +++ b/src/seedpass/core/config_manager.py @@ -4,7 +4,7 @@ from __future__ import annotations import logging from pathlib import Path -from typing import List, Optional +from typing import List, Optional, TYPE_CHECKING from utils.seed_prompt import masked_input @@ -15,6 +15,9 @@ from nostr.client import DEFAULT_RELAYS as DEFAULT_NOSTR_RELAYS from constants import INACTIVITY_TIMEOUT, MAX_RETRIES, RETRY_DELAY +if TYPE_CHECKING: + from .password_generation import PasswordPolicy + logger = logging.getLogger(__name__) @@ -41,17 +44,18 @@ class ConfigManager: logger.info("Config file not found; returning defaults") return { "relays": list(DEFAULT_NOSTR_RELAYS), - "offline_mode": False, + "offline_mode": True, "pin_hash": "", "password_hash": "", "inactivity_timeout": INACTIVITY_TIMEOUT, "kdf_iterations": 50_000, "kdf_mode": "pbkdf2", + "argon2_time_cost": 2, "additional_backup_path": "", "backup_interval": 0, "secret_mode_enabled": False, "clipboard_clear_delay": 45, - "quick_unlock": False, + "quick_unlock_enabled": False, "nostr_max_retries": MAX_RETRIES, "nostr_retry_delay": float(RETRY_DELAY), "min_uppercase": 2, @@ -70,17 +74,18 @@ class ConfigManager: raise ValueError("Config data must be a dictionary") # Ensure defaults for missing keys data.setdefault("relays", list(DEFAULT_NOSTR_RELAYS)) - data.setdefault("offline_mode", False) + data.setdefault("offline_mode", True) data.setdefault("pin_hash", "") data.setdefault("password_hash", "") data.setdefault("inactivity_timeout", INACTIVITY_TIMEOUT) data.setdefault("kdf_iterations", 50_000) data.setdefault("kdf_mode", "pbkdf2") + data.setdefault("argon2_time_cost", 2) data.setdefault("additional_backup_path", "") data.setdefault("backup_interval", 0) data.setdefault("secret_mode_enabled", False) data.setdefault("clipboard_clear_delay", 45) - data.setdefault("quick_unlock", False) + data.setdefault("quick_unlock_enabled", data.get("quick_unlock", False)) data.setdefault("nostr_max_retries", MAX_RETRIES) data.setdefault("nostr_retry_delay", float(RETRY_DELAY)) data.setdefault("min_uppercase", 2) @@ -196,6 +201,19 @@ class ConfigManager: config = self.load_config(require_pin=False) return config.get("kdf_mode", "pbkdf2") + def set_argon2_time_cost(self, time_cost: int) -> None: + """Persist the Argon2 ``time_cost`` parameter.""" + if time_cost <= 0: + raise ValueError("time_cost must be positive") + config = self.load_config(require_pin=False) + config["argon2_time_cost"] = int(time_cost) + self.save_config(config) + + def get_argon2_time_cost(self) -> int: + """Retrieve the Argon2 ``time_cost`` setting.""" + config = self.load_config(require_pin=False) + return int(config.get("argon2_time_cost", 2)) + def set_additional_backup_path(self, path: Optional[str]) -> None: """Persist an optional additional backup path in the config.""" config = self.load_config(require_pin=False) @@ -228,7 +246,7 @@ class ConfigManager: def get_offline_mode(self) -> bool: """Retrieve the offline mode setting.""" config = self.load_config(require_pin=False) - return bool(config.get("offline_mode", False)) + return bool(config.get("offline_mode", True)) def set_clipboard_clear_delay(self, delay: int) -> None: """Persist clipboard clear timeout in seconds.""" @@ -320,13 +338,13 @@ class ConfigManager: def set_quick_unlock(self, enabled: bool) -> None: """Persist the quick unlock toggle.""" cfg = self.load_config(require_pin=False) - cfg["quick_unlock"] = bool(enabled) + cfg["quick_unlock_enabled"] = bool(enabled) self.save_config(cfg) def get_quick_unlock(self) -> bool: """Retrieve whether quick unlock is enabled.""" cfg = self.load_config(require_pin=False) - return bool(cfg.get("quick_unlock", False)) + return bool(cfg.get("quick_unlock_enabled", False)) def set_nostr_max_retries(self, retries: int) -> None: """Persist the maximum number of Nostr retry attempts.""" diff --git a/src/seedpass/core/encryption.py b/src/seedpass/core/encryption.py index 70408b2e..9e33d26a 100644 --- a/src/seedpass/core/encryption.py +++ b/src/seedpass/core/encryption.py @@ -1,12 +1,12 @@ # /src/seedpass.core/encryption.py import logging -import traceback +import unicodedata try: import orjson as json_lib # type: ignore - JSONDecodeError = orjson.JSONDecodeError + JSONDecodeError = json_lib.JSONDecodeError USE_ORJSON = True except Exception: # pragma: no cover - fallback for environments without orjson import json as json_lib @@ -16,39 +16,41 @@ except Exception: # pragma: no cover - fallback for environments without orjson import hashlib import os import base64 +import zlib +from dataclasses import asdict from pathlib import Path -from typing import Optional +from typing import Optional, Tuple from cryptography.hazmat.primitives.ciphers.aead import AESGCM from cryptography.exceptions import InvalidTag from cryptography.fernet import Fernet, InvalidToken from termcolor import colored from utils.file_lock import exclusive_lock +from mnemonic import Mnemonic +from utils.password_prompt import prompt_existing_password +from utils.key_derivation import KdfConfig, CURRENT_KDF_VERSION +from .errors import DecryptionError # Instantiate the logger logger = logging.getLogger(__name__) -def get_salt_from_parent_seed_file(file_path: Path) -> bytes: - """ - Reads the salt from the parent seed file if it exists and uses the V3 format. +def _derive_legacy_key_from_password(password: str, iterations: int = 100_000) -> bytes: + """Derive legacy Fernet key using password only (no fingerprint).""" + normalized = unicodedata.normalize("NFKD", password).strip().encode("utf-8") + key = hashlib.pbkdf2_hmac("sha256", normalized, b"", iterations, dklen=32) + return base64.urlsafe_b64encode(key) - Parameters: - file_path (Path): The path to the parent seed file. - Returns: - bytes: The 16-byte salt if found, otherwise an empty bytes object. - """ - if not file_path.exists(): - return b"" - try: - with open(file_path, "rb") as f: - header = f.read(3) - if header == b"V3:": - return f.read(16) - except Exception as e: - logger.warning(f"Failed to read salt from {file_path}: {e}") - return b"" +class LegacyFormatRequiresMigrationError(Exception): + """Raised when legacy-encrypted data needs user-guided migration.""" + + def __init__(self, context: Optional[str] = None) -> None: + msg = ( + f"Legacy data detected for {context}" if context else "Legacy data detected" + ) + super().__init__(msg) + self.context = context class EncryptionManager: @@ -88,46 +90,94 @@ class EncryptionManager: ) raise + # Track user preference for handling legacy indexes + self._legacy_migrate_flag = True + self.last_migration_performed = False + # Track nonces to detect accidental reuse + self.nonce_crc_table: set[int] = set() + def encrypt_data(self, data: bytes) -> bytes: """ - (2) Encrypts data using the NEW AES-GCM format, prepending a version - header and the nonce. All new data will be in this format. + Encrypt data using AES-GCM, emitting ``b"V3|" + nonce + ciphertext + tag``. + A fresh 96-bit nonce is generated for each call and tracked via a CRC + table to detect accidental reuse during batch operations. """ try: nonce = os.urandom(12) # 96-bit nonce is recommended for AES-GCM + crc = zlib.crc32(nonce) + if crc in self.nonce_crc_table: + raise ValueError("Nonce reuse detected") + self.nonce_crc_table.add(crc) ciphertext = self.cipher.encrypt(nonce, data, None) - return b"V2:" + nonce + ciphertext + return b"V3|" + nonce + ciphertext except Exception as e: logger.error(f"Failed to encrypt data: {e}", exc_info=True) raise - def decrypt_data(self, encrypted_data: bytes) -> bytes: - """ - (3) The core migration logic. Tries the new format first, then falls back - to the old one. This is the ONLY place decryption logic should live. - """ - # Try the new V2 format first - if encrypted_data.startswith(b"V2:"): - try: - nonce = encrypted_data[3:15] - ciphertext = encrypted_data[15:] - if len(ciphertext) < 16: - logger.error("AES-GCM payload too short") - raise InvalidToken("AES-GCM payload too short") - return self.cipher.decrypt(nonce, ciphertext, None) - except InvalidTag as e: - logger.error("AES-GCM decryption failed: Invalid authentication tag.") - try: - result = self.fernet.decrypt(encrypted_data[3:]) - logger.warning( - "Legacy-format file had incorrect 'V2:' header; decrypted with Fernet" - ) - return result - except InvalidToken: - raise InvalidToken("AES-GCM decryption failed.") from e + def decrypt_data( + self, encrypted_data: bytes, context: Optional[str] = None + ) -> bytes: + """Decrypt ``encrypted_data`` handling legacy fallbacks. - # If it's not V2, it must be the legacy Fernet format - else: + Parameters + ---------- + encrypted_data: + The bytes to decrypt. + context: + Optional string describing what is being decrypted ("seed", "index", etc.) + for clearer error messages. + """ + + ctx = f" {context}" if context else "" + + try: + # Try the new V3 format first + if encrypted_data.startswith(b"V3|"): + try: + nonce = encrypted_data[3:15] + ciphertext = encrypted_data[15:] + if len(ciphertext) < 16: + logger.error("AES-GCM payload too short") + raise DecryptionError( + f"Failed to decrypt{ctx}: AES-GCM payload too short" + ) + return self.cipher.decrypt(nonce, ciphertext, None) + except InvalidTag as e: + logger.error(f"Failed to decrypt{ctx}: invalid key or corrupt file") + raise DecryptionError( + f"Failed to decrypt{ctx}: invalid key or corrupt file" + ) from e + + # Next try the older V2 format + if encrypted_data.startswith(b"V2:"): + try: + nonce = encrypted_data[3:15] + ciphertext = encrypted_data[15:] + if len(ciphertext) < 16: + logger.error("AES-GCM payload too short") + raise DecryptionError( + f"Failed to decrypt{ctx}: AES-GCM payload too short" + ) + return self.cipher.decrypt(nonce, ciphertext, None) + except InvalidTag as e: + logger.debug( + "AES-GCM decryption failed: Invalid authentication tag." + ) + try: + result = self.fernet.decrypt(encrypted_data[3:]) + logger.warning( + "Legacy-format file had incorrect 'V2:' header; decrypted with Fernet" + ) + return result + except InvalidToken: + logger.error( + f"Failed to decrypt{ctx}: invalid key or corrupt file" + ) + raise DecryptionError( + f"Failed to decrypt{ctx}: invalid key or corrupt file" + ) from e + + # If it's neither V3 nor V2, assume legacy Fernet format logger.warning("Data is in legacy Fernet format. Attempting migration.") try: return self.fernet.decrypt(encrypted_data) @@ -135,136 +185,262 @@ class EncryptionManager: logger.error( "Legacy Fernet decryption failed. Vault may be corrupt or key is incorrect." ) - raise InvalidToken( - "Could not decrypt data with any available method." + raise DecryptionError( + f"Failed to decrypt{ctx}: invalid key or corrupt file" ) from e + except DecryptionError as e: + if ( + encrypted_data.startswith(b"V3|") + or encrypted_data.startswith(b"V2:") + or not self._legacy_migrate_flag + ): + raise + logger.debug(f"Could not decrypt data{ctx}: {e}") + raise LegacyFormatRequiresMigrationError(context) from e + except (InvalidToken, InvalidTag) as e: # pragma: no cover - safety net + raise DecryptionError( + f"Failed to decrypt{ctx}: invalid key or corrupt file" + ) from e + + def decrypt_legacy( + self, encrypted_data: bytes, password: str, context: Optional[str] = None + ) -> bytes: + """Decrypt ``encrypted_data`` using legacy password-only key derivation.""" + + ctx = f" {context}" if context else "" + last_exc: Optional[Exception] = None + for iter_count in [50_000, 100_000]: + try: + legacy_key = _derive_legacy_key_from_password( + password, iterations=iter_count + ) + legacy_mgr = EncryptionManager(legacy_key, self.fingerprint_dir) + legacy_mgr._legacy_migrate_flag = False + result = legacy_mgr.decrypt_data(encrypted_data, context=context) + try: # record iteration count for future runs + from .vault import Vault + from .config_manager import ConfigManager + + cfg_mgr = ConfigManager( + Vault(self, self.fingerprint_dir), self.fingerprint_dir + ) + cfg_mgr.set_kdf_iterations(iter_count) + except Exception: # pragma: no cover - best effort + logger.error( + "Failed to record PBKDF2 iteration count in config", + exc_info=True, + ) + logger.warning( + "Data decrypted using legacy password-only key derivation." + ) + return result + except Exception as e2: # pragma: no cover - try next iteration + last_exc = e2 + logger.error(f"Failed legacy decryption attempt: {last_exc}", exc_info=True) + raise DecryptionError( + f"Failed to decrypt{ctx}: invalid key or corrupt file" + ) from last_exc + # --- All functions below this point now use the smart `decrypt_data` method --- - def encrypt_parent_seed(self, parent_seed: str, salt: bytes = b"") -> None: + def resolve_relative_path(self, relative_path: Path) -> Path: + """Resolve ``relative_path`` within ``fingerprint_dir`` and validate it. + + Parameters + ---------- + relative_path: + The user-supplied path relative to ``fingerprint_dir``. + + Returns + ------- + Path + The normalized absolute path inside ``fingerprint_dir``. + + Raises + ------ + ValueError + If the resulting path is absolute or escapes ``fingerprint_dir``. + """ + + candidate = (self.fingerprint_dir / relative_path).resolve() + if not candidate.is_relative_to(self.fingerprint_dir.resolve()): + raise ValueError("Invalid path outside fingerprint directory") + return candidate + + def encrypt_parent_seed( + self, parent_seed: str, kdf: Optional[KdfConfig] = None + ) -> None: """Encrypts and saves the parent seed to 'parent_seed.enc'.""" data = parent_seed.encode("utf-8") - - if salt: - # V3 format: V3: - try: - nonce = os.urandom(12) - ciphertext = self.cipher.encrypt(nonce, data, None) - encrypted_data = b"V3:" + salt + nonce + ciphertext - except Exception as e: - logger.error(f"Failed to encrypt parent seed with V3 format: {e}", exc_info=True) - raise - else: - # Fallback to V2 (no salt stored) or use encrypt_data - encrypted_data = self.encrypt_data(data) # This creates V2 format - - with exclusive_lock(self.parent_seed_file) as fh: - fh.seek(0) - fh.truncate() - fh.write(encrypted_data) - os.chmod(self.parent_seed_file, 0o600) + self.encrypt_and_save_file(data, self.parent_seed_file, kdf=kdf) logger.info(f"Parent seed encrypted and saved to '{self.parent_seed_file}'.") def decrypt_parent_seed(self) -> str: """Decrypts and returns the parent seed, handling migration.""" with exclusive_lock(self.parent_seed_file) as fh: fh.seek(0) - encrypted_data = fh.read() + blob = fh.read() - if encrypted_data.startswith(b"V3:"): - # V3 format: V3: - try: - # Salt is used for key derivation externally, so we skip it here - nonce = encrypted_data[19:31] - ciphertext = encrypted_data[31:] - if len(ciphertext) < 16: - raise InvalidToken("AES-GCM payload too short") - decrypted_data = self.cipher.decrypt(nonce, ciphertext, None) - return decrypted_data.decode("utf-8").strip() - except InvalidTag as e: - logger.error("AES-GCM decryption failed for V3 parent seed.") - raise InvalidToken("AES-GCM decryption failed.") from e - - is_legacy = not encrypted_data.startswith(b"V2:") - decrypted_data = self.decrypt_data(encrypted_data) + kdf, encrypted_data = self._deserialize(blob) + is_legacy = not ( + encrypted_data.startswith(b"V3|") or encrypted_data.startswith(b"V2:") + ) + decrypted_data = self.decrypt_data(encrypted_data, context="seed") if is_legacy: - logger.info("Parent seed was in legacy format. Re-encrypting to V2 format.") - self.encrypt_parent_seed(decrypted_data.decode("utf-8").strip()) + logger.info("Parent seed was in legacy format. Re-encrypting to V3 format.") + self.encrypt_parent_seed(decrypted_data.decode("utf-8").strip(), kdf=kdf) return decrypted_data.decode("utf-8").strip() - def encrypt_and_save_file(self, data: bytes, relative_path: Path) -> None: - file_path = self.fingerprint_dir / relative_path + def _serialize(self, kdf: KdfConfig, ciphertext: bytes) -> bytes: + payload = {"kdf": asdict(kdf), "ct": base64.b64encode(ciphertext).decode()} + if USE_ORJSON: + return json_lib.dumps(payload) + return json_lib.dumps(payload, separators=(",", ":")).encode("utf-8") + + def _deserialize(self, blob: bytes) -> Tuple[KdfConfig, bytes]: + """Return ``(KdfConfig, ciphertext)`` from serialized *blob*. + + Legacy files stored the raw ciphertext without a JSON wrapper. If + decoding the wrapper fails, treat ``blob`` as the ciphertext and return + a default HKDF configuration. + """ + + try: + if USE_ORJSON: + obj = json_lib.loads(blob) + else: + obj = json_lib.loads(blob.decode("utf-8")) + kdf = KdfConfig(**obj.get("kdf", {})) + ct_b64 = obj.get("ct", "") + ciphertext = base64.b64decode(ct_b64) + if ciphertext: + return kdf, ciphertext + except Exception: # pragma: no cover - fall back to legacy path + pass + + # Legacy format: ``blob`` already contains the ciphertext + return ( + KdfConfig(name="hkdf", version=CURRENT_KDF_VERSION, params={}, salt_b64=""), + blob, + ) + + def encrypt_and_save_file( + self, data: bytes, relative_path: Path, *, kdf: Optional[KdfConfig] = None + ) -> None: + if kdf is None: + kdf = KdfConfig() + file_path = self.resolve_relative_path(relative_path) file_path.parent.mkdir(parents=True, exist_ok=True) encrypted_data = self.encrypt_data(data) + payload = self._serialize(kdf, encrypted_data) with exclusive_lock(file_path) as fh: fh.seek(0) fh.truncate() - fh.write(encrypted_data) + fh.write(payload) fh.flush() os.fsync(fh.fileno()) os.chmod(file_path, 0o600) def decrypt_file(self, relative_path: Path) -> bytes: - file_path = self.fingerprint_dir / relative_path + file_path = self.resolve_relative_path(relative_path) with exclusive_lock(file_path) as fh: fh.seek(0) - encrypted_data = fh.read() - return self.decrypt_data(encrypted_data) + blob = fh.read() + _, encrypted_data = self._deserialize(blob) + return self.decrypt_data(encrypted_data, context=str(relative_path)) - def save_json_data(self, data: dict, relative_path: Optional[Path] = None) -> None: + def get_file_kdf(self, relative_path: Path) -> KdfConfig: + file_path = self.resolve_relative_path(relative_path) + with exclusive_lock(file_path) as fh: + fh.seek(0) + blob = fh.read() + kdf, _ = self._deserialize(blob) + return kdf + + def save_json_data( + self, + data: dict, + relative_path: Optional[Path] = None, + *, + kdf: Optional[KdfConfig] = None, + ) -> None: if relative_path is None: relative_path = Path("seedpass_entries_db.json.enc") if USE_ORJSON: json_data = json_lib.dumps(data) else: json_data = json_lib.dumps(data, separators=(",", ":")).encode("utf-8") - self.encrypt_and_save_file(json_data, relative_path) + self.encrypt_and_save_file(json_data, relative_path, kdf=kdf) logger.debug(f"JSON data encrypted and saved to '{relative_path}'.") - def load_json_data(self, relative_path: Optional[Path] = None) -> dict: + def load_json_data( + self, relative_path: Optional[Path] = None, *, return_kdf: bool = False + ) -> dict | Tuple[dict, KdfConfig]: """ Loads and decrypts JSON data, automatically migrating and re-saving if it's in the legacy format. """ if relative_path is None: relative_path = Path("seedpass_entries_db.json.enc") - - file_path = self.fingerprint_dir / relative_path + file_path = self.resolve_relative_path(relative_path) if not file_path.exists(): - return {"entries": {}} + empty: dict = {"entries": {}} + if return_kdf: + return empty, KdfConfig( + name="hkdf", version=CURRENT_KDF_VERSION, params={}, salt_b64="" + ) + return empty with exclusive_lock(file_path) as fh: fh.seek(0) - encrypted_data = fh.read() + blob = fh.read() - is_legacy = not encrypted_data.startswith(b"V2:") + kdf, encrypted_data = self._deserialize(blob) + is_legacy = not ( + encrypted_data.startswith(b"V3|") or encrypted_data.startswith(b"V2:") + ) + self.last_migration_performed = False try: - decrypted_data = self.decrypt_data(encrypted_data) + decrypted_data = self.decrypt_data( + encrypted_data, context=str(relative_path) + ) if USE_ORJSON: data = json_lib.loads(decrypted_data) else: data = json_lib.loads(decrypted_data.decode("utf-8")) # If it was a legacy file, re-save it in the new format now - if is_legacy: + if is_legacy and self._legacy_migrate_flag: logger.info(f"Migrating and re-saving legacy vault file: {file_path}") - self.save_json_data(data, relative_path) + self.save_json_data(data, relative_path, kdf=kdf) self.update_checksum(relative_path) + self.last_migration_performed = True + if return_kdf: + return data, kdf return data - except (InvalidToken, InvalidTag, JSONDecodeError) as e: - logger.error( - f"FATAL: Could not decrypt or parse data from {file_path}: {e}", - exc_info=True, - ) + except DecryptionError as e: + msg = f"Failed to decrypt or parse data from {file_path}: {e}" + logger.error(msg) + raise + except (InvalidToken, InvalidTag) as e: # pragma: no cover - legacy safety + msg = f"Failed to decrypt or parse data from {file_path}: {e}" + logger.error(msg) + raise DecryptionError( + f"Failed to decrypt {file_path}: invalid key or corrupt file" + ) from e + except JSONDecodeError as e: + msg = f"Failed to parse JSON data from {file_path}: {e}" + logger.error(msg) raise def get_encrypted_index(self) -> Optional[bytes]: relative_path = Path("seedpass_entries_db.json.enc") - file_path = self.fingerprint_dir / relative_path + file_path = self.resolve_relative_path(relative_path) if not file_path.exists(): return None with exclusive_lock(file_path) as fh: @@ -293,13 +469,18 @@ class EncryptionManager: """ if relative_path is None: relative_path = Path("seedpass_entries_db.json.enc") - try: - decrypted_data = self.decrypt_data(encrypted_data) + + kdf, ciphertext = self._deserialize(encrypted_data) + is_legacy = not (ciphertext.startswith(b"V3|") or ciphertext.startswith(b"V2:")) + self.last_migration_performed = False + + def _process(decrypted: bytes) -> dict: if USE_ORJSON: - data = json_lib.loads(decrypted_data) + data = json_lib.loads(decrypted) else: - data = json_lib.loads(decrypted_data.decode("utf-8")) - if merge and (self.fingerprint_dir / relative_path).exists(): + data = json_lib.loads(decrypted.decode("utf-8")) + existing_file = self.resolve_relative_path(relative_path) + if merge and existing_file.exists(): current = self.load_json_data(relative_path) current_entries = current.get("entries", {}) for idx, entry in data.get("entries", {}).items(): @@ -313,11 +494,53 @@ class EncryptionManager: current.get("schema_version", 0), data.get("schema_version", 0) ) data = current - self.save_json_data(data, relative_path) # This always saves in V2 format + return data + + try: + decrypted_data = self.decrypt_data(ciphertext, context=str(relative_path)) + data = _process(decrypted_data) + self.save_json_data(data, relative_path, kdf=kdf) self.update_checksum(relative_path) logger.info("Index file from Nostr was processed and saved successfully.") - print(colored("Index file updated from Nostr successfully.", "green")) + self.last_migration_performed = is_legacy return True + except (DecryptionError, LegacyFormatRequiresMigrationError): + try: + password = prompt_existing_password( + "Enter your master password for legacy decryption: " + ) + decrypted_data = self.decrypt_legacy( + ciphertext, password, context=str(relative_path) + ) + data = _process(decrypted_data) + self.save_json_data(data, relative_path, kdf=kdf) + self.update_checksum(relative_path) + logger.warning( + "Index decrypted using legacy password-only key derivation." + ) + print( + colored( + "Warning: index decrypted with legacy key; it will be re-encrypted.", + "yellow", + ) + ) + self.last_migration_performed = True + return True + except Exception as e2: + if strict: + logger.error( + f"Failed legacy decryption attempt: {e2}", + exc_info=True, + ) + print( + colored( + f"Error: Failed to decrypt and save data from Nostr: {e2}", + "red", + ) + ) + raise + logger.warning(f"Failed to decrypt index from Nostr: {e2}") + return False except Exception as e: # pragma: no cover - error handling if strict: logger.error( @@ -338,8 +561,7 @@ class EncryptionManager: """Updates the checksum file for the specified file.""" if relative_path is None: relative_path = Path("seedpass_entries_db.json.enc") - - file_path = self.fingerprint_dir / relative_path + file_path = self.resolve_relative_path(relative_path) if not file_path.exists(): return @@ -348,7 +570,22 @@ class EncryptionManager: fh.seek(0) encrypted_bytes = fh.read() checksum = hashlib.sha256(encrypted_bytes).hexdigest() - checksum_file = file_path.parent / f"{file_path.stem}_checksum.txt" + + # Build checksum path by stripping both `.json` and `.enc` + checksum_base = file_path.with_suffix("").with_suffix("") + checksum_file = checksum_base.parent / f"{checksum_base.name}_checksum.txt" + + # Remove legacy checksum file if present + legacy_checksum = file_path.parent / f"{file_path.stem}_checksum.txt" + if legacy_checksum != checksum_file and legacy_checksum.exists(): + try: + legacy_checksum.unlink() + except Exception: + logger.warning( + f"Could not remove legacy checksum file '{legacy_checksum}'", + exc_info=True, + ) + with exclusive_lock(checksum_file) as fh: fh.seek(0) fh.truncate() @@ -363,25 +600,21 @@ class EncryptionManager: ) raise - # ... validate_seed and derive_seed_from_mnemonic can remain the same ... - def validate_seed(self, seed_phrase: str) -> bool: + def validate_seed(self, seed_phrase: str) -> tuple[bool, Optional[str]]: + """Validate a BIP-39 mnemonic. + + Returns a tuple of ``(is_valid, error_message)`` where ``error_message`` + is ``None`` when the mnemonic is valid. + """ try: - words = seed_phrase.split() - if len(words) != 12: - logger.error("Seed phrase does not contain exactly 12 words.") - print( - colored( - "Error: Seed phrase must contain exactly 12 words.", - "red", - ) - ) - return False - logger.debug("Seed phrase validated successfully.") - return True + if Mnemonic("english").check(seed_phrase): + logger.debug("Seed phrase validated successfully.") + return True, None + logger.error("Seed phrase failed BIP-39 validation.") + return False, "Invalid seed phrase." except Exception as e: - logging.error(f"Error validating seed phrase: {e}", exc_info=True) - print(colored(f"Error: Failed to validate seed phrase: {e}", "red")) - return False + logger.error(f"Error validating seed phrase: {e}", exc_info=True) + return False, f"Failed to validate seed phrase: {e}" def derive_seed_from_mnemonic(self, mnemonic: str, passphrase: str = "") -> bytes: try: diff --git a/src/seedpass/core/entry_management.py b/src/seedpass/core/entry_management.py index a6de693f..d9ae24be 100644 --- a/src/seedpass/core/entry_management.py +++ b/src/seedpass/core/entry_management.py @@ -15,9 +15,16 @@ completely deterministic passwords from a BIP-85 seed, ensuring that passwords a the same way every time. Salts would break this functionality and are not suitable for this software. """ +try: + import orjson as json_lib # type: ignore + + USE_ORJSON = True +except Exception: # pragma: no cover - fallback when orjson is missing + import json as json_lib + + USE_ORJSON = False import logging import hashlib -import sys import shutil import time from typing import Optional, Tuple, Dict, Any, List @@ -25,10 +32,11 @@ from pathlib import Path from termcolor import colored from .migrations import LATEST_VERSION -from .entry_types import EntryType -from .totp import TotpManager +from .entry_types import EntryType, ALL_ENTRY_TYPES +from .totp import TotpManager, random_totp_secret from utils.fingerprint import generate_fingerprint from utils.checksum import canonical_json_dumps +from utils.atomic_write import atomic_write from utils.key_validation import ( validate_totp_secret, validate_ssh_key_pair, @@ -39,6 +47,7 @@ from utils.key_validation import ( from .vault import Vault from .backup import BackupManager +from .errors import SeedPassError # Instantiate the logger logger = logging.getLogger(__name__) @@ -138,7 +147,7 @@ class EntryManager: except Exception as e: logger.error(f"Error determining next index: {e}", exc_info=True) print(colored(f"Error determining next index: {e}", "red")) - sys.exit(1) + raise SeedPassError(f"Error determining next index: {e}") from e def add_entry( self, @@ -212,7 +221,9 @@ class EntryManager: data["entries"][str(index)] = entry - logger.debug(f"Added entry at index {index}: {data['entries'][str(index)]}") + logger.debug( + f"Added entry at index {index} with label '{entry.get('label', '')}'." + ) self._save_index(data) self.update_checksum() @@ -226,7 +237,7 @@ class EntryManager: except Exception as e: logger.error(f"Failed to add entry: {e}", exc_info=True) print(colored(f"Error: Failed to add entry: {e}", "red")) - sys.exit(1) + raise SeedPassError(f"Failed to add entry: {e}") from e def get_next_totp_index(self) -> int: """Return the next available derivation index for TOTP secrets.""" @@ -245,7 +256,7 @@ class EntryManager: def add_totp( self, label: str, - parent_seed: str, + parent_seed: str | bytes | None = None, *, archived: bool = False, secret: str | None = None, @@ -254,13 +265,16 @@ class EntryManager: digits: int = 6, notes: str = "", tags: list[str] | None = None, + deterministic: bool = False, ) -> str: """Add a new TOTP entry and return the provisioning URI.""" entry_id = self.get_next_index() data = self._load_index() data.setdefault("entries", {}) - if secret is None: + if deterministic: + if parent_seed is None: + raise ValueError("Seed required for deterministic TOTP") if index is None: index = self.get_next_totp_index() secret = TotpManager.derive_secret(parent_seed, index) @@ -277,8 +291,11 @@ class EntryManager: "archived": archived, "notes": notes, "tags": tags or [], + "deterministic": True, } else: + if secret is None: + secret = random_totp_secret() if not validate_totp_secret(secret): raise ValueError("Invalid TOTP secret") entry = { @@ -292,6 +309,7 @@ class EntryManager: "archived": archived, "notes": notes, "tags": tags or [], + "deterministic": False, } data["entries"][str(entry_id)] = entry @@ -449,7 +467,7 @@ class EntryManager: seed_bytes = Bip39SeedGenerator(parent_seed).Generate() bip85 = BIP85(seed_bytes) - entropy = bip85.derive_entropy(index=index, bytes_len=32) + entropy = bip85.derive_entropy(index=index, entropy_bytes=32) keys = Keys(priv_k=entropy.hex()) npub = Keys.hex_to_bech32(keys.public_key_hex(), "npub") nsec = Keys.hex_to_bech32(keys.private_key_hex(), "nsec") @@ -527,7 +545,7 @@ class EntryManager: bip85 = BIP85(seed_bytes) key_idx = int(entry.get("index", index)) - entropy = bip85.derive_entropy(index=key_idx, bytes_len=32) + entropy = bip85.derive_entropy(index=key_idx, entropy_bytes=32) keys = Keys(priv_k=entropy.hex()) npub = Keys.hex_to_bech32(keys.public_key_hex(), "npub") nsec = Keys.hex_to_bech32(keys.private_key_hex(), "nsec") @@ -676,12 +694,12 @@ class EntryManager: seed_index = int(entry.get("index", index)) return derive_seed_phrase(bip85, seed_index, words) - def get_totp_secret(self, index: int, parent_seed: str | None = None) -> str: - """Return the TOTP secret for the specified entry. - - If the entry uses an imported secret, it is returned directly. - If the entry uses a derived secret, it is derived from the parent seed. - """ + def get_totp_secret( + self, + index: int, + parent_seed: str | bytes | None = None, + ) -> str: + """Return the TOTP secret for the specified entry.""" entry = self.retrieve_entry(index) etype = entry.get("type") if entry else None kind = entry.get("kind") if entry else None @@ -689,18 +707,18 @@ class EntryManager: etype != EntryType.TOTP.value and kind != EntryType.TOTP.value ): raise ValueError("Entry is not a TOTP entry") - - if "secret" in entry: - return entry["secret"] - - if parent_seed is None: - raise ValueError("Seed required for derived TOTP") - - totp_index = int(entry.get("index", 0)) - return TotpManager.derive_secret(parent_seed, totp_index) + if entry.get("deterministic", False) or "secret" not in entry: + if parent_seed is None: + raise ValueError("Seed required for derived TOTP") + totp_index = int(entry.get("index", 0)) + return TotpManager.derive_secret(parent_seed, totp_index) + return entry["secret"] def get_totp_code( - self, index: int, parent_seed: str | None = None, timestamp: int | None = None + self, + index: int, + parent_seed: str | bytes | None = None, + timestamp: int | None = None, ) -> str: """Return the current TOTP code for the specified entry.""" entry = self.retrieve_entry(index) @@ -710,12 +728,12 @@ class EntryManager: etype != EntryType.TOTP.value and kind != EntryType.TOTP.value ): raise ValueError("Entry is not a TOTP entry") - if "secret" in entry: - return TotpManager.current_code_from_secret(entry["secret"], timestamp) - if parent_seed is None: - raise ValueError("Seed required for derived TOTP") - totp_index = int(entry.get("index", 0)) - return TotpManager.current_code(parent_seed, totp_index, timestamp) + if entry.get("deterministic", False) or "secret" not in entry: + if parent_seed is None: + raise ValueError("Seed required for derived TOTP") + totp_index = int(entry.get("index", 0)) + return TotpManager.current_code(parent_seed, totp_index, timestamp) + return TotpManager.current_code_from_secret(entry["secret"], timestamp) def get_totp_time_remaining(self, index: int) -> int: """Return seconds remaining in the TOTP period for the given entry.""" @@ -730,7 +748,9 @@ class EntryManager: period = int(entry.get("period", 30)) return TotpManager.time_remaining(period) - def export_totp_entries(self, parent_seed: str) -> dict[str, list[dict[str, Any]]]: + def export_totp_entries( + self, parent_seed: str | bytes | None + ) -> dict[str, list[dict[str, Any]]]: """Return all TOTP secrets and metadata for external use.""" data = self._load_index() entries = data.get("entries", {}) @@ -742,11 +762,13 @@ class EntryManager: label = entry.get("label", "") period = int(entry.get("period", 30)) digits = int(entry.get("digits", 6)) - if "secret" in entry: - secret = entry["secret"] - else: + if entry.get("deterministic", False) or "secret" not in entry: + if parent_seed is None: + raise ValueError("Seed required for deterministic TOTP export") idx = int(entry.get("index", 0)) secret = TotpManager.derive_secret(parent_seed, idx) + else: + secret = entry["secret"] uri = TotpManager.make_otpauth_uri(label, secret, period, digits) exported.append( { @@ -793,7 +815,9 @@ class EntryManager: EntryType.MANAGED_ACCOUNT.value, ): entry.setdefault("custom_fields", []) - logger.debug(f"Retrieved entry at index {index}: {entry}") + logger.debug( + f"Retrieved entry at index {index} with label '{entry.get('label', '')}'." + ) clean = {k: v for k, v in entry.items() if k != "modified_ts"} return clean else: @@ -1023,13 +1047,11 @@ class EntryManager: if custom_fields is not None: entry["custom_fields"] = custom_fields - logger.debug( - f"Updated custom fields for index {index}: {custom_fields}" - ) + logger.debug(f"Updated custom fields for index {index}.") if tags is not None: entry["tags"] = tags - logger.debug(f"Updated tags for index {index}: {tags}") + logger.debug(f"Updated tags for index {index}.") policy_updates: dict[str, Any] = {} if include_special_chars is not None: @@ -1056,7 +1078,9 @@ class EntryManager: entry["modified_ts"] = int(time.time()) data["entries"][str(index)] = entry - logger.debug(f"Modified entry at index {index}: {entry}") + logger.debug( + f"Modified entry at index {index} with label '{entry.get('label', '')}'." + ) self._save_index(data) self.update_checksum() @@ -1085,7 +1109,7 @@ class EntryManager: def list_entries( self, sort_by: str = "index", - filter_kind: str | None = None, + filter_kinds: list[str] | None = None, *, include_archived: bool = False, verbose: bool = True, @@ -1097,8 +1121,9 @@ class EntryManager: sort_by: Field to sort by. Supported values are ``"index"``, ``"label"`` and ``"updated"``. - filter_kind: - Optional entry kind to restrict the results. + filter_kinds: + Optional list of entry kinds to restrict the results. Defaults to + ``ALL_ENTRY_TYPES``. Archived entries are omitted unless ``include_archived`` is ``True``. """ @@ -1127,12 +1152,14 @@ class EntryManager: sorted_items = sorted(entries_data.items(), key=sort_key) + if filter_kinds is None: + filter_kinds = ALL_ENTRY_TYPES + filtered_items: List[Tuple[int, Dict[str, Any]]] = [] for idx_str, entry in sorted_items: if ( - filter_kind is not None - and entry.get("type", entry.get("kind", EntryType.PASSWORD.value)) - != filter_kind + entry.get("type", entry.get("kind", EntryType.PASSWORD.value)) + not in filter_kinds ): continue if not include_archived and entry.get( @@ -1326,8 +1353,7 @@ class EntryManager: # The checksum file path already includes the fingerprint directory checksum_path = self.checksum_file - with open(checksum_path, "w") as f: - f.write(checksum) + atomic_write(checksum_path, lambda f: f.write(checksum)) logger.debug(f"Checksum updated and written to '{checksum_path}'.") print(colored("[+] Checksum updated successfully.", "green")) @@ -1381,7 +1407,7 @@ class EntryManager: def list_all_entries( self, sort_by: str = "index", - filter_kind: str | None = None, + filter_kinds: list[str] | None = None, *, include_archived: bool = False, ) -> None: @@ -1389,7 +1415,7 @@ class EntryManager: try: entries = self.list_entries( sort_by=sort_by, - filter_kind=filter_kind, + filter_kinds=filter_kinds, include_archived=include_archived, ) if not entries: @@ -1413,7 +1439,7 @@ class EntryManager: def get_entry_summaries( self, - filter_kind: str | None = None, + filter_kinds: list[str] | None = None, *, include_archived: bool = False, ) -> list[tuple[int, str, str]]: @@ -1422,10 +1448,13 @@ class EntryManager: data = self._load_index() entries_data = data.get("entries", {}) + if filter_kinds is None: + filter_kinds = ALL_ENTRY_TYPES + summaries: list[tuple[int, str, str]] = [] for idx_str, entry in entries_data.items(): etype = entry.get("type", entry.get("kind", EntryType.PASSWORD.value)) - if filter_kind and etype != filter_kind: + if etype not in filter_kinds: continue if not include_archived and entry.get( "archived", entry.get("blacklisted", False) diff --git a/src/seedpass/core/entry_service.py b/src/seedpass/core/entry_service.py new file mode 100644 index 00000000..0e880280 --- /dev/null +++ b/src/seedpass/core/entry_service.py @@ -0,0 +1,242 @@ +from __future__ import annotations + +import logging +import time +from typing import TYPE_CHECKING + +from termcolor import colored + +from constants import ( + DEFAULT_PASSWORD_LENGTH, + MAX_PASSWORD_LENGTH, + MIN_PASSWORD_LENGTH, +) +import seedpass.core.manager as manager_module +from utils.terminal_utils import clear_header_with_notification, pause + +if TYPE_CHECKING: # pragma: no cover - typing only + from .manager import PasswordManager + + +class EntryService: + """Entry management operations for :class:`PasswordManager`.""" + + def __init__(self, manager: PasswordManager) -> None: + self.manager = manager + + def handle_add_password(self) -> None: + pm = self.manager + try: + fp, parent_fp, child_fp = pm.header_fingerprint_args + clear_header_with_notification( + pm, + fp, + "Main Menu > Add Entry > Password", + parent_fingerprint=parent_fp, + child_fingerprint=child_fp, + ) + + def prompt_length() -> int: + while True: + length_input = input( + f"Enter desired password length (default {DEFAULT_PASSWORD_LENGTH}): " + ).strip() + length = DEFAULT_PASSWORD_LENGTH + if length_input: + if not length_input.isdigit(): + print( + colored( + "Error: Password length must be a number.", "red" + ) + ) + continue + length = int(length_input) + if not (MIN_PASSWORD_LENGTH <= length <= MAX_PASSWORD_LENGTH): + print( + colored( + f"Error: Password length must be between {MIN_PASSWORD_LENGTH} and {MAX_PASSWORD_LENGTH}.", + "red", + ) + ) + continue + return length + + def finalize_entry(index: int, label: str, length: int) -> None: + pm.is_dirty = True + pm.last_update = time.time() + + entry = pm.entry_manager.retrieve_entry(index) + password = pm._generate_password_for_entry(entry, index, length) + + print( + colored( + f"\n[+] Password generated and indexed with ID {index}.\n", + "green", + ) + ) + if pm.secret_mode_enabled: + if manager_module.copy_to_clipboard( + password, pm.clipboard_clear_delay + ): + print( + colored( + f"[+] Password copied to clipboard. Will clear in {pm.clipboard_clear_delay} seconds.", + "green", + ) + ) + else: + print(colored(f"Password for {label}: {password}\n", "yellow")) + + try: + pm.start_background_vault_sync() + logging.info( + "Encrypted index posted to Nostr after entry addition." + ) + except Exception as nostr_error: # pragma: no cover - best effort + logging.error( + f"Failed to post updated index to Nostr: {nostr_error}", + exc_info=True, + ) + pause() + + while True: + mode = input("Choose mode: [Q]uick or [A]dvanced? ").strip().lower() + if not mode: + return + if mode.startswith("q") or mode.startswith("a"): + break + print( + colored( + "Invalid mode. Enter 'q' for quick or 'a' for advanced.", "red" + ) + ) + + website_name = input("Enter the label or website name: ").strip() + if not website_name: + print(colored("Error: Label cannot be empty.", "red")) + return + + username = input("Enter the username (optional): ").strip() + url = input("Enter the URL (optional): ").strip() + + if mode.startswith("q"): + length = prompt_length() + include_special_input = ( + input("Include special characters? (Y/n): ").strip().lower() + ) + include_special_chars: bool | None = None + if include_special_input: + include_special_chars = include_special_input != "n" + + index = pm.entry_manager.add_entry( + website_name, + length, + username, + url, + include_special_chars=include_special_chars, + ) + + finalize_entry(index, website_name, length) + return + + notes = input("Enter notes (optional): ").strip() + tags_input = input("Enter tags (comma-separated, optional): ").strip() + tags = ( + [t.strip() for t in tags_input.split(",") if t.strip()] + if tags_input + else [] + ) + + custom_fields: list[dict[str, object]] = [] + while True: + add_field = input("Add custom field? (y/N): ").strip().lower() + if add_field != "y": + break + label = input(" Field label: ").strip() + value = input(" Field value: ").strip() + hidden = input(" Hidden field? (y/N): ").strip().lower() == "y" + custom_fields.append( + {"label": label, "value": value, "is_hidden": hidden} + ) + + length = prompt_length() + + include_special_input = ( + input("Include special characters? (Y/n): ").strip().lower() + ) + include_special_chars: bool | None = None + if include_special_input: + include_special_chars = include_special_input != "n" + + allowed_special_chars = input( + "Allowed special characters (leave blank for default): " + ).strip() + if not allowed_special_chars: + allowed_special_chars = None + + special_mode = input("Special character mode (safe/leave blank): ").strip() + if not special_mode: + special_mode = None + + exclude_ambiguous_input = ( + input("Exclude ambiguous characters? (y/N): ").strip().lower() + ) + exclude_ambiguous: bool | None = None + if exclude_ambiguous_input: + exclude_ambiguous = exclude_ambiguous_input == "y" + + min_uppercase_input = input( + "Minimum uppercase letters (blank for default): " + ).strip() + if min_uppercase_input and not min_uppercase_input.isdigit(): + print(colored("Error: Minimum uppercase must be a number.", "red")) + return + min_uppercase = int(min_uppercase_input) if min_uppercase_input else None + + min_lowercase_input = input( + "Minimum lowercase letters (blank for default): " + ).strip() + if min_lowercase_input and not min_lowercase_input.isdigit(): + print(colored("Error: Minimum lowercase must be a number.", "red")) + return + min_lowercase = int(min_lowercase_input) if min_lowercase_input else None + + min_digits_input = input("Minimum digits (blank for default): ").strip() + if min_digits_input and not min_digits_input.isdigit(): + print(colored("Error: Minimum digits must be a number.", "red")) + return + min_digits = int(min_digits_input) if min_digits_input else None + + min_special_input = input( + "Minimum special characters (blank for default): " + ).strip() + if min_special_input and not min_special_input.isdigit(): + print(colored("Error: Minimum special must be a number.", "red")) + return + min_special = int(min_special_input) if min_special_input else None + + index = pm.entry_manager.add_entry( + website_name, + length, + username, + url, + archived=False, + notes=notes, + custom_fields=custom_fields, + tags=tags, + include_special_chars=include_special_chars, + allowed_special_chars=allowed_special_chars, + special_mode=special_mode, + exclude_ambiguous=exclude_ambiguous, + min_uppercase=min_uppercase, + min_lowercase=min_lowercase, + min_digits=min_digits, + min_special=min_special, + ) + + finalize_entry(index, website_name, length) + + except Exception as e: # pragma: no cover - defensive + logging.error(f"Error during password generation: {e}", exc_info=True) + print(colored(f"Error: Failed to generate password: {e}", "red")) + pause() diff --git a/src/seedpass/core/entry_types.py b/src/seedpass/core/entry_types.py index a11643a1..0babc4fa 100644 --- a/src/seedpass/core/entry_types.py +++ b/src/seedpass/core/entry_types.py @@ -15,3 +15,7 @@ class EntryType(str, Enum): NOSTR = "nostr" KEY_VALUE = "key_value" MANAGED_ACCOUNT = "managed_account" + + +# List of all entry type values for convenience +ALL_ENTRY_TYPES = [e.value for e in EntryType] diff --git a/src/seedpass/core/errors.py b/src/seedpass/core/errors.py new file mode 100644 index 00000000..85bc99c2 --- /dev/null +++ b/src/seedpass/core/errors.py @@ -0,0 +1,30 @@ +"""Custom exceptions for SeedPass core modules. + +This module defines :class:`SeedPassError`, a base exception used across the +core modules. Library code should raise this error instead of terminating the +process with ``sys.exit`` so that callers can handle failures gracefully. + +When raised inside the CLI, :class:`SeedPassError` behaves like a Click +exception, displaying a friendly message and exiting with code ``1``. +""" + +from click import ClickException +from cryptography.fernet import InvalidToken + + +class SeedPassError(ClickException): + """Base exception for SeedPass-related errors.""" + + def __init__(self, message: str): + super().__init__(message) + + +class DecryptionError(InvalidToken, SeedPassError): + """Raised when encrypted data cannot be decrypted. + + Subclasses :class:`cryptography.fernet.InvalidToken` so callers expecting + the cryptography exception continue to work. + """ + + +__all__ = ["SeedPassError", "DecryptionError"] diff --git a/src/seedpass/core/manager.py b/src/seedpass/core/manager.py index 2ae7e97c..a74cc346 100644 --- a/src/seedpass/core/manager.py +++ b/src/seedpass/core/manager.py @@ -14,25 +14,30 @@ import json import logging import os import hashlib -from typing import Optional, Literal +import hmac +import base64 +from typing import Optional, Literal, Any import shutil import time +from datetime import datetime, timezone import builtins import threading import queue from dataclasses import dataclass import dataclasses +from functools import wraps from termcolor import colored from utils.color_scheme import color_text from utils.input_utils import timed_input +from constants import MAX_RETRIES, RETRY_DELAY -from .encryption import EncryptionManager, get_salt_from_parent_seed_file +from .encryption import EncryptionManager from .entry_management import EntryManager from .password_generation import PasswordGenerator from .backup import BackupManager from .vault import Vault -from .portable_backup import export_backup, import_backup -from cryptography.fernet import InvalidToken +from .portable_backup import export_backup, import_backup, PortableMode +from .errors import SeedPassError, DecryptionError from .totp import TotpManager from .entry_types import EntryType from .pubsub import bus @@ -42,7 +47,9 @@ from utils.key_derivation import ( derive_key_from_password_argon2, derive_index_key, EncryptionMode, + KdfConfig, ) +from utils.key_hierarchy import kd from utils.checksum import ( calculate_checksum, verify_checksum, @@ -66,8 +73,10 @@ from utils.terminal_utils import ( clear_header_with_notification, ) from utils.fingerprint import generate_fingerprint +from utils.atomic_write import atomic_write from constants import MIN_HEALTHY_RELAYS from .migrations import LATEST_VERSION +from ..errors import VaultLockedError from constants import ( APP_DIR, @@ -82,7 +91,6 @@ from constants import ( initialize_app, ) -import traceback import asyncio import gzip import bcrypt @@ -94,23 +102,90 @@ from mnemonic import Mnemonic from datetime import datetime from utils.fingerprint_manager import FingerprintManager +from utils.logging_utils import pause_logging_for_ui # Import NostrClient -from nostr.client import NostrClient, DEFAULT_RELAYS, MANIFEST_ID_PREFIX +from nostr.client import NostrClient +from nostr.connection import DEFAULT_RELAYS from .config_manager import ConfigManager from .state_manager import StateManager from .stats_manager import StatsManager +from .menu_handler import MenuHandler +from .profile_service import ProfileService +from .entry_service import EntryService # Instantiate the logger logger = logging.getLogger(__name__) +class AuditLogger: + """Append-only logger producing tamper-evident JSON records.""" + + def __init__(self, key: bytes, path: Path | None = None) -> None: + self.key = key + self.path = path or (Path.home() / ".seedpass" / "audit.log") + self.path.parent.mkdir(parents=True, exist_ok=True) + self.last_sig = "0" * 64 + if self.path.exists(): + try: + with self.path.open("r", encoding="utf-8") as fh: + last = None + for line in fh: + if line.strip(): + last = line + if last is not None: + self.last_sig = json.loads(last).get("sig", self.last_sig) + except Exception: + pass + + def log(self, event: str, details: dict[str, Any] | None = None) -> None: + details = details or {} + entry = { + "timestamp": datetime.now(timezone.utc).isoformat(), + "event": event, + "details": details, + } + payload = json.dumps(entry, sort_keys=True, separators=(",", ":")) + sig = hmac.new( + self.key, f"{self.last_sig}{payload}".encode(), hashlib.sha256 + ).hexdigest() + entry["sig"] = sig + with self.path.open("a", encoding="utf-8") as fh: + fh.write(json.dumps(entry, sort_keys=True) + "\n") + self.last_sig = sig + + def calculate_profile_id(seed: str) -> str: """Return the fingerprint identifier for ``seed``.""" fp = generate_fingerprint(seed) return fp or "" +def restore_backup_index(path: Path, fingerprint: str) -> None: + """Restore the encrypted index for ``fingerprint`` from ``path``. + + This helper is intended for use before full :class:`PasswordManager` + initialization. It simply copies the provided backup file into the + profile's directory, replacing the existing index if present. A copy of + the previous index is kept with a ``.bak`` suffix to allow manual + recovery if needed. + """ + + fingerprint_dir = APP_DIR / fingerprint + fingerprint_dir.mkdir(parents=True, exist_ok=True) + dest = fingerprint_dir / "seedpass_entries_db.json.enc" + src = Path(path) + + # Ensure the source file can be read + src.read_bytes() + + if dest.exists(): + shutil.copy2(dest, dest.with_suffix(".bak")) + + shutil.copy2(src, dest) + os.chmod(dest, 0o600) + + @dataclass class Notification: """Simple message container for UI notifications.""" @@ -119,6 +194,18 @@ class Notification: level: str = "INFO" +def requires_unlocked(func): + """Decorator to ensure the vault is unlocked before proceeding.""" + + @wraps(func) + def wrapper(self, *args, **kwargs): + if getattr(self, "is_locked", False): + raise VaultLockedError("Vault is locked") + return func(self, *args, **kwargs) + + return wrapper + + class AuthGuard: """Helper to enforce inactivity timeouts.""" @@ -146,6 +233,14 @@ class PasswordManager: verification, ensuring the integrity and confidentiality of the stored password database. """ + # Class-level fallbacks so attributes exist even if ``__init__`` is bypassed + master_key: bytes | None = None + KEY_STORAGE: bytes | None = None + KEY_INDEX: bytes | None = None + KEY_PW_DERIVE: bytes | None = None + KEY_TOTP_DET: bytes | None = None + deterministic_totp: bool = False + def __init__( self, fingerprint: Optional[str] = None, *, password: Optional[str] = None ) -> None: @@ -172,26 +267,49 @@ class PasswordManager: self.state_manager: Optional[StateManager] = None self.stats_manager: StatsManager = StatsManager() self.notifications: queue.Queue[Notification] = queue.Queue() + self.error_queue: queue.Queue[Exception] = queue.Queue() self._current_notification: Optional[Notification] = None self._notification_expiry: float = 0.0 + self._bip85_cache: dict[tuple[int, int], bytes] = {} + self.audit_logger: Optional[AuditLogger] = None + + # Derived key hierarchy + self.master_key: bytes | None = None + self.KEY_STORAGE: bytes | None = None + self.KEY_INDEX: bytes | None = None + self.KEY_PW_DERIVE: bytes | None = None + self.KEY_TOTP_DET: bytes | None = None # Track changes to trigger periodic Nostr sync self.is_dirty: bool = False self.last_update: float = time.time() self.last_activity: float = time.time() self.locked: bool = False + self.is_locked: bool = False self.inactivity_timeout: float = INACTIVITY_TIMEOUT self.secret_mode_enabled: bool = False + self.deterministic_totp: bool = False self.clipboard_clear_delay: int = 45 - self.offline_mode: bool = False + self.offline_mode: bool = True self.profile_stack: list[tuple[str, Path, str]] = [] self.last_unlock_duration: float | None = None self.verbose_timing: bool = False self._suppress_entry_actions_menu: bool = False self.last_bip85_idx: int = 0 self.last_sync_ts: int = 0 + self.nostr_account_idx: int = 0 self.auth_guard = AuthGuard(self) + # Service composition + self._menu_handler: MenuHandler | None = None + self._profile_service: ProfileService | None = None + self._entry_service: EntryService | None = None + + # Initialize service instances + self.menu_handler + self.profile_service + self.entry_service + # Initialize the fingerprint manager first self.initialize_fingerprint_manager() @@ -206,6 +324,48 @@ class PasswordManager: self.fingerprint_manager.get_current_fingerprint_dir() ) + @requires_unlocked + def get_bip85_entropy( + self, purpose: int, index: int, entropy_bytes: int = 32 + ) -> bytes: + """Return deterministic entropy via the cached BIP-85 function.""" + + if self.bip85 is None: + raise RuntimeError("BIP-85 is not initialized") + return self.bip85.derive_entropy( + index=index, entropy_bytes=entropy_bytes, app_no=purpose + ) + + @requires_unlocked + def clear_bip85_cache(self) -> None: + """Clear the internal BIP-85 cache.""" + + self._bip85_cache.clear() + + def derive_key_hierarchy(self, seed_bytes: bytes) -> None: + """Populate sub-keys from ``seed_bytes`` using HKDF.""" + + master = kd(seed_bytes, b"seedpass:v1:master") + self.master_key = master + self.KEY_STORAGE = kd(master, b"seedpass:v1:storage") + self.KEY_INDEX = kd(master, b"seedpass:v1:index") + self.KEY_PW_DERIVE = kd(master, b"seedpass:v1:pw") + self.KEY_TOTP_DET = kd(master, b"seedpass:v1:totp") + + def ensure_key_hierarchy(self) -> None: + """Ensure sub-keys are derived from the current parent seed.""" + if ( + self.KEY_STORAGE is None + or self.KEY_INDEX is None + or self.KEY_PW_DERIVE is None + or self.KEY_TOTP_DET is None + ) and getattr(self, "parent_seed", None): + try: + seed_bytes = Bip39SeedGenerator(self.parent_seed).Generate() + except Exception: + seed_bytes = hashlib.sha256(self.parent_seed.encode()).digest() + self.derive_key_hierarchy(seed_bytes) + def ensure_script_checksum(self) -> None: """Initialize or verify the checksum of the manager script.""" script_path = Path(__file__).resolve() @@ -302,19 +462,43 @@ class PasswordManager: return self._current_notification return None + def poll_background_errors(self) -> None: + """Process exceptions raised by background threads.""" + if not hasattr(self, "error_queue"): + return + while True: + try: + exc = self.error_queue.get_nowait() + except queue.Empty: + break + logger.warning("Background task failed: %s", exc) + self.notify(f"Background task failed: {exc}", level="WARNING") + + @property + def menu_handler(self) -> MenuHandler: + if getattr(self, "_menu_handler", None) is None: + self._menu_handler = MenuHandler(self) + return self._menu_handler + + @property + def profile_service(self) -> ProfileService: + if getattr(self, "_profile_service", None) is None: + self._profile_service = ProfileService(self) + return self._profile_service + + @property + def entry_service(self) -> EntryService: + if getattr(self, "is_locked", False): + raise VaultLockedError("Vault is locked") + if getattr(self, "_entry_service", None) is None: + self._entry_service = EntryService(self) + return self._entry_service + def lock_vault(self) -> None: """Clear sensitive information from memory.""" if self.entry_manager is not None: self.entry_manager.clear_cache() - self.parent_seed = None - self.encryption_manager = None - self.entry_manager = None - self.password_generator = None - self.backup_manager = None - self.vault = None - self.bip85 = None - self.nostr_client = None - self.config_manager = None + self.is_locked = True self.locked = True bus.publish("vault_locked") @@ -339,8 +523,26 @@ class PasswordManager: self.setup_encryption_manager(self.fingerprint_dir, password) self.initialize_bip85() self.initialize_managers() + self.ensure_key_hierarchy() + self.is_locked = False self.locked = False self.update_activity() + if getattr(self, "audit_logger", None) is None and self.KEY_INDEX is not None: + self.audit_logger = AuditLogger(self.KEY_INDEX) + if ( + getattr(self, "config_manager", None) + and self.config_manager.get_quick_unlock() + ): + logger.info( + "Quick unlock used by %s at %s", + self.current_fingerprint or "unknown", + datetime.now(timezone.utc).isoformat(), + ) + audit_logger = getattr(self, "audit_logger", None) + if audit_logger: + audit_logger.log( + "quick_unlock", {"fingerprint": self.current_fingerprint} + ) self.last_unlock_duration = time.perf_counter() - start if getattr(self, "verbose_timing", False): logger.info("Vault unlocked in %.2f seconds", self.last_unlock_duration) @@ -358,7 +560,7 @@ class PasswordManager: print( colored(f"Error: Failed to initialize FingerprintManager: {e}", "red") ) - sys.exit(1) + raise SeedPassError(f"Failed to initialize FingerprintManager: {e}") from e def setup_parent_seed(self) -> None: """ @@ -400,7 +602,7 @@ class PasswordManager: choice = input("Select a seed profile by number: ").strip() if not choice.isdigit() or not (1 <= int(choice) <= len(fingerprints) + 1): print(colored("Invalid selection. Exiting.", "red")) - sys.exit(1) + raise SeedPassError("Invalid selection.") choice = int(choice) if choice == len(fingerprints) + 1: @@ -414,7 +616,7 @@ class PasswordManager: except Exception as e: logger.error(f"Error during seed profile selection: {e}", exc_info=True) print(colored(f"Error: Failed to select seed profile: {e}", "red")) - sys.exit(1) + raise SeedPassError(f"Failed to select seed profile: {e}") from e def add_new_fingerprint(self): """ @@ -423,9 +625,11 @@ class PasswordManager: """ try: choice = input( - "Do you want to (1) Paste in an existing seed in full " - "(2) Enter an existing seed one word at a time or " - "(3) Generate a new seed? (1/2/3): " + "Choose an option:\n" + "1. Paste in an existing seed in full\n" + "2. Enter an existing seed one word at a time\n" + "3. Generate a new seed\n" + "Enter choice (1/2/3): " ).strip() if choice == "1": fingerprint = self.setup_existing_seed(method="paste") @@ -435,7 +639,10 @@ class PasswordManager: fingerprint = self.generate_new_seed() else: print(colored("Invalid choice. Exiting.", "red")) - sys.exit(1) + raise SeedPassError("Invalid choice.") + + if not fingerprint: + return None # Set current_fingerprint in FingerprintManager only self.fingerprint_manager.current_fingerprint = fingerprint @@ -446,10 +653,16 @@ class PasswordManager: ) ) + # Ensure managers are initialized for the newly created profile + if getattr(self, "config_manager", None) is None: + self.initialize_managers() + + return fingerprint + except Exception as e: logger.error(f"Error adding new seed profile: {e}", exc_info=True) print(colored(f"Error: Failed to add new seed profile: {e}", "red")) - sys.exit(1) + raise SeedPassError(f"Failed to add new seed profile: {e}") from e def select_fingerprint( self, fingerprint: str, *, password: Optional[str] = None @@ -466,7 +679,9 @@ class PasswordManager: "red", ) ) - sys.exit(1) + raise SeedPassError( + f"Seed profile directory for {fingerprint} not found." + ) # Setup the encryption manager and load parent seed self.setup_encryption_manager(self.fingerprint_dir, password) # Initialize BIP85 and other managers @@ -480,7 +695,7 @@ class PasswordManager: ) else: print(colored(f"Error: Seed profile {fingerprint} not found.", "red")) - sys.exit(1) + raise SeedPassError(f"Seed profile {fingerprint} not found.") def setup_encryption_manager( self, @@ -508,46 +723,48 @@ class PasswordManager: if getattr(self, "config_manager", None) else 50_000 ) - - # Check for existing salt in parent_seed.enc (V3 format) - parent_seed_file = fingerprint_dir / "parent_seed.enc" - salt = get_salt_from_parent_seed_file(parent_seed_file) - print("Deriving key...") - if mode == "argon2": - seed_key = derive_key_from_password_argon2(password, salt=salt) - else: - seed_key = derive_key_from_password(password, salt=salt, iterations=iterations) + salt_fp = fingerprint_dir.name - seed_mgr = EncryptionManager(seed_key, fingerprint_dir) - print("Decrypting seed...") - try: - self.parent_seed = seed_mgr.decrypt_parent_seed() + iter_candidates: list[int] = [iterations] + if mode != "argon2": + iter_candidates.extend([50_000, 100_000]) - # If the file didn't have a salt (legacy/V2), upgrade it to V3 - if not salt: - logging.info("Upgrading parent seed encryption to V3 (with salt).") - new_salt = os.urandom(16) + seed_mgr: EncryptionManager | None = None + for iter_try in dict.fromkeys(iter_candidates): + try: if mode == "argon2": - new_seed_key = derive_key_from_password_argon2(password, salt=new_salt) + salt = hashlib.sha256(salt_fp.encode()).digest()[:16] + cfg = KdfConfig(salt_b64=base64.b64encode(salt).decode()) + seed_key = derive_key_from_password_argon2(password, cfg) else: - new_seed_key = derive_key_from_password(password, salt=new_salt, iterations=iterations) + seed_key = derive_key_from_password( + password, salt_fp, iterations=iter_try + ) + seed_mgr = EncryptionManager(seed_key, fingerprint_dir) + print("Decrypting seed...") + self.parent_seed = seed_mgr.decrypt_parent_seed() + if ( + mode != "argon2" + and iter_try != iterations + and getattr(self, "config_manager", None) + ): + self.config_manager.set_kdf_iterations(iter_try) + break + except DecryptionError: + seed_mgr = None - new_seed_mgr = EncryptionManager(new_seed_key, fingerprint_dir) - new_seed_mgr.encrypt_parent_seed(self.parent_seed, salt=new_salt) - - except Exception: - msg = ( - "Invalid password for selected seed profile. Please try again." - ) + if seed_mgr is None: + msg = "Incorrect password or corrupt file" print(colored(msg, "red")) attempts += 1 password = None continue - key = derive_index_key(self.parent_seed) - - self.encryption_manager = EncryptionManager(key, fingerprint_dir) + seed_bytes = Bip39SeedGenerator(self.parent_seed).Generate() + self.derive_key_hierarchy(seed_bytes) + key_b64 = base64.urlsafe_b64encode(self.KEY_STORAGE) + self.encryption_manager = EncryptionManager(key_b64, fingerprint_dir) self.vault = Vault(self.encryption_manager, fingerprint_dir) self.config_manager = ConfigManager( @@ -568,10 +785,10 @@ class PasswordManager: logger.error(f"Failed to set up EncryptionManager: {e}", exc_info=True) print(colored(f"Error: Failed to set up encryption: {e}", "red")) if exit_on_fail: - sys.exit(1) + raise SeedPassError(f"Failed to set up encryption: {e}") from e return False if exit_on_fail: - sys.exit(1) + raise SeedPassError("Failed to set up encryption") return False def load_parent_seed( @@ -596,122 +813,35 @@ class PasswordManager: if getattr(self, "config_manager", None) else 50_000 ) - - parent_seed_file = fingerprint_dir / "parent_seed.enc" - salt = get_salt_from_parent_seed_file(parent_seed_file) - + salt_fp = fingerprint_dir.name if mode == "argon2": - seed_key = derive_key_from_password_argon2(password, salt=salt) + salt = hashlib.sha256(salt_fp.encode()).digest()[:16] + cfg = KdfConfig(salt_b64=base64.b64encode(salt).decode()) + seed_key = derive_key_from_password_argon2(password, cfg) else: - seed_key = derive_key_from_password(password, salt=salt, iterations=iterations) - + seed_key = derive_key_from_password( + password, salt_fp, iterations=iterations + ) seed_mgr = EncryptionManager(seed_key, fingerprint_dir) self.parent_seed = seed_mgr.decrypt_parent_seed() seed_bytes = Bip39SeedGenerator(self.parent_seed).Generate() + self.derive_key_hierarchy(seed_bytes) self.bip85 = BIP85(seed_bytes) + except DecryptionError as e: + logger.error(f"Failed to load parent seed: {e}", exc_info=True) + print(colored("Incorrect password or corrupt file", "red")) + raise SeedPassError("Incorrect password or corrupt file") from e except Exception as e: logger.error(f"Failed to load parent seed: {e}", exc_info=True) print(colored(f"Error: Failed to load parent seed: {e}", "red")) - sys.exit(1) + raise SeedPassError(f"Failed to load parent seed: {e}") from e + @pause_logging_for_ui + @requires_unlocked def handle_switch_fingerprint(self, *, password: Optional[str] = None) -> bool: - """ - Handles switching to a different seed profile. - - Returns: - bool: True if switch was successful, False otherwise. - """ - try: - print(colored("\nAvailable Seed Profiles:", "cyan")) - fingerprints = self.fingerprint_manager.list_fingerprints() - for idx, fp in enumerate(fingerprints, start=1): - display = ( - self.fingerprint_manager.display_name(fp) - if hasattr(self.fingerprint_manager, "display_name") - else fp - ) - print(colored(f"{idx}. {display}", "cyan")) - - choice = input("Select a seed profile by number to switch: ").strip() - if not choice.isdigit() or not (1 <= int(choice) <= len(fingerprints)): - print(colored("Invalid selection. Returning to main menu.", "red")) - return False # Return False to indicate failure - - selected_fingerprint = fingerprints[int(choice) - 1] - self.fingerprint_manager.current_fingerprint = selected_fingerprint - self.current_fingerprint = selected_fingerprint - if not getattr(self, "manifest_id", None): - self.manifest_id = f"{MANIFEST_ID_PREFIX}{selected_fingerprint}" - - # Update fingerprint directory - self.fingerprint_dir = ( - self.fingerprint_manager.get_current_fingerprint_dir() - ) - if not self.fingerprint_dir: - print( - colored( - f"Error: Seed profile directory for {selected_fingerprint} not found.", - "red", - ) - ) - return False # Return False to indicate failure - - # Prompt for master password for the selected seed profile - if password is None: - password = prompt_existing_password( - "Enter the master password for the selected seed profile: " - ) - - # Set up the encryption manager with the new password and seed profile directory - if not self.setup_encryption_manager( - self.fingerprint_dir, password, exit_on_fail=False - ): - return False - - # Initialize BIP85 and other managers - self.initialize_bip85() - self.initialize_managers() - self.start_background_sync() - print(colored(f"Switched to seed profile {selected_fingerprint}.", "green")) - - # Re-initialize NostrClient with the new fingerprint - try: - self.nostr_client = NostrClient( - encryption_manager=self.encryption_manager, - fingerprint=self.current_fingerprint, - config_manager=getattr(self, "config_manager", None), - parent_seed=getattr(self, "parent_seed", None), - ) - if getattr(self, "manifest_id", None) and hasattr( - self.nostr_client, "_state_lock" - ): - from nostr.backup_models import Manifest - - with self.nostr_client._state_lock: - self.nostr_client.current_manifest_id = self.manifest_id - self.nostr_client.current_manifest = Manifest( - ver=1, - algo="gzip", - chunks=[], - delta_since=self.delta_since or None, - ) - logging.info( - f"NostrClient re-initialized with seed profile {self.current_fingerprint}." - ) - except Exception as e: - logging.error(f"Failed to re-initialize NostrClient: {e}") - print( - colored(f"Error: Failed to re-initialize NostrClient: {e}", "red") - ) - return False - - return True # Return True to indicate success - - except Exception as e: - logging.error(f"Error during seed profile switching: {e}", exc_info=True) - print(colored(f"Error: Failed to switch seed profiles: {e}", "red")) - return False # Return False to indicate failure + return self.profile_service.handle_switch_fingerprint(password=password) + @requires_unlocked def load_managed_account(self, index: int) -> None: """Load a managed account derived from the current seed profile.""" if not self.entry_manager or not self.parent_seed: @@ -730,8 +860,10 @@ class PasswordManager: self.fingerprint_dir = account_dir self.parent_seed = seed - key = derive_index_key(seed) - self.encryption_manager = EncryptionManager(key, account_dir) + seed_bytes = Bip39SeedGenerator(seed).Generate() + self.derive_key_hierarchy(seed_bytes) + key_b64 = base64.urlsafe_b64encode(self.KEY_STORAGE) + self.encryption_manager = EncryptionManager(key_b64, account_dir) self.vault = Vault(self.encryption_manager, account_dir) self.initialize_bip85() @@ -740,6 +872,7 @@ class PasswordManager: self.update_activity() self.start_background_sync() + @requires_unlocked def exit_managed_account(self) -> None: """Return to the parent seed profile if one is on the stack.""" if not self.profile_stack: @@ -749,9 +882,13 @@ class PasswordManager: self.current_fingerprint = fp self.fingerprint_dir = path self.parent_seed = seed - - key = derive_index_key(seed) - self.encryption_manager = EncryptionManager(key, path) + try: + seed_bytes = Bip39SeedGenerator(seed).Generate() + self.derive_key_hierarchy(seed_bytes) + key_b64 = base64.urlsafe_b64encode(self.KEY_STORAGE) + except Exception: + key_b64 = derive_index_key(seed) + self.encryption_manager = EncryptionManager(key_b64, path) self.vault = Vault(self.encryption_manager, path) self.initialize_bip85() @@ -760,6 +897,7 @@ class PasswordManager: self.update_activity() self.start_background_sync() + @pause_logging_for_ui def handle_existing_seed(self, *, password: Optional[str] = None) -> None: """ Handles the scenario where an existing parent seed file is found. @@ -782,7 +920,9 @@ class PasswordManager: "red", ) ) - sys.exit(1) + raise SeedPassError( + "No seed profiles available. Please add a seed profile first." + ) print(colored("Available Seed Profiles:", "cyan")) for idx, fp in enumerate(fingerprints, start=1): @@ -796,7 +936,7 @@ class PasswordManager: choice = input("Select a seed profile by number: ").strip() if not choice.isdigit() or not (1 <= int(choice) <= len(fingerprints)): print(colored("Invalid selection. Exiting.", "red")) - sys.exit(1) + raise SeedPassError("Invalid selection.") selected_fingerprint = fingerprints[int(choice) - 1] self.current_fingerprint = selected_fingerprint @@ -805,23 +945,26 @@ class PasswordManager: ) if not fingerprint_dir: print(colored("Error: Seed profile directory not found.", "red")) - sys.exit(1) + raise SeedPassError("Seed profile directory not found.") - # Derive encryption key from password, now that we have the directory to check for salt + # Derive encryption key from password using selected fingerprint iterations = ( self.config_manager.get_kdf_iterations() if getattr(self, "config_manager", None) else 50_000 ) - parent_seed_file = fingerprint_dir / "parent_seed.enc" - salt = get_salt_from_parent_seed_file(parent_seed_file) + key = derive_key_from_password( + password, selected_fingerprint, iterations=iterations + ) - key = derive_key_from_password(password, salt=salt, iterations=iterations) - - # Initialize EncryptionManager with key and fingerprint_dir - self.encryption_manager = EncryptionManager(key, fingerprint_dir) + seed_mgr = EncryptionManager(key, fingerprint_dir) + self.vault = Vault(seed_mgr, fingerprint_dir) + self.parent_seed = seed_mgr.decrypt_parent_seed() + seed_bytes = Bip39SeedGenerator(self.parent_seed).Generate() + self.derive_key_hierarchy(seed_bytes) + key_b64 = base64.urlsafe_b64encode(self.KEY_STORAGE) + self.encryption_manager = EncryptionManager(key_b64, fingerprint_dir) self.vault = Vault(self.encryption_manager, fingerprint_dir) - self.parent_seed = self.encryption_manager.decrypt_parent_seed() # Log the type and content of parent_seed logger.debug( @@ -832,15 +975,16 @@ class PasswordManager: if not self.validate_bip85_seed(self.parent_seed): logging.error("Decrypted seed is invalid. Exiting.") print(colored("Error: Decrypted seed is invalid.", "red")) - sys.exit(1) + raise SeedPassError("Decrypted seed is invalid.") self.initialize_bip85() logging.debug("Parent seed decrypted and validated successfully.") except Exception as e: logging.error(f"Failed to decrypt parent seed: {e}", exc_info=True) print(colored(f"Error: Failed to decrypt parent seed: {e}", "red")) - sys.exit(1) + raise SeedPassError(f"Failed to decrypt parent seed: {e}") from e + @pause_logging_for_ui def handle_new_seed_setup(self) -> None: """ Handles the setup process when no existing parent seed is found. @@ -849,9 +993,13 @@ class PasswordManager: self.notify("No existing seed found. Let's set up a new one!", level="WARNING") choice = input( - "Do you want to (1) Paste in an existing seed in full " - "(2) Enter an existing seed one word at a time, " - "(3) Generate a new seed, or (4) Restore from Nostr? (1/2/3/4): " + "Choose an option:\n" + "1. Paste in an existing seed in full\n" + "2. Enter an existing seed one word at a time\n" + "3. Generate a new seed\n" + "4. Restore from Nostr\n" + "5. Restore from local backup\n" + "Enter choice (1/2/3/4/5): " ).strip() if choice == "1": @@ -864,9 +1012,22 @@ class PasswordManager: seed_phrase = masked_input("Enter your 12-word BIP-85 seed: ").strip() self.restore_from_nostr_with_guidance(seed_phrase) return + elif choice == "5": + backup_path = input("Enter backup file path: ").strip() + if not getattr(self, "fingerprint_manager", None): + self.initialize_fingerprint_manager() + seed_phrase = masked_input("Enter your 12-word BIP-85 seed: ").strip() + fp = self._finalize_existing_seed(seed_phrase) + if fp: + self.backup_manager.restore_from_backup(backup_path) + return else: print(colored("Invalid choice. Exiting.", "red")) - sys.exit(1) + raise SeedPassError("Invalid choice.") + + # Some seed loading paths may not initialize managers; ensure they exist + if getattr(self, "config_manager", None) is None: + self.initialize_managers() def setup_existing_seed( self, @@ -899,13 +1060,13 @@ class PasswordManager: if not self.validate_bip85_seed(parent_seed): logging.error("Invalid BIP-85 seed phrase. Exiting.") print(colored("Error: Invalid BIP-85 seed phrase.", "red")) - sys.exit(1) - - return self._finalize_existing_seed(parent_seed, password=password) + raise SeedPassError("Invalid BIP-85 seed phrase.") + fingerprint = self._finalize_existing_seed(parent_seed, password=password) + return fingerprint except KeyboardInterrupt: logging.info("Operation cancelled by user.") self.notify("Operation cancelled by user.", level="WARNING") - sys.exit(0) + raise SeedPassError("Operation cancelled by user.") def setup_existing_seed_word_by_word( self, *, seed: Optional[str] = None, password: Optional[str] = None @@ -918,7 +1079,19 @@ class PasswordManager: ) -> Optional[str]: """Common logic for initializing an existing seed.""" if self.validate_bip85_seed(parent_seed): - fingerprint = self.fingerprint_manager.add_fingerprint(parent_seed) + try: + fingerprint = self.fingerprint_manager.add_fingerprint(parent_seed) + except ValueError: + existing_fp = generate_fingerprint(parent_seed) + print(colored("Error: Seed profile already exists.", "red")) + if confirm_action("Switch to existing profile? (Y/N): "): + self.current_fingerprint = existing_fp + self.fingerprint_manager.current_fingerprint = existing_fp + self.fingerprint_dir = ( + self.fingerprint_manager.get_fingerprint_directory(existing_fp) + ) + return existing_fp + return None if not fingerprint: print( colored( @@ -926,7 +1099,9 @@ class PasswordManager: "red", ) ) - sys.exit(1) + raise SeedPassError( + "Failed to generate seed profile for the provided seed." + ) fingerprint_dir = self.fingerprint_manager.get_fingerprint_directory( fingerprint @@ -935,28 +1110,29 @@ class PasswordManager: print( colored("Error: Failed to retrieve seed profile directory.", "red") ) - sys.exit(1) + raise SeedPassError("Failed to retrieve seed profile directory.") self.current_fingerprint = fingerprint self.fingerprint_manager.current_fingerprint = fingerprint self.fingerprint_dir = fingerprint_dir if not getattr(self, "manifest_id", None): - self.manifest_id = f"{MANIFEST_ID_PREFIX}{fingerprint}" + self.manifest_id = None logging.info(f"Current seed profile set to {fingerprint}") try: if password is None: password = prompt_for_password() - index_key = derive_index_key(parent_seed) + seed_bytes = Bip39SeedGenerator(parent_seed).Generate() + self.derive_key_hierarchy(seed_bytes) + index_key = base64.urlsafe_b64encode(self.KEY_STORAGE) iterations = ( self.config_manager.get_kdf_iterations() if getattr(self, "config_manager", None) else 50_000 ) - - # Generate new salt for new profile - salt = os.urandom(16) - seed_key = derive_key_from_password(password, salt=salt, iterations=iterations) + seed_key = derive_key_from_password( + password, fingerprint, iterations=iterations + ) self.encryption_manager = EncryptionManager(index_key, fingerprint_dir) seed_mgr = EncryptionManager(seed_key, fingerprint_dir) @@ -967,7 +1143,7 @@ class PasswordManager: fingerprint_dir=fingerprint_dir, ) - seed_mgr.encrypt_parent_seed(parent_seed, salt=salt) + seed_mgr.encrypt_parent_seed(parent_seed) logging.info("Parent seed encrypted and saved successfully.") self.store_hashed_password(password) @@ -988,8 +1164,9 @@ class PasswordManager: else: logging.error("Invalid BIP-85 seed phrase. Exiting.") print(colored("Error: Invalid BIP-85 seed phrase.", "red")) - sys.exit(1) + raise SeedPassError("Invalid BIP-85 seed phrase.") + @requires_unlocked def generate_new_seed(self) -> Optional[str]: """ Generates a new BIP-85 seed, displays it to the user, and prompts for confirmation before saving. @@ -1003,8 +1180,28 @@ class PasswordManager: print(colored("Please write this down and keep it in a safe place!", "red")) if confirm_action("Do you want to use this generated seed? (Y/N): "): + # Determine next account index if state manager is available + next_idx = 0 + if getattr(self, "state_manager", None) is not None: + try: + next_idx = self.state_manager.state.get("nostr_account_idx", 0) + 1 + except Exception: + next_idx = 0 + # Add a new fingerprint using the generated seed - fingerprint = self.fingerprint_manager.add_fingerprint(new_seed) + try: + fingerprint = self.fingerprint_manager.add_fingerprint(new_seed) + except ValueError: + print(colored("Error: Seed profile already exists.", "red")) + if confirm_action("Switch to existing profile? (Y/N): "): + existing_fp = generate_fingerprint(new_seed) + self.current_fingerprint = existing_fp + self.fingerprint_manager.current_fingerprint = existing_fp + self.fingerprint_dir = ( + self.fingerprint_manager.get_fingerprint_directory(existing_fp) + ) + return existing_fp + return None if not fingerprint: print( colored( @@ -1012,7 +1209,7 @@ class PasswordManager: "red", ) ) - sys.exit(1) + raise SeedPassError("Failed to generate seed profile for the new seed.") fingerprint_dir = self.fingerprint_manager.get_fingerprint_directory( fingerprint @@ -1021,7 +1218,16 @@ class PasswordManager: print( colored("Error: Failed to retrieve seed profile directory.", "red") ) - sys.exit(1) + raise SeedPassError("Failed to retrieve seed profile directory.") + + # Persist the assigned account index for the new profile + try: + StateManager(fingerprint_dir).update_state(nostr_account_idx=next_idx) + if getattr(self, "state_manager", None) is not None: + self.state_manager.update_state(nostr_account_idx=next_idx) + self.nostr_account_idx = next_idx + except Exception: + pass # Set the current fingerprint in both PasswordManager and FingerprintManager self.current_fingerprint = fingerprint @@ -1040,7 +1246,7 @@ class PasswordManager: return fingerprint # Return the generated fingerprint else: self.notify("Seed generation cancelled. Exiting.", level="WARNING") - sys.exit(0) + raise SeedPassError("Seed generation cancelled.") def validate_bip85_seed(self, seed: str) -> bool: """ @@ -1077,12 +1283,13 @@ class PasswordManager: except Bip85Error as e: logging.error(f"Failed to generate BIP-85 seed: {e}", exc_info=True) print(colored(f"Error: Failed to generate BIP-85 seed: {e}", "red")) - sys.exit(1) + raise SeedPassError(f"Failed to generate BIP-85 seed: {e}") from e except Exception as e: logging.error(f"Failed to generate BIP-85 seed: {e}", exc_info=True) print(colored(f"Error: Failed to generate BIP-85 seed: {e}", "red")) - sys.exit(1) + raise SeedPassError(f"Failed to generate BIP-85 seed: {e}") from e + @requires_unlocked def save_and_encrypt_seed( self, seed: str, fingerprint_dir: Path, *, password: Optional[str] = None ) -> None: @@ -1094,22 +1301,36 @@ class PasswordManager: fingerprint_dir (Path): The directory corresponding to the fingerprint. """ try: + fingerprint = generate_fingerprint(seed) + if ( + hasattr(self, "fingerprint_manager") + and self.fingerprint_manager is not None + ): + existing = self.fingerprint_manager.list_fingerprints() + # Allow saving when creating a new profile that was already + # registered via FingerprintManager. Only raise an error if + # the fingerprint exists for a *different* directory. + if fingerprint in existing and fingerprint_dir.name != fingerprint: + print(colored("Error: Seed profile already exists.", "red")) + raise ValueError("Fingerprint already exists") + # Set self.fingerprint_dir self.fingerprint_dir = fingerprint_dir if password is None: password = prompt_for_password() - index_key = derive_index_key(seed) + seed_bytes = Bip39SeedGenerator(seed).Generate() + self.derive_key_hierarchy(seed_bytes) + index_key = base64.urlsafe_b64encode(self.KEY_STORAGE) iterations = ( self.config_manager.get_kdf_iterations() if getattr(self, "config_manager", None) else 50_000 ) - - # Generate new salt for new seed - salt = os.urandom(16) - seed_key = derive_key_from_password(password, salt=salt, iterations=iterations) + seed_key = derive_key_from_password( + password, fingerprint_dir.name, iterations=iterations + ) self.encryption_manager = EncryptionManager(index_key, fingerprint_dir) seed_mgr = EncryptionManager(seed_key, fingerprint_dir) @@ -1126,7 +1347,7 @@ class PasswordManager: self.store_hashed_password(password) logging.info("User password hashed and stored successfully.") - seed_mgr.encrypt_parent_seed(seed, salt=salt) + seed_mgr.encrypt_parent_seed(seed) logging.info("Parent seed encrypted and saved successfully.") self.parent_seed = seed # Ensure this is a string @@ -1139,7 +1360,7 @@ class PasswordManager: except Exception as e: logging.error(f"Failed to encrypt and save parent seed: {e}", exc_info=True) print(colored(f"Error: Failed to encrypt and save parent seed: {e}", "red")) - sys.exit(1) + raise SeedPassError(f"Failed to encrypt and save parent seed: {e}") from e def initialize_bip85(self): """ @@ -1147,12 +1368,29 @@ class PasswordManager: """ try: seed_bytes = Bip39SeedGenerator(self.parent_seed).Generate() + self.derive_key_hierarchy(seed_bytes) self.bip85 = BIP85(seed_bytes) + self._bip85_cache = {} + orig_derive = self.bip85.derive_entropy + + def cached_derive( + index: int, entropy_bytes: int, app_no: int = 39 + ) -> bytes: + key = (app_no, index) + if key not in self._bip85_cache: + self._bip85_cache[key] = orig_derive( + index=index, entropy_bytes=entropy_bytes, app_no=app_no + ) + return self._bip85_cache[key] + + self.bip85.derive_entropy = cached_derive logging.debug("BIP-85 initialized successfully.") + # Reset cache directly so initialization is valid even while locked. + self._bip85_cache.clear() except Exception as e: logging.error(f"Failed to initialize BIP-85: {e}", exc_info=True) print(colored(f"Error: Failed to initialize BIP-85: {e}", "red")) - sys.exit(1) + raise SeedPassError(f"Failed to initialize BIP-85: {e}") from e def initialize_managers(self) -> None: """ @@ -1164,6 +1402,9 @@ class PasswordManager: if not self.encryption_manager: raise ValueError("EncryptionManager is not initialized.") + # Derive sub-keys if needed + self.ensure_key_hierarchy() + # Reinitialize the managers with the updated EncryptionManager and current fingerprint context self.config_manager = ConfigManager( vault=self.vault, @@ -1174,15 +1415,33 @@ class PasswordManager: fingerprint_dir=self.fingerprint_dir, config_manager=self.config_manager, ) + + migrated = False + last_migration_performed = False + index_exists = ( + self.vault.index_file.exists() + or ( + self.vault.fingerprint_dir / "seedpass_passwords_db.json.enc" + ).exists() + ) + try: + _, migrated, last_migration_performed = self.vault.load_index( + return_migration_flags=True + ) + except RuntimeError as exc: + print(colored(str(exc), "red")) + raise SeedPassError(str(exc)) + self.entry_manager = EntryManager( vault=self.vault, backup_manager=self.backup_manager, ) + pw_bip85 = BIP85(self.KEY_PW_DERIVE) self.password_generator = PasswordGenerator( encryption_manager=self.encryption_manager, - parent_seed=self.parent_seed, - bip85=self.bip85, + parent_seed=self.KEY_PW_DERIVE, + bip85=pw_bip85, policy=self.config_manager.get_password_policy(), ) @@ -1195,13 +1454,15 @@ class PasswordManager: self.last_sync_ts = state.get("last_sync_ts", 0) self.manifest_id = state.get("manifest_id") self.delta_since = state.get("delta_since", 0) + self.nostr_account_idx = state.get("nostr_account_idx", 0) else: relay_list = list(DEFAULT_RELAYS) self.last_bip85_idx = 0 self.last_sync_ts = 0 self.manifest_id = None self.delta_since = 0 - self.offline_mode = bool(config.get("offline_mode", False)) + self.nostr_account_idx = 0 + self.offline_mode = bool(config.get("offline_mode", True)) self.inactivity_timeout = config.get( "inactivity_timeout", INACTIVITY_TIMEOUT ) @@ -1217,6 +1478,8 @@ class PasswordManager: offline_mode=self.offline_mode, config_manager=self.config_manager, parent_seed=getattr(self, "parent_seed", None), + key_index=self.KEY_INDEX, + account_index=self.nostr_account_idx, ) if getattr(self, "manifest_id", None) and hasattr( @@ -1233,15 +1496,48 @@ class PasswordManager: delta_since=self.delta_since or None, ) + if migrated and index_exists: + print(colored("Local database migration successful.", "green")) + if self.encryption_manager is not None: + self.encryption_manager.last_migration_performed = False + if last_migration_performed and not self.offline_mode: + if confirm_action( + "Do you want to sync the migrated profile to Nostr now?" + ): + result = self.sync_vault() + if result: + print( + colored( + "Profile synchronized to Nostr successfully.", + "green", + ) + ) + else: + print( + colored( + "Error: Failed to sync profile to Nostr.", + "red", + ) + ) + else: + print( + colored( + "You can sync the migrated profile later from the main menu.", + "yellow", + ) + ) + logger.debug("Managers re-initialized for the new fingerprint.") except Exception as e: logger.error(f"Failed to initialize managers: {e}", exc_info=True) print(colored(f"Error: Failed to initialize managers: {e}", "red")) - sys.exit(1) + raise SeedPassError(f"Failed to initialize managers: {e}") from e async def sync_index_from_nostr_async(self) -> None: """Always fetch the latest vault data from Nostr and update the local index.""" + if not getattr(self, "nostr_client", None): + return start = time.perf_counter() try: if getattr(self, "current_fingerprint", None): @@ -1263,24 +1559,76 @@ class PasswordManager: encrypted = gzip.decompress(b"".join(chunks)) current = self.vault.get_encrypted_index() updated = False + migrated = False if current != encrypted: - if self.vault.decrypt_and_save_index_from_nostr( - encrypted, strict=False, merge=False - ): + success, mig = self.vault.decrypt_and_save_index_from_nostr( + encrypted, strict=False, merge=False, return_migration_flag=True + ) + if success: updated = True current = encrypted + migrated = migrated or mig if manifest.delta_since: version = int(manifest.delta_since) deltas = await self.nostr_client.fetch_deltas_since(version) for delta in deltas: if current != delta: - if self.vault.decrypt_and_save_index_from_nostr( - delta, strict=False, merge=True - ): + success, mig = self.vault.decrypt_and_save_index_from_nostr( + delta, + strict=False, + merge=True, + return_migration_flag=True, + ) + if success: updated = True current = delta + migrated = migrated or mig + if migrated: + print(colored("Local database migration successful.", "green")) + if self.encryption_manager is not None: + self.encryption_manager.last_migration_performed = False + if not getattr(self, "offline_mode", False): + if confirm_action( + "Do you want to sync the migrated profile to Nostr now?" + ): + try: + result = await self.sync_vault_async() + if result: + print( + colored( + "Profile synchronized to Nostr successfully.", + "green", + ) + ) + else: + print( + colored( + "Error: Failed to sync profile to Nostr.", + "red", + ) + ) + except Exception as sync_err: + logger.error( + "Failed to sync profile to Nostr after migration: %s", + sync_err, + exc_info=True, + ) + print( + colored( + "Error: Failed to sync profile to Nostr.", + "red", + ) + ) + else: + print( + colored( + "You can sync the migrated profile later from the main menu.", + "yellow", + ) + ) if updated: logger.info("Local database synchronized from Nostr.") + self.notify("Index file updated from Nostr successfully.") except Exception as e: logger.warning( "Unable to sync index from Nostr relays %s: %s", @@ -1307,6 +1655,8 @@ class PasswordManager: """Launch a thread to synchronize the vault without blocking the UI.""" if getattr(self, "offline_mode", False): return + if getattr(self, "nostr_client", None) is None: + return if getattr(self, "_sync_task", None) and not getattr( self._sync_task, "done", True ): @@ -1318,9 +1668,11 @@ class PasswordManager: await self.sync_index_from_nostr_async() except Exception as exc: logger.warning(f"Background sync failed: {exc}") + if hasattr(self, "error_queue") and getattr(self, "nostr_client", None): + self.error_queue.put(exc) try: - loop = asyncio.get_running_loop() + asyncio.get_running_loop() except RuntimeError: thread = threading.Thread( target=lambda: asyncio.run(_worker()), daemon=True @@ -1361,6 +1713,8 @@ class PasswordManager: ) except Exception as exc: logger.warning(f"Relay health check failed: {exc}") + if hasattr(self, "error_queue"): + self.error_queue.put(exc) self._relay_thread = threading.Thread(target=_worker, daemon=True) self._relay_thread.start() @@ -1377,9 +1731,11 @@ class PasswordManager: bus.publish("sync_finished", result) except Exception as exc: logging.error(f"Background vault sync failed: {exc}", exc_info=True) + if hasattr(self, "error_queue"): + self.error_queue.put(exc) try: - loop = asyncio.get_running_loop() + asyncio.get_running_loop() except RuntimeError: threading.Thread(target=_worker, daemon=True).start() else: @@ -1398,6 +1754,9 @@ class PasswordManager: local index file was written. Returns ``False`` otherwise. The local index file is not created on failure. """ + if not getattr(self, "nostr_client", None): + return False + index_file = self.fingerprint_dir / "seedpass_entries_db.json.enc" if index_file.exists(): return True @@ -1411,22 +1770,37 @@ class PasswordManager: if result: manifest, chunks = result encrypted = gzip.decompress(b"".join(chunks)) - success = self.vault.decrypt_and_save_index_from_nostr( - encrypted, strict=False, merge=False + migrated = False + success, mig = self.vault.decrypt_and_save_index_from_nostr( + encrypted, + strict=False, + merge=False, + return_migration_flag=True, ) if success: have_data = True + migrated = migrated or mig current = encrypted if manifest.delta_since: version = int(manifest.delta_since) deltas = await self.nostr_client.fetch_deltas_since(version) for delta in deltas: if current != delta: - if self.vault.decrypt_and_save_index_from_nostr( - delta, strict=False, merge=True - ): + success, mig = ( + self.vault.decrypt_and_save_index_from_nostr( + delta, + strict=False, + merge=True, + return_migration_flag=True, + ) + ) + if success: current = delta + migrated = migrated or mig + if migrated and not getattr(self, "offline_mode", False): + self.start_background_vault_sync() logger.info("Initialized local database from Nostr.") + self.notify("Index file updated from Nostr successfully.") except Exception as e: # pragma: no cover - network errors logger.warning(f"Unable to sync index from Nostr: {e}") finally: @@ -1448,6 +1822,8 @@ class PasswordManager: asyncio.run(self.sync_index_from_nostr_if_missing_async()) async def sync_index_from_nostr_if_missing_async(self) -> None: + if not getattr(self, "nostr_client", None): + return success = await self.attempt_initial_sync_async() if not success: self.vault.save_index({"schema_version": LATEST_VERSION, "entries": {}}) @@ -1456,22 +1832,37 @@ class PasswordManager: except Exception as exc: # pragma: no cover - best effort logger.warning(f"Unable to publish fresh database: {exc}") - def check_nostr_backup_exists(self, profile_id: str) -> bool: - """Return ``True`` if a snapshot exists on Nostr for ``profile_id``.""" + def check_nostr_backup_exists(self, seed_phrase: str) -> bool: + """Return ``True`` if a snapshot exists on Nostr for ``seed_phrase``.""" if not self.nostr_client or getattr(self, "offline_mode", False): return False + + profile_id = calculate_profile_id(seed_phrase) previous = self.nostr_client.fingerprint - self.nostr_client.fingerprint = profile_id try: - result = asyncio.run(self.nostr_client.fetch_latest_snapshot()) - return result is not None + if hasattr(self, "config_manager") and self.config_manager is not None: + cfg = self.config_manager.load_config(require_pin=False) + max_retries = int(cfg.get("nostr_max_retries", MAX_RETRIES)) + delay = float(cfg.get("nostr_retry_delay", RETRY_DELAY)) + else: + max_retries = MAX_RETRIES + delay = RETRY_DELAY + for attempt in range(max_retries): + self.nostr_client.fingerprint = profile_id + result = asyncio.run(self.nostr_client.fetch_latest_snapshot()) + if result is not None: + return True + if attempt < max_retries - 1: + time.sleep(delay * (2**attempt)) + return False finally: self.nostr_client.fingerprint = previous def restore_from_nostr_with_guidance(self, seed_phrase: str) -> None: """Restore a profile from Nostr, warning if no backup exists.""" - profile_id = calculate_profile_id(seed_phrase) - have_backup = self.check_nostr_backup_exists(profile_id) + self.notify("Searching for Nostr backup, this may take a moment...") + have_backup = self.check_nostr_backup_exists(seed_phrase) + if not have_backup: print(colored("No Nostr backup found for this seed profile.", "yellow")) if not confirm_action("Continue with an empty database? (Y/N): "): @@ -1481,222 +1872,26 @@ class PasswordManager: if not fp: return - success = self.attempt_initial_sync() - if success: - print(colored("Vault restored from Nostr.", "green")) - elif have_backup: - print(colored("Failed to download vault from Nostr.", "red")) + if have_backup: + self.notify("Backup found. Restoring vault...") + success = self.attempt_initial_sync() + if success: + self.notify("Vault restored successfully from Nostr.", level="INFO") + print(colored("Vault restored from Nostr.", "green")) + else: + self.notify( + "Failed to download or decrypt vault from Nostr.", level="ERROR" + ) + print(colored("Failed to download vault from Nostr.", "red")) + else: + self.notify("Starting with a new, empty vault.", level="INFO") + return + @pause_logging_for_ui def handle_add_password(self) -> None: - try: - fp, parent_fp, child_fp = self.header_fingerprint_args - clear_header_with_notification( - self, - fp, - "Main Menu > Add Entry > Password", - parent_fingerprint=parent_fp, - child_fingerprint=child_fp, - ) - - def prompt_length() -> int | None: - length_input = input( - f"Enter desired password length (default {DEFAULT_PASSWORD_LENGTH}): " - ).strip() - length = DEFAULT_PASSWORD_LENGTH - if length_input: - if not length_input.isdigit(): - print( - colored("Error: Password length must be a number.", "red") - ) - return None - length = int(length_input) - if not (MIN_PASSWORD_LENGTH <= length <= MAX_PASSWORD_LENGTH): - print( - colored( - f"Error: Password length must be between {MIN_PASSWORD_LENGTH} and {MAX_PASSWORD_LENGTH}.", - "red", - ) - ) - return None - return length - - def finalize_entry(index: int, label: str, length: int) -> None: - # Mark database as dirty for background sync - self.is_dirty = True - self.last_update = time.time() - - # Generate the password using the assigned index - entry = self.entry_manager.retrieve_entry(index) - password = self._generate_password_for_entry(entry, index, length) - - # Provide user feedback - print( - colored( - f"\n[+] Password generated and indexed with ID {index}.\n", - "green", - ) - ) - if self.secret_mode_enabled: - copy_to_clipboard(password, self.clipboard_clear_delay) - print( - colored( - f"[+] Password copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", - "green", - ) - ) - else: - print(colored(f"Password for {label}: {password}\n", "yellow")) - - # Automatically push the updated encrypted index to Nostr so the - # latest changes are backed up remotely. - try: - self.start_background_vault_sync() - logging.info( - "Encrypted index posted to Nostr after entry addition." - ) - except Exception as nostr_error: - logging.error( - f"Failed to post updated index to Nostr: {nostr_error}", - exc_info=True, - ) - pause() - - mode = input("Choose mode: [Q]uick or [A]dvanced? ").strip().lower() - - website_name = input("Enter the label or website name: ").strip() - if not website_name: - print(colored("Error: Label cannot be empty.", "red")) - return - - username = input("Enter the username (optional): ").strip() - url = input("Enter the URL (optional): ").strip() - - if mode.startswith("q"): - length = prompt_length() - if length is None: - return - include_special_input = ( - input("Include special characters? (Y/n): ").strip().lower() - ) - include_special_chars: bool | None = None - if include_special_input: - include_special_chars = include_special_input != "n" - - index = self.entry_manager.add_entry( - website_name, - length, - username, - url, - include_special_chars=include_special_chars, - ) - - finalize_entry(index, website_name, length) - return - - notes = input("Enter notes (optional): ").strip() - tags_input = input("Enter tags (comma-separated, optional): ").strip() - tags = ( - [t.strip() for t in tags_input.split(",") if t.strip()] - if tags_input - else [] - ) - - custom_fields: list[dict[str, object]] = [] - while True: - add_field = input("Add custom field? (y/N): ").strip().lower() - if add_field != "y": - break - label = input(" Field label: ").strip() - value = input(" Field value: ").strip() - hidden = input(" Hidden field? (y/N): ").strip().lower() == "y" - custom_fields.append( - {"label": label, "value": value, "is_hidden": hidden} - ) - - length = prompt_length() - if length is None: - return - - include_special_input = ( - input("Include special characters? (Y/n): ").strip().lower() - ) - include_special_chars: bool | None = None - if include_special_input: - include_special_chars = include_special_input != "n" - - allowed_special_chars = input( - "Allowed special characters (leave blank for default): " - ).strip() - if not allowed_special_chars: - allowed_special_chars = None - - special_mode = input("Special character mode (safe/leave blank): ").strip() - if not special_mode: - special_mode = None - - exclude_ambiguous_input = ( - input("Exclude ambiguous characters? (y/N): ").strip().lower() - ) - exclude_ambiguous: bool | None = None - if exclude_ambiguous_input: - exclude_ambiguous = exclude_ambiguous_input == "y" - - min_uppercase_input = input( - "Minimum uppercase letters (blank for default): " - ).strip() - if min_uppercase_input and not min_uppercase_input.isdigit(): - print(colored("Error: Minimum uppercase must be a number.", "red")) - return - min_uppercase = int(min_uppercase_input) if min_uppercase_input else None - - min_lowercase_input = input( - "Minimum lowercase letters (blank for default): " - ).strip() - if min_lowercase_input and not min_lowercase_input.isdigit(): - print(colored("Error: Minimum lowercase must be a number.", "red")) - return - min_lowercase = int(min_lowercase_input) if min_lowercase_input else None - - min_digits_input = input("Minimum digits (blank for default): ").strip() - if min_digits_input and not min_digits_input.isdigit(): - print(colored("Error: Minimum digits must be a number.", "red")) - return - min_digits = int(min_digits_input) if min_digits_input else None - - min_special_input = input( - "Minimum special characters (blank for default): " - ).strip() - if min_special_input and not min_special_input.isdigit(): - print(colored("Error: Minimum special must be a number.", "red")) - return - min_special = int(min_special_input) if min_special_input else None - - index = self.entry_manager.add_entry( - website_name, - length, - username, - url, - archived=False, - notes=notes, - custom_fields=custom_fields, - tags=tags, - include_special_chars=include_special_chars, - allowed_special_chars=allowed_special_chars, - special_mode=special_mode, - exclude_ambiguous=exclude_ambiguous, - min_uppercase=min_uppercase, - min_lowercase=min_lowercase, - min_digits=min_digits, - min_special=min_special, - ) - - finalize_entry(index, website_name, length) - - except Exception as e: - logging.error(f"Error during password generation: {e}", exc_info=True) - print(colored(f"Error: Failed to generate password: {e}", "red")) - pause() + self.entry_service.handle_add_password() + @pause_logging_for_ui def handle_add_totp(self) -> None: """Add a TOTP entry either derived from the seed or imported.""" try: @@ -1710,7 +1905,7 @@ class PasswordManager: child_fingerprint=child_fp, ) print("\nAdd TOTP:") - print("1. Make 2FA (derive from seed)") + print("1. Make 2FA") print("2. Import 2FA (paste otpauth URI or secret)") choice = input("Select option or press Enter to go back: ").strip() if choice == "1": @@ -1734,18 +1929,29 @@ class PasswordManager: if tags_input else [] ) - totp_index = self.entry_manager.get_next_totp_index() entry_id = self.entry_manager.get_next_index() + key = self.KEY_TOTP_DET if self.deterministic_totp else None + totp_index = ( + self.entry_manager.get_next_totp_index() + if self.deterministic_totp + else None + ) uri = self.entry_manager.add_totp( label, - self.parent_seed, + key, index=totp_index, period=int(period), digits=int(digits), notes=notes, tags=tags, + deterministic=self.deterministic_totp, ) - secret = TotpManager.derive_secret(self.parent_seed, totp_index) + if self.deterministic_totp: + secret = TotpManager.derive_secret(key, totp_index or 0) + color_cat = "deterministic" + else: + _lbl, secret, _, _ = TotpManager.parse_otpauth(uri) + color_cat = "default" self.is_dirty = True self.last_update = time.time() print( @@ -1756,7 +1962,7 @@ class PasswordManager: print(colored("Add this URI to your authenticator app:", "cyan")) print(colored(uri, "yellow")) TotpManager.print_qr_code(uri) - print(color_text(f"Secret: {secret}\n", "deterministic")) + print(color_text(f"Secret: {secret}\n", color_cat)) try: self.start_background_vault_sync() except Exception as nostr_error: @@ -1790,12 +1996,13 @@ class PasswordManager: entry_id = self.entry_manager.get_next_index() uri = self.entry_manager.add_totp( label, - self.parent_seed, + None, secret=secret, period=period, digits=digits, notes=notes, tags=tags, + deterministic=False, ) self.is_dirty = True self.last_update = time.time() @@ -1826,6 +2033,7 @@ class PasswordManager: print(colored(f"Error: Failed to add TOTP: {e}", "red")) pause() + @pause_logging_for_ui def handle_add_ssh_key(self) -> None: """Add an SSH key pair entry and display the derived keys.""" try: @@ -1883,6 +2091,7 @@ class PasswordManager: print(colored(f"Error: Failed to add SSH key: {e}", "red")) pause() + @pause_logging_for_ui def handle_add_seed(self) -> None: """Add a derived BIP-39 seed phrase entry.""" try: @@ -1952,6 +2161,7 @@ class PasswordManager: print(colored(f"Error: Failed to add seed phrase: {e}", "red")) pause() + @pause_logging_for_ui def handle_add_pgp(self) -> None: """Add a PGP key entry and display the generated key.""" try: @@ -2019,6 +2229,7 @@ class PasswordManager: print(colored(f"Error: Failed to add PGP key: {e}", "red")) pause() + @pause_logging_for_ui def handle_add_nostr_key(self) -> None: """Add a Nostr key entry and display the derived keys.""" try: @@ -2050,13 +2261,13 @@ class PasswordManager: print(colored(f"\n[+] Nostr key entry added with ID {index}.\n", "green")) print(colored(f"npub: {npub}", "cyan")) if self.secret_mode_enabled: - copy_to_clipboard(nsec, self.clipboard_clear_delay) - print( - colored( - f"[+] nsec copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", - "green", + if copy_to_clipboard(nsec, self.clipboard_clear_delay): + print( + colored( + f"[+] nsec copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", + "green", + ) ) - ) else: print(color_text(f"nsec: {nsec}", "deterministic")) if confirm_action("Show QR code for npub? (Y/N): "): @@ -2078,6 +2289,7 @@ class PasswordManager: print(colored(f"Error: Failed to add Nostr key: {e}", "red")) pause() + @pause_logging_for_ui def handle_add_key_value(self) -> None: """Add a generic key/value entry.""" try: @@ -2137,13 +2349,13 @@ class PasswordManager: if notes: print(colored(f"Notes: {notes}", "cyan")) if self.secret_mode_enabled: - copy_to_clipboard(value, self.clipboard_clear_delay) - print( - colored( - f"[+] Value copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", - "green", + if copy_to_clipboard(value, self.clipboard_clear_delay): + print( + colored( + f"[+] Value copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", + "green", + ) ) - ) else: print(color_text(f"Value: {value}", "deterministic")) try: @@ -2159,6 +2371,7 @@ class PasswordManager: print(colored(f"Error: Failed to add key/value entry: {e}", "red")) pause() + @pause_logging_for_ui def handle_add_managed_account(self) -> None: """Add a managed account seed entry.""" try: @@ -2195,13 +2408,13 @@ class PasswordManager: ) if confirm_action("Reveal seed now? (y/N): "): if self.secret_mode_enabled: - copy_to_clipboard(seed, self.clipboard_clear_delay) - print( - colored( - f"[+] Seed copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", - "green", + if copy_to_clipboard(seed, self.clipboard_clear_delay): + print( + colored( + f"[+] Seed copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", + "green", + ) ) - ) else: print(color_text(seed, "deterministic")) if confirm_action("Show Compact Seed QR? (Y/N): "): @@ -2551,16 +2764,18 @@ class PasswordManager: print(colored(f"Retrieving 2FA code for '{label}'.", "cyan")) print(colored("Press Enter to return to the menu.", "cyan")) try: + key = self.KEY_TOTP_DET or getattr(self, "parent_seed", None) + secret = self.entry_manager.get_totp_secret(index, key) while True: - code = self.entry_manager.get_totp_code(index, self.parent_seed) + code = TotpManager.current_code_from_secret(secret) if self.secret_mode_enabled: - copy_to_clipboard(code, self.clipboard_clear_delay) - print( - colored( - f"[+] 2FA code for '{label}' copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", - "green", + if copy_to_clipboard(code, self.clipboard_clear_delay): + print( + colored( + f"[+] 2FA code for '{label}' copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", + "green", + ) ) - ) else: print(colored("\n[+] Retrieved 2FA Code:\n", "green")) print(colored(f"Label: {label}", "cyan")) @@ -2626,13 +2841,13 @@ class PasswordManager: print(colored("Public Key:", "cyan")) print(color_text(pub_pem, "default")) if self.secret_mode_enabled: - copy_to_clipboard(priv_pem, self.clipboard_clear_delay) - print( - colored( - f"[+] SSH private key copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", - "green", + if copy_to_clipboard(priv_pem, self.clipboard_clear_delay): + print( + colored( + f"[+] SSH private key copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", + "green", + ) ) - ) else: print(colored("Private Key:", "cyan")) print(color_text(priv_pem, "deterministic")) @@ -2661,13 +2876,13 @@ class PasswordManager: if tags: print(colored(f"Tags: {', '.join(tags)}", "cyan")) if self.secret_mode_enabled: - copy_to_clipboard(phrase, self.clipboard_clear_delay) - print( - colored( - f"[+] Seed phrase copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", - "green", + if copy_to_clipboard(phrase, self.clipboard_clear_delay): + print( + colored( + f"[+] Seed phrase copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", + "green", + ) ) - ) else: print(color_text(phrase, "deterministic")) if confirm_action("Show derived entropy as hex? (Y/N): "): @@ -2675,14 +2890,14 @@ class PasswordManager: from bip_utils import Bip39SeedGenerator words = int(entry.get("word_count", entry.get("words", 24))) - bytes_len = {12: 16, 18: 24, 24: 32}.get(words, 32) + entropy_bytes = {12: 16, 18: 24, 24: 32}.get(words, 32) seed_bytes = Bip39SeedGenerator(self.parent_seed).Generate() bip85 = BIP85(seed_bytes) entropy = bip85.derive_entropy( index=int(entry.get("index", index)), - bytes_len=bytes_len, + entropy_bytes=entropy_bytes, app_no=39, - words_len=words, + word_count=words, ) print(color_text(f"Entropy: {entropy.hex()}", "deterministic")) except Exception as e: # pragma: no cover - best effort @@ -2712,13 +2927,13 @@ class PasswordManager: print(colored(f"Tags: {', '.join(tags)}", "cyan")) print(colored(f"Fingerprint: {fingerprint}", "cyan")) if self.secret_mode_enabled: - copy_to_clipboard(priv_key, self.clipboard_clear_delay) - print( - colored( - f"[+] PGP key copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", - "green", + if copy_to_clipboard(priv_key, self.clipboard_clear_delay): + print( + colored( + f"[+] PGP key copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", + "green", + ) ) - ) else: print(color_text(priv_key, "deterministic")) except Exception as e: # pragma: no cover - best effort @@ -2737,13 +2952,13 @@ class PasswordManager: print(colored(f"Label: {label}", "cyan")) print(colored(f"npub: {npub}", "cyan")) if self.secret_mode_enabled: - copy_to_clipboard(nsec, self.clipboard_clear_delay) - print( - colored( - f"[+] nsec copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", - "green", + if copy_to_clipboard(nsec, self.clipboard_clear_delay): + print( + colored( + f"[+] nsec copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", + "green", + ) ) - ) else: print(color_text(f"nsec: {nsec}", "deterministic")) if notes: @@ -2773,13 +2988,13 @@ class PasswordManager: ) ) if self.secret_mode_enabled: - copy_to_clipboard(value, self.clipboard_clear_delay) - print( - colored( - f"[+] Value copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", - "green", + if copy_to_clipboard(value, self.clipboard_clear_delay): + print( + colored( + f"[+] Value copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", + "green", + ) ) - ) else: print(color_text(f"Value: {value}", "deterministic")) @@ -2800,13 +3015,15 @@ class PasswordManager: if show == "y": for f_label, f_value in hidden_fields: if self.secret_mode_enabled: - copy_to_clipboard(f_value, self.clipboard_clear_delay) - print( - colored( - f"[+] {f_label} copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", - "green", + if copy_to_clipboard( + f_value, self.clipboard_clear_delay + ): + print( + colored( + f"[+] {f_label} copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", + "green", + ) ) - ) else: print(colored(f" {f_label}: {f_value}", "cyan")) return @@ -2841,13 +3058,13 @@ class PasswordManager: index, self.parent_seed ) if self.secret_mode_enabled: - copy_to_clipboard(seed, self.clipboard_clear_delay) - print( - colored( - f"[+] Seed phrase copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", - "green", + if copy_to_clipboard(seed, self.clipboard_clear_delay): + print( + colored( + f"[+] Seed phrase copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", + "green", + ) ) - ) else: print(color_text(seed, "deterministic")) return @@ -2885,13 +3102,13 @@ class PasswordManager: if password: if self.secret_mode_enabled: - copy_to_clipboard(password, self.clipboard_clear_delay) - print( - colored( - f"[+] Password for '{website_name}' copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", - "green", + if copy_to_clipboard(password, self.clipboard_clear_delay): + print( + colored( + f"[+] Password for '{website_name}' copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", + "green", + ) ) - ) else: print( colored( @@ -2930,19 +3147,22 @@ class PasswordManager: if show == "y": for label, value in hidden_fields: if self.secret_mode_enabled: - copy_to_clipboard(value, self.clipboard_clear_delay) - print( - colored( - f"[+] {label} copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", - "green", + if copy_to_clipboard( + value, self.clipboard_clear_delay + ): + print( + colored( + f"[+] {label} copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", + "green", + ) ) - ) else: print(colored(f" {label}: {value}", "cyan")) else: print(colored("Error: Failed to retrieve the password.", "red")) return + @pause_logging_for_ui def handle_retrieve_entry(self) -> None: """Prompt for an index and display the corresponding entry.""" try: @@ -2977,6 +3197,7 @@ class PasswordManager: print(colored(f"Error: Failed to retrieve password: {e}", "red")) pause() + @pause_logging_for_ui def handle_modify_entry(self) -> None: """ Handles modifying an existing password entry by prompting the user for the index number @@ -3408,15 +3629,13 @@ class PasswordManager: exc_info=True, ) - updated_entry = self.entry_manager.retrieve_entry(index) - if updated_entry: - self._prompt_toggle_archive(updated_entry, index) pause() except Exception as e: logging.error(f"Error during modifying entry: {e}", exc_info=True) print(colored(f"Error: Failed to modify entry: {e}", "red")) + @pause_logging_for_ui def handle_search_entries(self) -> None: """Prompt for a query, list matches and optionally show details.""" try: @@ -3626,86 +3845,9 @@ class PasswordManager: ) print("-" * 40) + @pause_logging_for_ui def handle_list_entries(self) -> None: - """List entries and optionally show details.""" - try: - while True: - fp, parent_fp, child_fp = self.header_fingerprint_args - clear_header_with_notification( - self, - fp, - "Main Menu > List Entries", - parent_fingerprint=parent_fp, - child_fingerprint=child_fp, - ) - print(color_text("\nList Entries:", "menu")) - print(color_text("1. All", "menu")) - print(color_text("2. Passwords", "menu")) - print(color_text("3. 2FA (TOTP)", "menu")) - print(color_text("4. SSH Key", "menu")) - print(color_text("5. Seed Phrase", "menu")) - print(color_text("6. Nostr Key Pair", "menu")) - print(color_text("7. PGP", "menu")) - print(color_text("8. Key/Value", "menu")) - print(color_text("9. Managed Account", "menu")) - choice = input("Select entry type or press Enter to go back: ").strip() - if choice == "1": - filter_kind = None - elif choice == "2": - filter_kind = EntryType.PASSWORD.value - elif choice == "3": - filter_kind = EntryType.TOTP.value - elif choice == "4": - filter_kind = EntryType.SSH.value - elif choice == "5": - filter_kind = EntryType.SEED.value - elif choice == "6": - filter_kind = EntryType.NOSTR.value - elif choice == "7": - filter_kind = EntryType.PGP.value - elif choice == "8": - filter_kind = EntryType.KEY_VALUE.value - elif choice == "9": - filter_kind = EntryType.MANAGED_ACCOUNT.value - elif not choice: - return - else: - print(colored("Invalid choice.", "red")) - continue - - summaries = self.entry_manager.get_entry_summaries( - filter_kind, include_archived=False - ) - if not summaries: - continue - while True: - fp, parent_fp, child_fp = self.header_fingerprint_args - clear_header_with_notification( - self, - fp, - "Main Menu > List Entries", - parent_fingerprint=parent_fp, - child_fingerprint=child_fp, - ) - print(colored("\n[+] Entries:\n", "green")) - for idx, etype, label in summaries: - if filter_kind is None: - display_type = etype.capitalize() - print(colored(f"{idx}. {display_type} - {label}", "cyan")) - else: - print(colored(f"{idx}. {label}", "cyan")) - idx_input = input( - "Enter index to view details or press Enter to go back: " - ).strip() - if not idx_input: - break - if not idx_input.isdigit(): - print(colored("Invalid index.", "red")) - continue - self.show_entry_details_by_index(int(idx_input)) - except Exception as e: - logging.error(f"Failed to list entries: {e}", exc_info=True) - print(colored(f"Error: Failed to list entries: {e}", "red")) + self.menu_handler.handle_list_entries() def delete_entry(self) -> None: """Deletes an entry from the password index.""" @@ -3744,6 +3886,7 @@ class PasswordManager: logging.error(f"Error during entry deletion: {e}", exc_info=True) print(colored(f"Error: Failed to delete entry: {e}", "red")) + @pause_logging_for_ui def handle_archive_entry(self) -> None: """Archive an entry without deleting it.""" try: @@ -3762,18 +3905,30 @@ class PasswordManager: logging.error(f"Error archiving entry: {e}", exc_info=True) print(colored(f"Error: Failed to archive entry: {e}", "red")) + @pause_logging_for_ui def handle_view_archived_entries(self) -> None: """Display archived entries and optionally view or restore them.""" try: - archived = self.entry_manager.list_entries( - include_archived=True, verbose=False - ) - archived = [e for e in archived if e[4]] + + def _load_archived_entries() -> ( + list[tuple[int, str, str | None, str | None, bool]] + ): + entries = self.entry_manager.list_entries( + include_archived=True, verbose=False + ) + return [e for e in entries if e[4]] + + archived = _load_archived_entries() if not archived: self.notify("No archived entries found.", level="WARNING") pause() return while True: + archived = _load_archived_entries() + if not archived: + self.notify("No archived entries found.", level="WARNING") + pause() + return fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( self, @@ -3806,16 +3961,15 @@ class PasswordManager: ) if action == "v": self.show_entry_details_by_index(entry_index) - pause() + archived = _load_archived_entries() + if entry_index not in [e[0] for e in archived]: + break elif action == "r": self.entry_manager.restore_entry(entry_index) self.is_dirty = True self.last_update = time.time() pause() - archived = self.entry_manager.list_entries( - include_archived=True, verbose=False - ) - archived = [e for e in archived if e[4]] + archived = _load_archived_entries() if not archived: print(colored("All entries restored.", "green")) pause() @@ -3829,95 +3983,11 @@ class PasswordManager: logging.error(f"Error viewing archived entries: {e}", exc_info=True) print(colored(f"Error: Failed to view archived entries: {e}", "red")) + @pause_logging_for_ui def handle_display_totp_codes(self) -> None: - """Display all stored TOTP codes with a countdown progress bar.""" - try: - fp, parent_fp, child_fp = self.header_fingerprint_args - clear_header_with_notification( - self, - fp, - "Main Menu > 2FA Codes", - parent_fingerprint=parent_fp, - child_fingerprint=child_fp, - ) - data = self.entry_manager.vault.load_index() - entries = data.get("entries", {}) - totp_list: list[tuple[str, int, int, bool]] = [] - for idx_str, entry in entries.items(): - if self._entry_type_str( - entry - ) == EntryType.TOTP.value and not entry.get( - "archived", entry.get("blacklisted", False) - ): - label = entry.get("label", "") - period = int(entry.get("period", 30)) - imported = "secret" in entry - totp_list.append((label, int(idx_str), period, imported)) - - if not totp_list: - self.notify("No 2FA entries found.", level="WARNING") - return - - totp_list.sort(key=lambda t: t[0].lower()) - print(colored("Press Enter to return to the menu.", "cyan")) - while True: - fp, parent_fp, child_fp = self.header_fingerprint_args - clear_header_with_notification( - self, - fp, - "Main Menu > 2FA Codes", - parent_fingerprint=parent_fp, - child_fingerprint=child_fp, - ) - print(colored("Press Enter to return to the menu.", "cyan")) - generated = [t for t in totp_list if not t[3]] - imported_list = [t for t in totp_list if t[3]] - if generated: - print(colored("\nGenerated 2FA Codes:", "green")) - for label, idx, period, _ in generated: - code = self.entry_manager.get_totp_code(idx, self.parent_seed) - remaining = self.entry_manager.get_totp_time_remaining(idx) - filled = int(20 * (period - remaining) / period) - bar = "[" + "#" * filled + "-" * (20 - filled) + "]" - if self.secret_mode_enabled: - copy_to_clipboard(code, self.clipboard_clear_delay) - print( - f"[{idx}] {label}: [HIDDEN] {bar} {remaining:2d}s - copied to clipboard" - ) - else: - print( - f"[{idx}] {label}: {color_text(code, 'deterministic')} {bar} {remaining:2d}s" - ) - if imported_list: - print(colored("\nImported 2FA Codes:", "green")) - for label, idx, period, _ in imported_list: - code = self.entry_manager.get_totp_code(idx, self.parent_seed) - remaining = self.entry_manager.get_totp_time_remaining(idx) - filled = int(20 * (period - remaining) / period) - bar = "[" + "#" * filled + "-" * (20 - filled) + "]" - if self.secret_mode_enabled: - copy_to_clipboard(code, self.clipboard_clear_delay) - print( - f"[{idx}] {label}: [HIDDEN] {bar} {remaining:2d}s - copied to clipboard" - ) - else: - print( - f"[{idx}] {label}: {color_text(code, 'imported')} {bar} {remaining:2d}s" - ) - sys.stdout.flush() - try: - user_input = timed_input("", 1) - if user_input.strip() == "" or user_input.strip().lower() == "b": - break - except TimeoutError: - pass - except KeyboardInterrupt: - print() - break - except Exception as e: - logging.error(f"Error displaying TOTP codes: {e}", exc_info=True) - print(colored(f"Error: Failed to display TOTP codes: {e}", "red")) + self.menu_handler.handle_display_totp_codes() + @pause_logging_for_ui def handle_verify_checksum(self) -> None: """ Handles verifying the script's checksum against the stored checksum to ensure integrity. @@ -3957,6 +4027,7 @@ class PasswordManager: logging.error(f"Error during checksum verification: {e}", exc_info=True) print(colored(f"Error: Failed to verify checksum: {e}", "red")) + @pause_logging_for_ui def handle_update_script_checksum(self) -> None: """Generate a new checksum for the manager script.""" if not confirm_action("Generate new script checksum? (Y/N): "): @@ -4014,7 +4085,6 @@ class PasswordManager: try: self.vault.decrypt_and_save_index_from_nostr(encrypted_data, merge=True) logging.info("Index file updated from Nostr successfully.") - print(colored("Index file updated from Nostr successfully.", "green")) except Exception as e: logging.error( f"Failed to decrypt and save data from Nostr: {e}", exc_info=True @@ -4047,7 +4117,7 @@ class PasswordManager: manifest, event_id = pub_snap(encrypted) else: # Fallback for tests using simplified stubs - event_id = self.nostr_client.publish_json_to_nostr(encrypted) + event_id = await self.nostr_client.publish_json_to_nostr(encrypted) self.is_dirty = False if event_id is None: return None @@ -4103,11 +4173,19 @@ class PasswordManager: logging.error(f"Failed to restore backup: {e}", exc_info=True) print(colored(f"Error: Failed to restore backup: {e}", "red")) + @pause_logging_for_ui def handle_export_database( self, dest: Path | None = None, + *, + encrypt: bool | None = None, ) -> Path | None: - """Export the current database to an encrypted portable file.""" + """Export the current database to a portable file. + + If ``encrypt`` is ``True`` (default) the payload is encrypted. When + ``encrypt`` is ``False`` the export contains plaintext data. When + ``encrypt`` is ``None`` the user is prompted interactively. + """ try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( @@ -4117,31 +4195,51 @@ class PasswordManager: parent_fingerprint=parent_fp, child_fingerprint=child_fp, ) + if encrypt is None: + encrypt = not confirm_action( + "Export database without encryption? (Y/N): " + ) path = export_backup( self.vault, self.backup_manager, dest, parent_seed=self.parent_seed, + encrypt=encrypt, ) print(colored(f"Database exported to '{path}'.", "green")) + audit_logger = getattr(self, "audit_logger", None) + if audit_logger and path is not None: + audit_logger.log("backup_export", {"path": str(path)}) return path except Exception as e: logging.error(f"Failed to export database: {e}", exc_info=True) print(colored(f"Error: Failed to export database: {e}", "red")) return None + @pause_logging_for_ui def handle_import_database(self, src: Path) -> None: """Import a portable database file, replacing the current index.""" - if not src.name.endswith(".json.enc"): + if not (src.name.endswith(".json.enc") or src.name.endswith(".json")): print( colored( - "Error: Selected file must be a SeedPass database backup (.json.enc).", + "Error: Selected file must be a SeedPass database backup (.json or .json.enc).", "red", ) ) return + # Determine encryption mode for post-processing + mode = None + try: + raw = src.read_bytes() + if src.suffix.endswith(".enc"): + raw = self.vault.encryption_manager.decrypt_data(raw, context=str(src)) + wrapper = json.loads(raw.decode("utf-8")) + mode = wrapper.get("encryption_mode") + except Exception: + mode = None + fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( self, @@ -4158,7 +4256,7 @@ class PasswordManager: src, parent_seed=self.parent_seed, ) - except InvalidToken: + except DecryptionError: logging.error("Invalid backup token during import", exc_info=True) print( colored( @@ -4181,12 +4279,31 @@ class PasswordManager: ) return + if mode == PortableMode.NONE.value: + try: + password = prompt_new_password() + iterations = self.config_manager.get_kdf_iterations() + seed_key = derive_key_from_password( + password, self.current_fingerprint, iterations=iterations + ) + seed_mgr = EncryptionManager(seed_key, self.fingerprint_dir) + seed_mgr.encrypt_parent_seed(self.parent_seed) + self.store_hashed_password(password) + except Exception as e: + logging.error( + f"Failed to set master password after import: {e}", exc_info=True + ) + print(colored(f"Error: Failed to set master password: {e}", "red")) + return + print(colored("Database imported successfully.", "green")) self.sync_vault() + @pause_logging_for_ui def handle_export_totp_codes(self) -> Path | None: """Export all 2FA codes to a JSON file for other authenticator apps.""" try: + self.ensure_key_hierarchy() fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( self, @@ -4208,7 +4325,8 @@ class PasswordManager: secret = entry["secret"] else: idx = int(entry.get("index", 0)) - secret = TotpManager.derive_secret(self.parent_seed, idx) + key = self.KEY_TOTP_DET or getattr(self, "parent_seed", None) + secret = TotpManager.derive_secret(key, idx) uri = TotpManager.make_otpauth_uri(label, secret, period, digits) totp_entries.append( { @@ -4234,7 +4352,9 @@ class PasswordManager: if confirm_action("Encrypt export with a password? (Y/N): "): password = prompt_new_password() iterations = self.config_manager.get_kdf_iterations() - key = derive_key_from_password(password, iterations=iterations) + key = derive_key_from_password( + password, self.current_fingerprint, iterations=iterations + ) enc_mgr = EncryptionManager(key, dest.parent) data_bytes = enc_mgr.encrypt_data(json_data.encode("utf-8")) dest = dest.with_suffix(dest.suffix + ".enc") @@ -4250,6 +4370,7 @@ class PasswordManager: print(colored(f"Error: Failed to export 2FA codes: {e}", "red")) return None + @pause_logging_for_ui def handle_backup_reveal_parent_seed( self, file: Path | None = None, *, password: Optional[str] = None ) -> None: @@ -4336,7 +4457,12 @@ class PasswordManager: "green", ) ) - + audit_logger = getattr(self, "audit_logger", None) + if audit_logger: + details = { + "backup_path": str(backup_path) if save and backup_path else None + } + audit_logger.log("seed_reveal", details) except Exception as e: logging.error(f"Error during parent seed backup/reveal: {e}", exc_info=True) print(colored(f"Error: Failed to backup/reveal parent seed: {e}", "red")) @@ -4372,6 +4498,15 @@ class PasswordManager: else: logging.warning("Password verification failed.") return is_correct + except DecryptionError as e: + logging.error(f"Failed to decrypt config: {e}") + print( + colored( + "Error: Could not decrypt configuration. The password may be incorrect or the file may be corrupted.", + "red", + ) + ) + return False except Exception as e: logging.error(f"Error verifying password: {e}", exc_info=True) print(colored(f"Error: Failed to verify password: {e}", "red")) @@ -4406,8 +4541,11 @@ class PasswordManager: else: # Fallback to legacy file method if config_manager unavailable hashed_password_file = self.fingerprint_dir / "hashed_password.enc" - with open(hashed_password_file, "wb") as f: - f.write(hashed.encode()) + atomic_write( + hashed_password_file, + lambda f: f.write(hashed.encode()), + mode="wb", + ) os.chmod(hashed_password_file, 0o600) logging.info("User password hashed and stored successfully.") except AttributeError: @@ -4418,8 +4556,11 @@ class PasswordManager: self.config_manager.set_password_hash(hashed) else: hashed_password_file = self.fingerprint_dir / "hashed_password.enc" - with open(hashed_password_file, "wb") as f: - f.write(hashed.encode()) + atomic_write( + hashed_password_file, + lambda f: f.write(hashed.encode()), + mode="wb", + ) os.chmod(hashed_password_file, 0o600) logging.info( "User password hashed and stored successfully (using alternative method)." @@ -4432,6 +4573,7 @@ class PasswordManager: def change_password(self, old_password: str, new_password: str) -> None: """Change the master password used for encryption.""" try: + self.ensure_key_hierarchy() if not self.verify_password(old_password): raise ValueError("Incorrect password") @@ -4440,18 +4582,17 @@ class PasswordManager: config_data = self.config_manager.load_config(require_pin=False) # Create a new encryption manager with the new password - new_key = derive_index_key(self.parent_seed) + new_key = base64.urlsafe_b64encode(self.KEY_STORAGE) iterations = self.config_manager.get_kdf_iterations() - - # Generate new salt for changed password - salt = os.urandom(16) - seed_key = derive_key_from_password(new_password, salt=salt, iterations=iterations) + seed_key = derive_key_from_password( + new_password, self.current_fingerprint, iterations=iterations + ) seed_mgr = EncryptionManager(seed_key, self.fingerprint_dir) new_enc_mgr = EncryptionManager(new_key, self.fingerprint_dir) - seed_mgr.encrypt_parent_seed(self.parent_seed, salt=salt) + seed_mgr.encrypt_parent_seed(self.parent_seed) self.vault.set_encryption_manager(new_enc_mgr) self.vault.save_index(index_data) self.config_manager.vault = self.vault @@ -4473,6 +4614,8 @@ class PasswordManager: relays=relay_list, config_manager=self.config_manager, parent_seed=getattr(self, "parent_seed", None), + key_index=self.KEY_INDEX, + account_index=self.nostr_account_idx, ) if getattr(self, "manifest_id", None) and hasattr( diff --git a/src/seedpass/core/menu_handler.py b/src/seedpass/core/menu_handler.py new file mode 100644 index 00000000..93abf0f2 --- /dev/null +++ b/src/seedpass/core/menu_handler.py @@ -0,0 +1,212 @@ +from __future__ import annotations + +import logging +import sys +from typing import TYPE_CHECKING + +from termcolor import colored + +from .entry_types import EntryType, ALL_ENTRY_TYPES +from .totp import TotpManager +import seedpass.core.manager as manager_module +from utils.color_scheme import color_text +from utils.terminal_utils import clear_header_with_notification +from utils.logging_utils import pause_logging_for_ui + +if TYPE_CHECKING: # pragma: no cover - typing only + from .manager import PasswordManager + + +class MenuHandler: + """Handle interactive menu operations for :class:`PasswordManager`.""" + + def __init__(self, manager: PasswordManager) -> None: + self.manager = manager + + @pause_logging_for_ui + def handle_list_entries(self) -> None: + """List entries and optionally show details.""" + pm = self.manager + try: + while True: + fp, parent_fp, child_fp = pm.header_fingerprint_args + clear_header_with_notification( + pm, + fp, + "Main Menu > List Entries", + parent_fingerprint=parent_fp, + child_fingerprint=child_fp, + ) + print(color_text("\nList Entries:", "menu")) + print(color_text("1. All", "menu")) + option_map: dict[str, str] = {} + for i, etype in enumerate(ALL_ENTRY_TYPES, start=2): + label = etype.replace("_", " ").title() + print(color_text(f"{i}. {label}", "menu")) + option_map[str(i)] = etype + choice = input("Select entry type or press Enter to go back: ").strip() + if choice == "1": + filter_kinds = None + elif choice in option_map: + filter_kinds = [option_map[choice]] + elif not choice: + return + else: + print(colored("Invalid choice.", "red")) + continue + + while True: + summaries = pm.entry_manager.get_entry_summaries( + filter_kinds, include_archived=False + ) + if not summaries: + if filter_kinds is None: + print(colored("No active entries found.", "yellow")) + else: + entry_label = filter_kinds[0].replace("_", " ").title() + print( + colored( + f"No active {entry_label} entries found.", + "yellow", + ) + ) + break + fp, parent_fp, child_fp = pm.header_fingerprint_args + clear_header_with_notification( + pm, + fp, + "Main Menu > List Entries", + parent_fingerprint=parent_fp, + child_fingerprint=child_fp, + ) + print(colored("\n[+] Entries:\n", "green")) + for idx, etype, label in summaries: + if filter_kinds is None: + display_type = etype.capitalize() + print(colored(f"{idx}. {display_type} - {label}", "cyan")) + else: + print(colored(f"{idx}. {label}", "cyan")) + idx_input = input( + "Enter index to view details or press Enter to go back: " + ).strip() + if not idx_input: + break + if not idx_input.isdigit(): + print(colored("Invalid index.", "red")) + continue + pm.show_entry_details_by_index(int(idx_input)) + except Exception as e: # pragma: no cover - defensive + logging.error(f"Failed to list entries: {e}", exc_info=True) + print(colored(f"Error: Failed to list entries: {e}", "red")) + + @pause_logging_for_ui + def handle_display_totp_codes(self) -> None: + """Display all stored TOTP codes with a countdown progress bar.""" + pm = self.manager + try: + fp, parent_fp, child_fp = pm.header_fingerprint_args + clear_header_with_notification( + pm, + fp, + "Main Menu > 2FA Codes", + parent_fingerprint=parent_fp, + child_fingerprint=child_fp, + ) + data = pm.entry_manager.vault.load_index() + entries = data.get("entries", {}) + totp_list: list[tuple[str, int, int, bool]] = [] + for idx_str, entry in entries.items(): + if pm._entry_type_str(entry) == EntryType.TOTP.value and not entry.get( + "archived", entry.get("blacklisted", False) + ): + label = entry.get("label", "") + period = int(entry.get("period", 30)) + imported = "secret" in entry + totp_list.append((label, int(idx_str), period, imported)) + + if not totp_list: + pm.notify("No 2FA entries found.", level="WARNING") + return + + totp_list.sort(key=lambda t: t[0].lower()) + + totp_secrets: dict[int, str] = {} + key = getattr(pm, "KEY_TOTP_DET", None) or getattr(pm, "parent_seed", None) + for _, idx, _, _ in totp_list: + try: + totp_secrets[idx] = pm.entry_manager.get_totp_secret(idx, key) + except Exception: + pass + + print(colored("Press Enter to return to the menu.", "cyan")) + while True: + fp, parent_fp, child_fp = pm.header_fingerprint_args + clear_header_with_notification( + pm, + fp, + "Main Menu > 2FA Codes", + parent_fingerprint=parent_fp, + child_fingerprint=child_fp, + ) + print(colored("Press Enter to return to the menu.", "cyan")) + generated = [t for t in totp_list if not t[3]] + imported_list = [t for t in totp_list if t[3]] + if generated: + print(colored("\nGenerated 2FA Codes:", "green")) + for label, idx, period, _ in generated: + secret = totp_secrets.get(idx) + code = ( + TotpManager.current_code_from_secret(secret) + if secret + else "ERROR" + ) + remaining = pm.entry_manager.get_totp_time_remaining(idx) + filled = int(20 * (period - remaining) / period) + bar = "[" + "#" * filled + "-" * (20 - filled) + "]" + if pm.secret_mode_enabled: + if manager_module.copy_to_clipboard( + code, pm.clipboard_clear_delay + ): + print( + f"[{idx}] {label}: [HIDDEN] {bar} {remaining:2d}s - copied to clipboard" + ) + else: + print( + f"[{idx}] {label}: {color_text(code, 'deterministic')} {bar} {remaining:2d}s" + ) + if imported_list: + print(colored("\nImported 2FA Codes:", "green")) + for label, idx, period, _ in imported_list: + secret = totp_secrets.get(idx) + code = ( + TotpManager.current_code_from_secret(secret) + if secret + else "ERROR" + ) + remaining = pm.entry_manager.get_totp_time_remaining(idx) + filled = int(20 * (period - remaining) / period) + bar = "[" + "#" * filled + "-" * (20 - filled) + "]" + if pm.secret_mode_enabled: + if manager_module.copy_to_clipboard( + code, pm.clipboard_clear_delay + ): + print( + f"[{idx}] {label}: [HIDDEN] {bar} {remaining:2d}s - copied to clipboard" + ) + else: + print( + f"[{idx}] {label}: {color_text(code, 'imported')} {bar} {remaining:2d}s" + ) + sys.stdout.flush() + try: + user_input = manager_module.timed_input("", 1) + if user_input.strip() == "" or user_input.strip().lower() == "b": + break + except TimeoutError: + pass + except KeyboardInterrupt: + print() + break + except Exception as e: # pragma: no cover - defensive + logging.error(f"Error displaying TOTP codes: {e}", exc_info=True) + print(colored(f"Error: Failed to display TOTP codes: {e}", "red")) diff --git a/src/seedpass/core/password_generation.py b/src/seedpass/core/password_generation.py index 4044c5c6..60d6a8de 100644 --- a/src/seedpass/core/password_generation.py +++ b/src/seedpass/core/password_generation.py @@ -11,14 +11,18 @@ Ensure that all dependencies are installed and properly configured in your envir Never ever ever use Random Salt. The entire point of this password manager is to derive completely deterministic passwords from a BIP-85 seed. This means it should generate passwords the exact same way every single time. Salts would break this functionality and is not appropriate for this software's use case. +To keep behaviour stable across Python versions, the shuffling logic uses an +HMAC-SHA256-based Fisher–Yates shuffle instead of ``random.Random``. The HMAC +is keyed with the derived password bytes, providing deterministic yet +cryptographically strong pseudo-randomness without relying on Python's +non-stable random implementation. """ import os import logging import hashlib import string -import random -import traceback +import hmac import base64 from typing import Optional from dataclasses import dataclass @@ -109,10 +113,12 @@ class PasswordGenerator: self.bip85 = bip85 self.policy = policy or PasswordPolicy() - # Derive seed bytes from parent_seed using BIP39 (handled by EncryptionManager) - self.seed_bytes = self.encryption_manager.derive_seed_from_mnemonic( - self.parent_seed - ) + if isinstance(parent_seed, (bytes, bytearray)): + self.seed_bytes = bytes(parent_seed) + else: + self.seed_bytes = self.encryption_manager.derive_seed_from_mnemonic( + self.parent_seed + ) logger.debug("PasswordGenerator initialized successfully.") except Exception as e: @@ -122,8 +128,8 @@ class PasswordGenerator: def _derive_password_entropy(self, index: int) -> bytes: """Derive deterministic entropy for password generation.""" - entropy = self.bip85.derive_entropy(index=index, bytes_len=64, app_no=32) - logger.debug(f"Derived entropy: {entropy.hex()}") + entropy = self.bip85.derive_entropy(index=index, entropy_bytes=64, app_no=32) + logger.debug("Entropy derived for password generation.") hkdf = HKDF( algorithm=hashes.SHA256(), @@ -133,26 +139,43 @@ class PasswordGenerator: backend=default_backend(), ) hkdf_derived = hkdf.derive(entropy) - logger.debug(f"Derived key using HKDF: {hkdf_derived.hex()}") + logger.debug("Derived key using HKDF.") dk = hashlib.pbkdf2_hmac("sha256", entropy, b"", 100000) - logger.debug(f"Derived key using PBKDF2: {dk.hex()}") + logger.debug("Derived key using PBKDF2.") return dk def _map_entropy_to_chars(self, dk: bytes, alphabet: str) -> str: """Map derived bytes to characters from the provided alphabet.""" password = "".join(alphabet[byte % len(alphabet)] for byte in dk) - logger.debug(f"Password after mapping to all allowed characters: {password}") + logger.debug("Mapped entropy to allowed characters.") return password + def _fisher_yates_hmac(self, items: list[str], key: bytes) -> list[str]: + """Shuffle ``items`` in a deterministic yet cryptographically sound manner. + + A Fisher–Yates shuffle is driven by an HMAC-SHA256 based + pseudo-random number generator seeded with ``key``. Unlike + :class:`random.Random`, this approach is stable across Python + versions while still deriving all of its entropy from ``key``. + """ + + counter = 0 + for i in range(len(items) - 1, 0, -1): + msg = counter.to_bytes(4, "big") + digest = hmac.new(key, msg, hashlib.sha256).digest() + j = int.from_bytes(digest, "big") % (i + 1) + items[i], items[j] = items[j], items[i] + counter += 1 + return items + def _shuffle_deterministically(self, password: str, dk: bytes) -> str: - """Deterministically shuffle characters using derived bytes.""" - shuffle_seed = int.from_bytes(dk, "big") - rng = random.Random(shuffle_seed) + """Deterministically shuffle characters using an HMAC-based PRNG.""" + password_chars = list(password) - rng.shuffle(password_chars) - shuffled = "".join(password_chars) - logger.debug("Shuffled password deterministically.") + shuffled_chars = self._fisher_yates_hmac(password_chars, dk) + shuffled = "".join(shuffled_chars) + logger.debug("Shuffled password deterministically using HMAC-Fisher-Yates.") return shuffled def generate_password( @@ -226,7 +249,7 @@ class PasswordGenerator: extra = self._map_entropy_to_chars(dk, all_allowed) password += extra password = self._shuffle_deterministically(password, dk) - logger.debug(f"Extended password: {password}") + logger.debug("Extended password to meet length requirement.") # Trim the password to the desired length and enforce complexity on # the final result. Complexity enforcement is repeated here because @@ -239,7 +262,7 @@ class PasswordGenerator: ) password = self._shuffle_deterministically(password, dk) logger.debug( - f"Final password (trimmed to {length} chars with complexity enforced): {password}" + f"Generated final password of length {length} with complexity enforced." ) return password @@ -311,34 +334,28 @@ class PasswordGenerator: index = get_dk_value() % len(password_chars) char = uppercase[get_dk_value() % len(uppercase)] password_chars[index] = char - logger.debug( - f"Added uppercase letter '{char}' at position {index}." - ) + logger.debug(f"Added uppercase letter at position {index}.") if current_lower < min_lower: for _ in range(min_lower - current_lower): index = get_dk_value() % len(password_chars) char = lowercase[get_dk_value() % len(lowercase)] password_chars[index] = char - logger.debug( - f"Added lowercase letter '{char}' at position {index}." - ) + logger.debug(f"Added lowercase letter at position {index}.") if current_digits < min_digits: for _ in range(min_digits - current_digits): index = get_dk_value() % len(password_chars) char = digits[get_dk_value() % len(digits)] password_chars[index] = char - logger.debug(f"Added digit '{char}' at position {index}.") + logger.debug(f"Added digit at position {index}.") if special and current_special < min_special: for _ in range(min_special - current_special): index = get_dk_value() % len(password_chars) char = special[get_dk_value() % len(special)] password_chars[index] = char - logger.debug( - f"Added special character '{char}' at position {index}." - ) + logger.debug(f"Added special character at position {index}.") # Additional deterministic inclusion of symbols to increase score if special: @@ -352,9 +369,7 @@ class PasswordGenerator: index = get_dk_value() % len(password_chars) char = special[get_dk_value() % len(special)] password_chars[index] = char - logger.debug( - f"Added additional symbol '{char}' at position {index}." - ) + logger.debug(f"Added additional symbol at position {index}.") # Ensure balanced distribution by assigning different character types to specific segments # Example: Divide password into segments and assign different types @@ -372,19 +387,15 @@ class PasswordGenerator: if i == 0 and password_chars[j] not in uppercase: char = uppercase[get_dk_value() % len(uppercase)] password_chars[j] = char - logger.debug( - f"Assigned uppercase letter '{char}' to position {j}." - ) + logger.debug(f"Assigned uppercase letter to position {j}.") elif i == 1 and password_chars[j] not in lowercase: char = lowercase[get_dk_value() % len(lowercase)] password_chars[j] = char - logger.debug( - f"Assigned lowercase letter '{char}' to position {j}." - ) + logger.debug(f"Assigned lowercase letter to position {j}.") elif i == 2 and password_chars[j] not in digits: char = digits[get_dk_value() % len(digits)] password_chars[j] = char - logger.debug(f"Assigned digit '{char}' to position {j}.") + logger.debug(f"Assigned digit to position {j}.") elif ( special and i == len(char_types) - 1 @@ -392,17 +403,18 @@ class PasswordGenerator: ): char = special[get_dk_value() % len(special)] password_chars[j] = char - logger.debug( - f"Assigned special character '{char}' to position {j}." - ) + logger.debug(f"Assigned special character to position {j}.") - # Shuffle again to distribute the characters more evenly - shuffle_seed = ( - int.from_bytes(dk, "big") + dk_index - ) # Modify seed to vary shuffle - rng = random.Random(shuffle_seed) - rng.shuffle(password_chars) - logger.debug(f"Shuffled password characters for balanced distribution.") + # Shuffle again to distribute the characters more evenly. The key is + # tweaked with the current ``dk_index`` so that each call produces a + # unique but deterministic ordering. + shuffle_key = hmac.new( + dk, dk_index.to_bytes(4, "big"), hashlib.sha256 + ).digest() + password_chars = self._fisher_yates_hmac(password_chars, shuffle_key) + logger.debug( + "Shuffled password characters for balanced distribution using HMAC-Fisher-Yates." + ) # Final counts after modifications final_upper = sum(1 for c in password_chars if c in uppercase) @@ -423,7 +435,7 @@ class PasswordGenerator: def derive_ssh_key(bip85: BIP85, idx: int) -> bytes: """Derive 32 bytes of entropy suitable for an SSH key.""" - return bip85.derive_entropy(index=idx, bytes_len=32, app_no=32) + return bip85.derive_entropy(index=idx, entropy_bytes=32, app_no=32) def derive_ssh_key_pair(parent_seed: str, index: int) -> tuple[str, str]: @@ -457,7 +469,13 @@ def derive_seed_phrase(bip85: BIP85, idx: int, words: int = 24) -> str: def derive_pgp_key( bip85: BIP85, idx: int, key_type: str = "ed25519", user_id: str = "" ) -> tuple[str, str]: - """Derive a deterministic PGP private key and return it with its fingerprint.""" + """Derive a deterministic PGP private key and return it with its fingerprint. + + For RSA keys the randomness required during key generation is provided by + an HMAC-SHA256 based deterministic generator seeded from the BIP-85 + entropy. This avoids use of Python's ``random`` module while ensuring the + output remains stable across Python versions. + """ from pgpy import PGPKey, PGPUID from pgpy.packet.packets import PrivKeyV4 @@ -483,20 +501,24 @@ def derive_pgp_key( import hashlib import datetime - entropy = bip85.derive_entropy(index=idx, bytes_len=32, app_no=32) + entropy = bip85.derive_entropy(index=idx, entropy_bytes=32, app_no=32) created = datetime.datetime(2000, 1, 1, tzinfo=datetime.timezone.utc) if key_type.lower() == "rsa": class DRNG: + """HMAC-SHA256 based deterministic random generator.""" + def __init__(self, seed: bytes) -> None: - self.seed = seed + self.key = seed + self.counter = 0 def __call__(self, n: int) -> bytes: # pragma: no cover - deterministic out = b"" while len(out) < n: - self.seed = hashlib.sha256(self.seed).digest() - out += self.seed + msg = self.counter.to_bytes(4, "big") + out += hmac.new(self.key, msg, hashlib.sha256).digest() + self.counter += 1 return out[:n] rsa_key = RSA.generate(2048, randfunc=DRNG(entropy)) diff --git a/src/seedpass/core/portable_backup.py b/src/seedpass/core/portable_backup.py index a76879be..bc00c9ab 100644 --- a/src/seedpass/core/portable_backup.py +++ b/src/seedpass/core/portable_backup.py @@ -21,6 +21,7 @@ from utils.key_derivation import ( ) from .encryption import EncryptionManager from utils.checksum import json_checksum, canonical_json_dumps +from .state_manager import StateManager logger = logging.getLogger(__name__) @@ -32,6 +33,7 @@ class PortableMode(Enum): """Encryption mode for portable exports.""" SEED_ONLY = EncryptionMode.SEED_ONLY.value + NONE = "none" def _derive_export_key(seed: str) -> bytes: @@ -47,8 +49,15 @@ def export_backup( *, publish: bool = False, parent_seed: str | None = None, + encrypt: bool = True, ) -> Path: - """Export the current vault state to a portable encrypted file.""" + """Export the current vault state to a portable file. + + When ``encrypt`` is ``True`` (the default) the payload is encrypted with a + key derived from the parent seed. When ``encrypt`` is ``False`` the payload + is written in plaintext and the wrapper records an ``encryption_mode`` of + :data:`PortableMode.NONE`. + """ if dest_path is None: ts = int(time.time()) @@ -57,24 +66,32 @@ def export_backup( dest_path = dest_dir / EXPORT_NAME_TEMPLATE.format(ts=ts) index_data = vault.load_index() - seed = ( - parent_seed - if parent_seed is not None - else vault.encryption_manager.decrypt_parent_seed() - ) - key = _derive_export_key(seed) - enc_mgr = EncryptionManager(key, vault.fingerprint_dir) - canonical = canonical_json_dumps(index_data) - payload_bytes = enc_mgr.encrypt_data(canonical.encode("utf-8")) + + if encrypt: + seed = ( + parent_seed + if parent_seed is not None + else vault.encryption_manager.decrypt_parent_seed() + ) + key = _derive_export_key(seed) + enc_mgr = EncryptionManager(key, vault.fingerprint_dir) + payload_bytes = enc_mgr.encrypt_data(canonical.encode("utf-8")) + mode = PortableMode.SEED_ONLY + cipher = "aes-gcm" + else: + payload_bytes = canonical.encode("utf-8") + mode = PortableMode.NONE + cipher = "none" + checksum = json_checksum(index_data) wrapper = { "format_version": FORMAT_VERSION, "created_at": int(time.time()), "fingerprint": vault.fingerprint_dir.name, - "encryption_mode": PortableMode.SEED_ONLY.value, - "cipher": "aes-gcm", + "encryption_mode": mode.value, + "cipher": cipher, "checksum": checksum, "payload": base64.b64encode(payload_bytes).decode("utf-8"), } @@ -90,10 +107,12 @@ def export_backup( enc_file.write_bytes(encrypted) os.chmod(enc_file, 0o600) try: + idx = StateManager(vault.fingerprint_dir).state.get("nostr_account_idx", 0) client = NostrClient( vault.encryption_manager, vault.fingerprint_dir.name, config_manager=backup_manager.config_manager, + account_index=idx, ) asyncio.run(client.publish_snapshot(encrypted)) except Exception: @@ -112,24 +131,30 @@ def import_backup( raw = Path(path).read_bytes() if path.suffix.endswith(".enc"): - raw = vault.encryption_manager.decrypt_data(raw) + raw = vault.encryption_manager.decrypt_data(raw, context=str(path)) wrapper = json.loads(raw.decode("utf-8")) if wrapper.get("format_version") != FORMAT_VERSION: raise ValueError("Unsupported backup format") - if wrapper.get("encryption_mode") != PortableMode.SEED_ONLY.value: - raise ValueError("Unsupported encryption mode") + mode = wrapper.get("encryption_mode") payload = base64.b64decode(wrapper["payload"]) - seed = ( - parent_seed - if parent_seed is not None - else vault.encryption_manager.decrypt_parent_seed() - ) - key = _derive_export_key(seed) - enc_mgr = EncryptionManager(key, vault.fingerprint_dir) - index_bytes = enc_mgr.decrypt_data(payload) + if mode == PortableMode.SEED_ONLY.value: + seed = ( + parent_seed + if parent_seed is not None + else vault.encryption_manager.decrypt_parent_seed() + ) + key = _derive_export_key(seed) + enc_mgr = EncryptionManager(key, vault.fingerprint_dir) + enc_mgr._legacy_migrate_flag = False + index_bytes = enc_mgr.decrypt_data(payload, context="backup payload") + elif mode == PortableMode.NONE.value: + index_bytes = payload + else: + raise ValueError("Unsupported encryption mode") + index = json.loads(index_bytes.decode("utf-8")) checksum = json_checksum(index) diff --git a/src/seedpass/core/profile_service.py b/src/seedpass/core/profile_service.py new file mode 100644 index 00000000..821165e3 --- /dev/null +++ b/src/seedpass/core/profile_service.py @@ -0,0 +1,109 @@ +from __future__ import annotations + +import logging +from typing import Optional, TYPE_CHECKING + +from termcolor import colored + +import seedpass.core.manager as manager_module + +from utils.password_prompt import prompt_existing_password + +if TYPE_CHECKING: # pragma: no cover - typing only + from .manager import PasswordManager + from nostr.client import NostrClient + + +class ProfileService: + """Profile-related operations for :class:`PasswordManager`.""" + + def __init__(self, manager: PasswordManager) -> None: + self.manager = manager + + def handle_switch_fingerprint(self, *, password: Optional[str] = None) -> bool: + """Handle switching to a different seed profile.""" + pm = self.manager + try: + print(colored("\nAvailable Seed Profiles:", "cyan")) + fingerprints = pm.fingerprint_manager.list_fingerprints() + for idx, fp in enumerate(fingerprints, start=1): + display = ( + pm.fingerprint_manager.display_name(fp) + if hasattr(pm.fingerprint_manager, "display_name") + else fp + ) + print(colored(f"{idx}. {display}", "cyan")) + + choice = input("Select a seed profile by number to switch: ").strip() + if not choice.isdigit() or not (1 <= int(choice) <= len(fingerprints)): + print(colored("Invalid selection. Returning to main menu.", "red")) + return False + + selected_fingerprint = fingerprints[int(choice) - 1] + pm.fingerprint_manager.current_fingerprint = selected_fingerprint + pm.current_fingerprint = selected_fingerprint + if not getattr(pm, "manifest_id", None): + pm.manifest_id = None + + pm.fingerprint_dir = pm.fingerprint_manager.get_current_fingerprint_dir() + if not pm.fingerprint_dir: + print( + colored( + f"Error: Seed profile directory for {selected_fingerprint} not found.", + "red", + ) + ) + return False + + if password is None: + password = prompt_existing_password( + "Enter the master password for the selected seed profile: " + ) + + if not pm.setup_encryption_manager( + pm.fingerprint_dir, password, exit_on_fail=False + ): + return False + + pm.initialize_bip85() + pm.initialize_managers() + pm.start_background_sync() + print(colored(f"Switched to seed profile {selected_fingerprint}.", "green")) + + try: + pm.nostr_client = manager_module.NostrClient( + encryption_manager=pm.encryption_manager, + fingerprint=pm.current_fingerprint, + config_manager=getattr(pm, "config_manager", None), + parent_seed=getattr(pm, "parent_seed", None), + key_index=pm.KEY_INDEX, + account_index=pm.nostr_account_idx, + ) + if getattr(pm, "manifest_id", None) and hasattr( + pm.nostr_client, "_state_lock" + ): + from nostr.backup_models import Manifest + + with pm.nostr_client._state_lock: + pm.nostr_client.current_manifest_id = pm.manifest_id + pm.nostr_client.current_manifest = Manifest( + ver=1, + algo="gzip", + chunks=[], + delta_since=pm.delta_since or None, + ) + logging.info( + f"NostrClient re-initialized with seed profile {pm.current_fingerprint}." + ) + except Exception as e: + logging.error(f"Failed to re-initialize NostrClient: {e}") + print( + colored(f"Error: Failed to re-initialize NostrClient: {e}", "red") + ) + return False + + return True + except Exception as e: # pragma: no cover - defensive + logging.error(f"Error during seed profile switching: {e}", exc_info=True) + print(colored(f"Error: Failed to switch seed profiles: {e}", "red")) + return False diff --git a/src/seedpass/core/state_manager.py b/src/seedpass/core/state_manager.py index f2ca11e6..74238f52 100644 --- a/src/seedpass/core/state_manager.py +++ b/src/seedpass/core/state_manager.py @@ -26,6 +26,7 @@ class StateManager: "manifest_id": None, "delta_since": 0, "relays": list(DEFAULT_RELAYS), + "nostr_account_idx": 0, } with shared_lock(self.state_path) as fh: fh.seek(0) @@ -37,6 +38,7 @@ class StateManager: "manifest_id": None, "delta_since": 0, "relays": list(DEFAULT_RELAYS), + "nostr_account_idx": 0, } try: obj = json.loads(data.decode()) @@ -47,6 +49,7 @@ class StateManager: obj.setdefault("manifest_id", None) obj.setdefault("delta_since", 0) obj.setdefault("relays", list(DEFAULT_RELAYS)) + obj.setdefault("nostr_account_idx", 0) return obj def _save(self, data: dict) -> None: diff --git a/src/seedpass/core/totp.py b/src/seedpass/core/totp.py index e93032a8..7164d650 100644 --- a/src/seedpass/core/totp.py +++ b/src/seedpass/core/totp.py @@ -2,8 +2,11 @@ from __future__ import annotations +import os import sys import time +import base64 +from typing import Union from urllib.parse import quote from urllib.parse import urlparse, parse_qs, unquote @@ -14,17 +17,24 @@ import pyotp from utils import key_derivation +def random_totp_secret(length: int = 20) -> str: + """Return a random Base32 encoded TOTP secret.""" + return base64.b32encode(os.urandom(length)).decode("ascii").rstrip("=") + + class TotpManager: """Helper methods for TOTP secrets and codes.""" @staticmethod - def derive_secret(seed: str, index: int) -> str: - """Derive a TOTP secret from a BIP39 seed and index.""" + def derive_secret(seed: Union[str, bytes], index: int) -> str: + """Derive a TOTP secret from a seed or raw key and index.""" return key_derivation.derive_totp_secret(seed, index) @classmethod - def current_code(cls, seed: str, index: int, timestamp: int | None = None) -> str: - """Return the TOTP code for the given seed and index.""" + def current_code( + cls, seed: Union[str, bytes], index: int, timestamp: int | None = None + ) -> str: + """Return the TOTP code for the given seed/key and index.""" secret = cls.derive_secret(seed, index) totp = pyotp.TOTP(secret) if timestamp is None: diff --git a/src/seedpass/core/vault.py b/src/seedpass/core/vault.py index e1a6fbc3..a0a639d1 100644 --- a/src/seedpass/core/vault.py +++ b/src/seedpass/core/vault.py @@ -3,8 +3,19 @@ from pathlib import Path from typing import Optional, Union from os import PathLike +import shutil -from .encryption import EncryptionManager +from termcolor import colored +from cryptography.fernet import InvalidToken + +from .encryption import ( + EncryptionManager, + LegacyFormatRequiresMigrationError, + USE_ORJSON, + json_lib, +) +from utils.key_derivation import KdfConfig, CURRENT_KDF_VERSION +from utils.password_prompt import prompt_existing_password class Vault: @@ -22,26 +33,164 @@ class Vault: self.fingerprint_dir = Path(fingerprint_dir) self.index_file = self.fingerprint_dir / self.INDEX_FILENAME self.config_file = self.fingerprint_dir / self.CONFIG_FILENAME + self.migrated_from_legacy = False def set_encryption_manager(self, manager: EncryptionManager) -> None: """Replace the internal encryption manager.""" self.encryption_manager = manager + def _hkdf_kdf(self) -> KdfConfig: + return KdfConfig( + name="hkdf", version=CURRENT_KDF_VERSION, params={}, salt_b64="" + ) + # ----- Password index helpers ----- - def load_index(self) -> dict: - """Return decrypted password index data as a dict, applying migrations.""" + def load_index(self, *, return_migration_flags: bool = False): + """Return decrypted password index data, applying migrations. + + If a legacy ``seedpass_passwords_db.json.enc`` file is detected, the + user is prompted to migrate it. A backup copy of the legacy file (and + its checksum) is saved under ``legacy_backups`` within the fingerprint + directory before renaming to the new filename. + + When ``return_migration_flags`` is ``True`` the tuple + ``(data, migrated, last_migration_performed)`` is returned where + ``migrated`` indicates whether any migration occurred and + ``last_migration_performed`` reflects whether the underlying + :class:`EncryptionManager` reported a conversion. + """ + legacy_file = self.fingerprint_dir / "seedpass_passwords_db.json.enc" + self.migrated_from_legacy = False + legacy_detected = False + backup_dir = None if legacy_file.exists() and not self.index_file.exists(): + print(colored("Legacy index detected.", "yellow")) + resp = ( + input("Would you like to migrate this to the new index format? [y/N]: ") + .strip() + .lower() + ) + if resp != "y": + raise RuntimeError("Migration declined by user") + legacy_checksum = ( self.fingerprint_dir / "seedpass_passwords_db_checksum.txt" ) + backup_dir = self.fingerprint_dir / "legacy_backups" + backup_dir.mkdir(exist_ok=True) + shutil.copy2(legacy_file, backup_dir / legacy_file.name) + if legacy_checksum.exists(): + shutil.copy2(legacy_checksum, backup_dir / legacy_checksum.name) + legacy_file.rename(self.index_file) if legacy_checksum.exists(): legacy_checksum.rename( self.fingerprint_dir / "seedpass_entries_db_checksum.txt" ) - data = self.encryption_manager.load_json_data(self.index_file) + # Remove any leftover legacy files to avoid triggering migration again + for stray in self.fingerprint_dir.glob("seedpass_passwords_db*.enc"): + try: + stray.unlink() + except FileNotFoundError: + pass + stray_checksum = self.fingerprint_dir / "seedpass_passwords_db_checksum.txt" + if stray_checksum.exists(): + stray_checksum.unlink() + + legacy_detected = True + print( + colored( + "Migration complete. Original index backed up to 'legacy_backups'", + "green", + ) + ) + + try: + data, kdf = self.encryption_manager.load_json_data( + self.index_file, return_kdf=True + ) + migration_performed = getattr( + self.encryption_manager, "last_migration_performed", False + ) + if kdf.version < CURRENT_KDF_VERSION: + new_kdf = KdfConfig( + name=kdf.name, + version=CURRENT_KDF_VERSION, + params=kdf.params, + salt_b64=kdf.salt_b64, + ) + self.encryption_manager.save_json_data( + data, self.index_file, kdf=new_kdf + ) + self.encryption_manager.update_checksum(self.index_file) + migration_performed = True + except LegacyFormatRequiresMigrationError: + print( + colored( + "Failed to decrypt index with current key. This may be a legacy index.", + "red", + ) + ) + resp = input( + "\nChoose an option:\n" + "1. Open legacy index without migrating\n" + "2. Migrate to new format.\n" + "Selection [1/2]: " + ).strip() + if resp == "1": + self.encryption_manager._legacy_migrate_flag = False + self.encryption_manager.last_migration_performed = False + elif resp == "2": + self.encryption_manager._legacy_migrate_flag = True + self.encryption_manager.last_migration_performed = True + else: + raise InvalidToken( + "User declined legacy decryption or provided invalid choice." + ) + password = prompt_existing_password( + "Enter your master password for legacy decryption: " + ) + with self.index_file.open("rb") as fh: + encrypted_data = fh.read() + decrypted = self.encryption_manager.decrypt_legacy( + encrypted_data, password, context=str(self.index_file) + ) + if USE_ORJSON: + data = json_lib.loads(decrypted) + else: + data = json_lib.loads(decrypted.decode("utf-8")) + if self.encryption_manager._legacy_migrate_flag: + self.encryption_manager.save_json_data( + data, self.index_file, kdf=self._hkdf_kdf() + ) + self.encryption_manager.update_checksum(self.index_file) + migration_performed = getattr( + self.encryption_manager, "last_migration_performed", False + ) + except Exception as exc: # noqa: BLE001 - surface clear error and restore + if legacy_detected and backup_dir is not None: + backup_file = backup_dir / legacy_file.name + legacy_checksum_path = ( + self.fingerprint_dir / "seedpass_passwords_db_checksum.txt" + ) + backup_checksum = backup_dir / legacy_checksum_path.name + try: + if self.index_file.exists(): + self.index_file.unlink() + shutil.copy2(backup_file, legacy_file) + checksum_new = ( + self.fingerprint_dir / "seedpass_entries_db_checksum.txt" + ) + if checksum_new.exists(): + checksum_new.unlink() + if backup_checksum.exists(): + shutil.copy2(backup_checksum, legacy_checksum_path) + finally: + self.migrated_from_legacy = False + raise RuntimeError(f"Migration failed: {exc}") from exc + from .migrations import apply_migrations, LATEST_VERSION version = data.get("schema_version", 0) @@ -49,24 +198,78 @@ class Vault: raise ValueError( f"File schema version {version} is newer than supported {LATEST_VERSION}" ) - data = apply_migrations(data) + schema_migrated = version < LATEST_VERSION + + try: + data = apply_migrations(data) + if schema_migrated: + self.encryption_manager.save_json_data( + data, self.index_file, kdf=self._hkdf_kdf() + ) + self.encryption_manager.update_checksum(self.index_file) + except Exception as exc: # noqa: BLE001 - surface clear error and restore + if legacy_detected and backup_dir is not None: + backup_file = backup_dir / legacy_file.name + legacy_checksum_path = ( + self.fingerprint_dir / "seedpass_passwords_db_checksum.txt" + ) + backup_checksum = backup_dir / legacy_checksum_path.name + try: + if self.index_file.exists(): + self.index_file.unlink() + shutil.copy2(backup_file, legacy_file) + checksum_new = ( + self.fingerprint_dir / "seedpass_entries_db_checksum.txt" + ) + if checksum_new.exists(): + checksum_new.unlink() + if backup_checksum.exists(): + shutil.copy2(backup_checksum, legacy_checksum_path) + finally: + self.migrated_from_legacy = False + raise RuntimeError(f"Migration failed: {exc}") from exc + + self.migrated_from_legacy = ( + legacy_detected or migration_performed or schema_migrated + ) + if return_migration_flags: + return data, self.migrated_from_legacy, migration_performed return data def save_index(self, data: dict) -> None: """Encrypt and write password index.""" - self.encryption_manager.save_json_data(data, self.index_file) + self.encryption_manager.save_json_data( + data, self.index_file, kdf=self._hkdf_kdf() + ) def get_encrypted_index(self) -> Optional[bytes]: """Return the encrypted index bytes if present.""" return self.encryption_manager.get_encrypted_index() def decrypt_and_save_index_from_nostr( - self, encrypted_data: bytes, *, strict: bool = True, merge: bool = False - ) -> bool: - """Decrypt Nostr payload and update the local index.""" - return self.encryption_manager.decrypt_and_save_index_from_nostr( + self, + encrypted_data: bytes, + *, + strict: bool = True, + merge: bool = False, + return_migration_flag: bool = False, + ): + """Decrypt Nostr payload and update the local index. + + Returns ``True``/``False`` for success by default. When + ``return_migration_flag`` is ``True`` a tuple ``(success, migrated)`` is + returned, where ``migrated`` indicates whether any legacy migration + occurred. + """ + result = self.encryption_manager.decrypt_and_save_index_from_nostr( encrypted_data, strict=strict, merge=merge ) + self.migrated_from_legacy = result and getattr( + self.encryption_manager, "last_migration_performed", False + ) + if return_migration_flag: + return result, self.migrated_from_legacy + return result # ----- Config helpers ----- def load_config(self) -> dict: @@ -75,4 +278,6 @@ class Vault: def save_config(self, config: dict) -> None: """Encrypt and persist configuration.""" - self.encryption_manager.save_json_data(config, self.config_file) + self.encryption_manager.save_json_data( + config, self.config_file, kdf=self._hkdf_kdf() + ) diff --git a/src/seedpass/errors.py b/src/seedpass/errors.py new file mode 100644 index 00000000..3334c688 --- /dev/null +++ b/src/seedpass/errors.py @@ -0,0 +1,13 @@ +"""Compatibility layer for historic exception types.""" + +from .core.errors import SeedPassError + + +class VaultLockedError(SeedPassError): + """Raised when an operation requires an unlocked vault.""" + + def __init__(self, message: str = "Vault is locked") -> None: + super().__init__(message) + + +__all__ = ["VaultLockedError", "SeedPassError"] diff --git a/src/seedpass_gui/__main__.py b/src/seedpass_gui/__main__.py index 37c2a2dd..868d99ef 100644 --- a/src/seedpass_gui/__main__.py +++ b/src/seedpass_gui/__main__.py @@ -1,4 +1,4 @@ -from .app import main +from . import main if __name__ == "__main__": main() diff --git a/src/seedpass_gui/app.py b/src/seedpass_gui/app.py index 14af8ae9..f7543351 100644 --- a/src/seedpass_gui/app.py +++ b/src/seedpass_gui/app.py @@ -394,7 +394,7 @@ class TotpViewerWindow(toga.Window): def refresh_codes(self) -> None: self.table.data = [] for idx, label, *_rest in self.entries.list_entries( - filter_kind=EntryType.TOTP.value + filter_kinds=[EntryType.TOTP.value] ): entry = self.entries.retrieve_entry(idx) diff --git a/src/tests/conftest.py b/src/tests/conftest.py index 4aa4e0d5..f46b6f30 100644 --- a/src/tests/conftest.py +++ b/src/tests/conftest.py @@ -1,5 +1,40 @@ +import importlib.util import logging +import sys +from pathlib import Path + import pytest +from types import SimpleNamespace +from httpx import ASGITransport, AsyncClient +import bcrypt + +sys.path.append(str(Path(__file__).resolve().parents[1])) + +from seedpass import api +from seedpass.core.entry_types import EntryType +from helpers import ( + create_vault, + TEST_PASSWORD, + TEST_SEED, + DummyBuilder, + DummyFilter, + DummyTag, + DummyTimestamp, + DummyEventId, + DummyRelayClient, +) +from seedpass.core.backup import BackupManager +from seedpass.core.config_manager import ConfigManager +from seedpass.core.entry_management import EntryManager +from seedpass.core.manager import EncryptionMode, PasswordManager +from seedpass.core.encryption import EncryptionManager as EncMgr + + +@pytest.fixture( + params=["asyncio"] + (["trio"] if importlib.util.find_spec("trio") else []) +) +def anyio_backend(request): + return request.param @pytest.fixture(autouse=True) @@ -49,3 +84,113 @@ def pytest_collection_modifyitems( for item in items: if "desktop" in item.keywords: item.add_marker(skip_desktop) + + +@pytest.fixture +def vault(tmp_path): + vault, _ = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + return vault + + +@pytest.fixture +def password_manager(vault, tmp_path): + cfg_mgr = ConfigManager(vault, tmp_path) + backup_mgr = BackupManager(tmp_path, cfg_mgr) + entry_mgr = EntryManager(vault, backup_mgr) + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = vault.encryption_manager + pm.vault = vault + pm.entry_manager = entry_mgr + pm.backup_manager = backup_mgr + pm.parent_seed = TEST_SEED + pm.nostr_client = None + pm.fingerprint_dir = tmp_path + pm.is_dirty = False + pm.secret_mode_enabled = False + return pm + + +@pytest.fixture +async def client(monkeypatch): + dummy = SimpleNamespace( + entry_manager=SimpleNamespace( + search_entries=lambda q: [ + (1, "Site", "user", "url", False, EntryType.PASSWORD) + ], + retrieve_entry=lambda i: {"label": "Site"}, + add_entry=lambda *a, **k: 1, + modify_entry=lambda *a, **k: None, + archive_entry=lambda i: None, + restore_entry=lambda i: None, + ), + config_manager=SimpleNamespace( + load_config=lambda require_pin=False: {"k": "v"}, + set_pin=lambda v: None, + set_password_hash=lambda v: None, + set_relays=lambda v, require_pin=False: None, + set_inactivity_timeout=lambda v: None, + set_additional_backup_path=lambda v: None, + set_secret_mode_enabled=lambda v: None, + set_clipboard_clear_delay=lambda v: None, + set_quick_unlock=lambda v: None, + ), + fingerprint_manager=SimpleNamespace(list_fingerprints=lambda: ["fp"]), + nostr_client=SimpleNamespace( + key_manager=SimpleNamespace(get_npub=lambda: "np") + ), + verify_password=lambda pw: True, + ) + monkeypatch.setattr(api, "PasswordManager", lambda: dummy) + monkeypatch.setenv("SEEDPASS_CORS_ORIGINS", "http://example.com") + token = api.start_server() + transport = ASGITransport(app=api.app) + async with AsyncClient(transport=transport, base_url="http://test") as ac: + yield ac, token + + +@pytest.fixture +def make_dummy_nostr_client(monkeypatch): + """Factory to return a NostrClient wired to a DummyRelayClient.""" + from cryptography.fernet import Fernet + from nostr.client import NostrClient + + def _make(base_path): + relay = DummyRelayClient() + monkeypatch.setattr("nostr.client.Client", lambda signer: relay) + monkeypatch.setattr("nostr.client.EventBuilder", DummyBuilder) + monkeypatch.setattr("nostr.client.Filter", DummyFilter) + monkeypatch.setattr("nostr.client.Tag", DummyTag) + monkeypatch.setattr("nostr.client.Timestamp", DummyTimestamp) + monkeypatch.setattr("nostr.client.EventId", DummyEventId) + from nostr.backup_models import KIND_DELTA as KD + + monkeypatch.setattr("nostr.client.KIND_DELTA", KD, raising=False) + monkeypatch.setattr(NostrClient, "initialize_client_pool", lambda self: None) + + enc_mgr = EncMgr(Fernet.generate_key(), base_path) + + class DummyKeys: + def private_key_hex(self): + return "1" * 64 + + def public_key_hex(self): + return "2" * 64 + + class DummyKeyManager: + def __init__(self, *a, **k): + self.keys = DummyKeys() + + with pytest.MonkeyPatch().context() as mp: + mp.setattr("nostr.client.KeyManager", DummyKeyManager) + mp.setattr(enc_mgr, "decrypt_parent_seed", lambda: TEST_SEED) + client = NostrClient(enc_mgr, "fp") + return client, relay + + return _make + + +@pytest.fixture +def dummy_nostr_client(make_dummy_nostr_client, tmp_path): + return make_dummy_nostr_client(tmp_path) diff --git a/src/tests/helpers.py b/src/tests/helpers.py index c36fa657..ad87a6f6 100644 --- a/src/tests/helpers.py +++ b/src/tests/helpers.py @@ -1,18 +1,24 @@ -import sys -import time import json +import uuid from pathlib import Path -sys.path.append(str(Path(__file__).resolve().parents[1])) - from seedpass.core.vault import Vault from seedpass.core.encryption import EncryptionManager from utils.key_derivation import ( derive_index_key, derive_key_from_password, ) +from utils.fingerprint import generate_fingerprint +from nostr.backup_models import ( + KIND_MANIFEST, + KIND_SNAPSHOT_CHUNK, + KIND_DELTA, +) -TEST_SEED = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" +TEST_SEED = ( + "abandon abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon about" +) TEST_PASSWORD = "pw" @@ -22,7 +28,8 @@ def create_vault( password: str = TEST_PASSWORD, ) -> tuple[Vault, EncryptionManager]: """Create a Vault initialized for tests.""" - seed_key = derive_key_from_password(password) + fp = generate_fingerprint(seed) + seed_key = derive_key_from_password(password, fp) seed_mgr = EncryptionManager(seed_key, dir_path) seed_mgr.encrypt_parent_seed(seed) @@ -32,17 +39,6 @@ def create_vault( return vault, enc_mgr -import uuid -import asyncio -import pytest - -from nostr.backup_models import ( - KIND_MANIFEST, - KIND_SNAPSHOT_CHUNK, - KIND_DELTA, -) - - class DummyEvent: def __init__(self, kind: int, content: str, tags=None, event_id: str | None = None): self.kind = kind @@ -235,41 +231,3 @@ class DummyRelayClient: return self._evs return Result(events) - - -@pytest.fixture -def dummy_nostr_client(tmp_path, monkeypatch): - """Return a NostrClient wired to a DummyRelayClient.""" - from cryptography.fernet import Fernet - from nostr.client import NostrClient - - relay = DummyRelayClient() - monkeypatch.setattr("nostr.client.Client", lambda signer: relay) - monkeypatch.setattr("nostr.client.EventBuilder", DummyBuilder) - monkeypatch.setattr("nostr.client.Filter", DummyFilter) - monkeypatch.setattr("nostr.client.Tag", DummyTag) - monkeypatch.setattr("nostr.client.Timestamp", DummyTimestamp) - monkeypatch.setattr("nostr.client.EventId", DummyEventId) - from nostr.backup_models import KIND_DELTA as KD - - monkeypatch.setattr("nostr.client.KIND_DELTA", KD, raising=False) - monkeypatch.setattr(NostrClient, "initialize_client_pool", lambda self: None) - - enc_mgr = EncryptionManager(Fernet.generate_key(), tmp_path) - - class DummyKeys: - def private_key_hex(self): - return "1" * 64 - - def public_key_hex(self): - return "2" * 64 - - class DummyKeyManager: - def __init__(self, *a, **k): - self.keys = DummyKeys() - - with pytest.MonkeyPatch().context() as mp: - mp.setattr("nostr.client.KeyManager", DummyKeyManager) - mp.setattr(enc_mgr, "decrypt_parent_seed", lambda: TEST_SEED) - client = NostrClient(enc_mgr, "fp") - return client, relay diff --git a/src/tests/test_add_new_fingerprint_words.py b/src/tests/test_add_new_fingerprint_words.py new file mode 100644 index 00000000..a95d1795 --- /dev/null +++ b/src/tests/test_add_new_fingerprint_words.py @@ -0,0 +1,35 @@ +import builtins +from types import SimpleNamespace + +import seedpass.core.manager as manager_module +from helpers import TEST_SEED + + +def test_add_new_fingerprint_word_entry_exits(monkeypatch): + pm = manager_module.PasswordManager.__new__(manager_module.PasswordManager) + pm.fingerprint_manager = SimpleNamespace(current_fingerprint=None) + pm.initialize_managers = lambda: None + + calls = {"count": 0} + original_setup = manager_module.PasswordManager.setup_existing_seed + + def setup_wrapper(self, *a, **k): + calls["count"] += 1 + return original_setup(self, *a, **k) + + monkeypatch.setattr( + manager_module.PasswordManager, "setup_existing_seed", setup_wrapper + ) + monkeypatch.setattr(manager_module, "prompt_seed_words", lambda *a, **k: TEST_SEED) + monkeypatch.setattr( + manager_module.PasswordManager, + "_finalize_existing_seed", + lambda self, seed, password=None: "fp", + ) + monkeypatch.setattr(builtins, "input", lambda *_a, **_k: "2") + + result = pm.add_new_fingerprint() + + assert result == "fp" + assert calls["count"] == 1 + assert pm.fingerprint_manager.current_fingerprint == "fp" diff --git a/src/tests/test_ai_tui_agent_harness.py b/src/tests/test_ai_tui_agent_harness.py new file mode 100644 index 00000000..ed228a38 --- /dev/null +++ b/src/tests/test_ai_tui_agent_harness.py @@ -0,0 +1,183 @@ +from __future__ import annotations + +import importlib.util +from pathlib import Path +import sys + +import pytest + + +def _load_harness_module(): + repo_root = Path(__file__).resolve().parents[2] + script_path = repo_root / "scripts" / "ai_tui_agent_test.py" + spec = importlib.util.spec_from_file_location("ai_tui_agent_test", script_path) + assert spec is not None and spec.loader is not None + module = importlib.util.module_from_spec(spec) + sys.modules[spec.name] = module + spec.loader.exec_module(module) + return module + + +harness = _load_harness_module() + + +def test_run_step_records_passed_result(): + results = [] + called = {"value": False} + + def _ok(): + called["value"] = True + + harness._run_step("step_a", "happy path", _ok, results, verbose=False) + + assert called["value"] is True + assert len(results) == 1 + assert results[0].step_id == "step_a" + assert results[0].status == "passed" + assert results[0].detail is None + + +def test_run_step_records_failed_result_and_reraises(): + results = [] + + def _boom(): + raise RuntimeError("boom") + + with pytest.raises(RuntimeError, match="boom"): + harness._run_step("step_b", "failing path", _boom, results, verbose=False) + + assert len(results) == 1 + assert results[0].step_id == "step_b" + assert results[0].status == "failed" + assert results[0].detail == "boom" + + +def test_add_entry_menu_open_waits_when_choice_omitted(): + class Runner: + def __init__(self): + self.sent = [] + self.waited = [] + + def sendline(self, value=""): + self.sent.append(value) + + def wait_for(self, pattern, timeout): + self.waited.append((pattern, timeout)) + + runner = Runner() + harness._add_entry_menu_open(runner, timeout=5.0, choice=None) + assert runner.sent == ["1"] + assert len(runner.waited) == 1 + assert "Select entry type or press Enter to go back:" in runner.waited[0][0] + + +def test_add_entry_menu_open_sends_choice_when_provided(): + class Runner: + def __init__(self): + self.sent = [] + self.expect_calls = [] + + def sendline(self, value=""): + self.sent.append(value) + + def expect_and_send(self, pattern, value, timeout): + self.expect_calls.append((pattern, value, timeout)) + + runner = Runner() + harness._add_entry_menu_open(runner, timeout=5.0, choice="7") + assert runner.sent == ["1"] + assert runner.expect_calls == [ + ("Select entry type or press Enter to go back:", "7", 5.0) + ] + + +def test_complete_onboarding_reaches_main_menu_and_sends_password(): + class Runner: + def __init__(self): + self.calls = [ + (r"Enter your choice \(1-8\) or press Enter to exit:", False), + (r"Enter a new password:", True), + (r"Enter your choice \(1-8\) or press Enter to exit:", False), + (r"Enter a new password:", False), + (r"Confirm your password:", True), + (r"Enter your choice \(1-8\) or press Enter to exit:", True), + ] + self.sent = [] + + def try_wait_for(self, pattern, timeout): + expected_pattern, ret = self.calls.pop(0) + assert pattern == expected_pattern + return ret + + def sendline(self, value=""): + self.sent.append(value) + + def pump(self, duration): + return None + + runner = Runner() + harness._complete_onboarding_to_main_menu(runner, timeout=1.0, password="pw123") + assert runner.sent == ["pw123", "pw123"] + assert runner.calls == [] + + +def test_complete_onboarding_times_out_without_expected_prompts(): + class Runner: + def try_wait_for(self, pattern, timeout): + return False + + def sendline(self, value=""): + return None + + def pump(self, duration): + return None + + runner = Runner() + with pytest.raises(harness.TUIHarnessError, match="Onboarding did not reach main"): + harness._complete_onboarding_to_main_menu(runner, timeout=0.0, password="pw") + + +def test_drain_to_main_menu_uses_helper_prompt_then_returns(): + class Runner: + def __init__(self): + self.main_attempts = 0 + self.helper_calls = [] + + def wait_for(self, pattern, timeout): + self.main_attempts += 1 + if self.main_attempts == 1: + raise harness.TUIHarnessError("not yet") + return None + + def expect_and_send(self, pattern, value, timeout): + self.helper_calls.append((pattern, value, timeout)) + return None + + def pump(self, duration): + return None + + runner = Runner() + harness._drain_to_main_menu(runner, timeout=1.0) + assert runner.main_attempts == 2 + assert len(runner.helper_calls) == 1 + assert runner.helper_calls[0][1] == "" + + +def test_drain_to_main_menu_times_out_when_no_prompt_progress(monkeypatch): + class Runner: + def wait_for(self, pattern, timeout): + raise harness.TUIHarnessError("missing") + + def expect_and_send(self, pattern, value, timeout): + raise harness.TUIHarnessError("missing helper") + + def pump(self, duration): + return None + + timeline = iter([0.0, 0.05, 0.15]) + monkeypatch.setattr(harness.time, "monotonic", lambda: next(timeline)) + + with pytest.raises( + harness.TUIHarnessError, match="Unable to return to main menu within timeout" + ): + harness._drain_to_main_menu(Runner(), timeout=0.1) diff --git a/src/tests/test_api.py b/src/tests/test_api.py index d1470415..e85bc1a9 100644 --- a/src/tests/test_api.py +++ b/src/tests/test_api.py @@ -1,63 +1,49 @@ -from types import SimpleNamespace from pathlib import Path import sys import pytest -from fastapi.testclient import TestClient +import bcrypt sys.path.append(str(Path(__file__).resolve().parents[1])) from seedpass import api -from seedpass.core.entry_types import EntryType -@pytest.fixture -def client(monkeypatch): - dummy = SimpleNamespace( - entry_manager=SimpleNamespace( - search_entries=lambda q: [ - (1, "Site", "user", "url", False, EntryType.PASSWORD) - ], - retrieve_entry=lambda i: {"label": "Site"}, - add_entry=lambda *a, **k: 1, - modify_entry=lambda *a, **k: None, - archive_entry=lambda i: None, - restore_entry=lambda i: None, - ), - config_manager=SimpleNamespace( - load_config=lambda require_pin=False: {"k": "v"}, - set_pin=lambda v: None, - set_password_hash=lambda v: None, - set_relays=lambda v, require_pin=False: None, - set_inactivity_timeout=lambda v: None, - set_additional_backup_path=lambda v: None, - set_secret_mode_enabled=lambda v: None, - set_clipboard_clear_delay=lambda v: None, - set_quick_unlock=lambda v: None, - ), - fingerprint_manager=SimpleNamespace(list_fingerprints=lambda: ["fp"]), - nostr_client=SimpleNamespace( - key_manager=SimpleNamespace(get_npub=lambda: "np") - ), - ) - monkeypatch.setattr(api, "PasswordManager", lambda: dummy) - monkeypatch.setenv("SEEDPASS_CORS_ORIGINS", "http://example.com") - token = api.start_server() - client = TestClient(api.app) - return client, token +def test_get_pm_requires_initialized_state(): + class DummyState: + pass + + class DummyApp: + state = DummyState() + + class DummyRequest: + app = DummyApp() + + with pytest.raises(api.HTTPException) as exc: + api._get_pm(DummyRequest()) + assert exc.value.status_code == 503 -def test_cors_and_auth(client): +@pytest.mark.anyio +async def test_token_hashed(client): + _, token = client + assert api.app.state.token_hash != token + assert bcrypt.checkpw(token.encode(), api.app.state.token_hash) + + +@pytest.mark.anyio +async def test_cors_and_auth(client): cl, token = client headers = {"Authorization": f"Bearer {token}", "Origin": "http://example.com"} - res = cl.get("/api/v1/entry", params={"query": "s"}, headers=headers) + res = await cl.get("/api/v1/entry", params={"query": "s"}, headers=headers) assert res.status_code == 200 assert res.headers.get("access-control-allow-origin") == "http://example.com" -def test_invalid_token(client): +@pytest.mark.anyio +async def test_invalid_token(client): cl, _token = client - res = cl.get( + res = await cl.get( "/api/v1/entry", params={"query": "s"}, headers={"Authorization": "Bearer bad"}, @@ -65,69 +51,65 @@ def test_invalid_token(client): assert res.status_code == 401 -def test_missing_token(client): - cl, _token = client - # No Authorization header - res = cl.get( - "/api/v1/entry", - params={"query": "s"}, - ) - assert res.status_code == 401 - - -def test_get_entry_by_id(client): +@pytest.mark.anyio +async def test_get_entry_by_id(client): cl, token = client headers = { "Authorization": f"Bearer {token}", "Origin": "http://example.com", + "X-SeedPass-Password": "pw", } - res = cl.get("/api/v1/entry/1", headers=headers) + res = await cl.get("/api/v1/entry/1", headers=headers) assert res.status_code == 200 assert res.json() == {"label": "Site"} assert res.headers.get("access-control-allow-origin") == "http://example.com" -def test_get_config_value(client): +@pytest.mark.anyio +async def test_get_config_value(client): cl, token = client headers = { "Authorization": f"Bearer {token}", "Origin": "http://example.com", } - res = cl.get("/api/v1/config/k", headers=headers) + res = await cl.get("/api/v1/config/k", headers=headers) assert res.status_code == 200 assert res.json() == {"key": "k", "value": "v"} assert res.headers.get("access-control-allow-origin") == "http://example.com" -def test_list_fingerprint(client): +@pytest.mark.anyio +async def test_list_fingerprint(client): cl, token = client headers = { "Authorization": f"Bearer {token}", "Origin": "http://example.com", } - res = cl.get("/api/v1/fingerprint", headers=headers) + res = await cl.get("/api/v1/fingerprint", headers=headers) assert res.status_code == 200 assert res.json() == ["fp"] assert res.headers.get("access-control-allow-origin") == "http://example.com" -def test_get_nostr_pubkey(client): +@pytest.mark.anyio +async def test_get_nostr_pubkey(client): cl, token = client headers = { "Authorization": f"Bearer {token}", "Origin": "http://example.com", } - res = cl.get("/api/v1/nostr/pubkey", headers=headers) + res = await cl.get("/api/v1/nostr/pubkey", headers=headers) assert res.status_code == 200 assert res.json() == {"npub": "np"} assert res.headers.get("access-control-allow-origin") == "http://example.com" -def test_create_modify_archive_entry(client): +@pytest.mark.anyio +async def test_create_modify_archive_entry(client): cl, token = client headers = {"Authorization": f"Bearer {token}", "Origin": "http://example.com"} - res = cl.post( + res = await cl.post( "/api/v1/entry", json={"label": "test", "length": 12}, headers=headers, @@ -135,7 +117,7 @@ def test_create_modify_archive_entry(client): assert res.status_code == 200 assert res.json() == {"id": 1} - res = cl.put( + res = await cl.put( "/api/v1/entry/1", json={"username": "bob"}, headers=headers, @@ -143,25 +125,26 @@ def test_create_modify_archive_entry(client): assert res.status_code == 200 assert res.json() == {"status": "ok"} - res = cl.post("/api/v1/entry/1/archive", headers=headers) + res = await cl.post("/api/v1/entry/1/archive", headers=headers) assert res.status_code == 200 assert res.json() == {"status": "archived"} - res = cl.post("/api/v1/entry/1/unarchive", headers=headers) + res = await cl.post("/api/v1/entry/1/unarchive", headers=headers) assert res.status_code == 200 assert res.json() == {"status": "active"} -def test_update_config(client): +@pytest.mark.anyio +async def test_update_config(client): cl, token = client called = {} def set_timeout(val): called["val"] = val - api._pm.config_manager.set_inactivity_timeout = set_timeout + api.app.state.pm.config_manager.set_inactivity_timeout = set_timeout headers = {"Authorization": f"Bearer {token}", "Origin": "http://example.com"} - res = cl.put( + res = await cl.put( "/api/v1/config/inactivity_timeout", json={"value": 42}, headers=headers, @@ -172,13 +155,15 @@ def test_update_config(client): assert res.headers.get("access-control-allow-origin") == "http://example.com" -def test_update_config_quick_unlock(client): +@pytest.mark.anyio +async def test_update_config_quick_unlock(client): cl, token = client called = {} - - api._pm.config_manager.set_quick_unlock = lambda v: called.setdefault("val", v) + api.app.state.pm.config_manager.set_quick_unlock = lambda v: called.setdefault( + "val", v + ) headers = {"Authorization": f"Bearer {token}", "Origin": "http://example.com"} - res = cl.put( + res = await cl.put( "/api/v1/config/quick_unlock", json={"value": True}, headers=headers, @@ -188,13 +173,13 @@ def test_update_config_quick_unlock(client): assert called.get("val") is True -def test_change_password_route(client): +@pytest.mark.anyio +async def test_change_password_route(client): cl, token = client called = {} - - api._pm.change_password = lambda o, n: called.setdefault("called", (o, n)) + api.app.state.pm.change_password = lambda o, n: called.setdefault("called", (o, n)) headers = {"Authorization": f"Bearer {token}", "Origin": "http://example.com"} - res = cl.post( + res = await cl.post( "/api/v1/change-password", headers=headers, json={"old": "old", "new": "new"}, @@ -205,10 +190,11 @@ def test_change_password_route(client): assert res.headers.get("access-control-allow-origin") == "http://example.com" -def test_update_config_unknown_key(client): +@pytest.mark.anyio +async def test_update_config_unknown_key(client): cl, token = client headers = {"Authorization": f"Bearer {token}", "Origin": "http://example.com"} - res = cl.put( + res = await cl.put( "/api/v1/config/bogus", json={"value": 1}, headers=headers, @@ -216,7 +202,8 @@ def test_update_config_unknown_key(client): assert res.status_code == 400 -def test_shutdown(client, monkeypatch): +@pytest.mark.anyio +async def test_shutdown(client, monkeypatch): cl, token = client calls = {} @@ -232,7 +219,7 @@ def test_shutdown(client, monkeypatch): "Authorization": f"Bearer {token}", "Origin": "http://example.com", } - res = cl.post("/api/v1/shutdown", headers=headers) + res = await cl.post("/api/v1/shutdown", headers=headers) assert res.status_code == 200 assert res.json() == {"status": "shutting down"} assert calls["func"] is sys.exit @@ -240,6 +227,7 @@ def test_shutdown(client, monkeypatch): assert res.headers.get("access-control-allow-origin") == "http://example.com" +@pytest.mark.anyio @pytest.mark.parametrize( "method,path", [ @@ -257,11 +245,11 @@ def test_shutdown(client, monkeypatch): ("post", "/api/v1/vault/lock"), ], ) -def test_invalid_token_other_endpoints(client, method, path): +async def test_invalid_token_other_endpoints(client, method, path): cl, _token = client req = getattr(cl, method) kwargs = {"headers": {"Authorization": "Bearer bad"}} if method in {"post", "put"}: kwargs["json"] = {} - res = req(path, **kwargs) + res = await req(path, **kwargs) assert res.status_code == 401 diff --git a/src/tests/test_api_new_endpoints.py b/src/tests/test_api_new_endpoints.py index f48f3bba..6715d353 100644 --- a/src/tests/test_api_new_endpoints.py +++ b/src/tests/test_api_new_endpoints.py @@ -1,16 +1,18 @@ from types import SimpleNamespace from pathlib import Path +import os +import base64 import pytest from seedpass import api -from test_api import client -from helpers import dummy_nostr_client import string from seedpass.core.password_generation import PasswordGenerator, PasswordPolicy +from seedpass.core.encryption import EncryptionManager from nostr.client import NostrClient, DEFAULT_RELAYS -def test_create_and_modify_totp_entry(client): +@pytest.mark.anyio +async def test_create_and_modify_totp_entry(client): cl, token = client calls = {} @@ -21,13 +23,13 @@ def test_create_and_modify_totp_entry(client): def modify(idx, **kwargs): calls["modify"] = (idx, kwargs) - api._pm.entry_manager.add_totp = add_totp - api._pm.entry_manager.modify_entry = modify - api._pm.entry_manager.get_next_index = lambda: 5 - api._pm.parent_seed = "seed" + api.app.state.pm.entry_manager.add_totp = add_totp + api.app.state.pm.entry_manager.modify_entry = modify + api.app.state.pm.entry_manager.get_next_index = lambda: 5 + api.app.state.pm.parent_seed = "seed" headers = {"Authorization": f"Bearer {token}"} - res = cl.post( + res = await cl.post( "/api/v1/entry", json={ "type": "totp", @@ -49,9 +51,10 @@ def test_create_and_modify_totp_entry(client): "digits": 8, "notes": "n", "archived": False, + "deterministic": False, } - res = cl.put( + res = await cl.put( "/api/v1/entry/5", json={"period": 90, "digits": 6}, headers=headers, @@ -62,7 +65,8 @@ def test_create_and_modify_totp_entry(client): assert calls["modify"][1]["digits"] == 6 -def test_create_and_modify_ssh_entry(client): +@pytest.mark.anyio +async def test_create_and_modify_ssh_entry(client): cl, token = client calls = {} @@ -73,12 +77,12 @@ def test_create_and_modify_ssh_entry(client): def modify(idx, **kwargs): calls["modify"] = (idx, kwargs) - api._pm.entry_manager.add_ssh_key = add_ssh - api._pm.entry_manager.modify_entry = modify - api._pm.parent_seed = "seed" + api.app.state.pm.entry_manager.add_ssh_key = add_ssh + api.app.state.pm.entry_manager.modify_entry = modify + api.app.state.pm.parent_seed = "seed" headers = {"Authorization": f"Bearer {token}"} - res = cl.post( + res = await cl.post( "/api/v1/entry", json={"type": "ssh", "label": "S", "index": 2, "notes": "n"}, headers=headers, @@ -87,7 +91,7 @@ def test_create_and_modify_ssh_entry(client): assert res.json() == {"id": 2} assert calls["create"] == {"index": 2, "notes": "n", "archived": False} - res = cl.put( + res = await cl.put( "/api/v1/entry/2", json={"notes": "x"}, headers=headers, @@ -97,29 +101,31 @@ def test_create_and_modify_ssh_entry(client): assert calls["modify"][1]["notes"] == "x" -def test_update_entry_error(client): +@pytest.mark.anyio +async def test_update_entry_error(client): cl, token = client def modify(*a, **k): raise ValueError("nope") - api._pm.entry_manager.modify_entry = modify + api.app.state.pm.entry_manager.modify_entry = modify headers = {"Authorization": f"Bearer {token}"} - res = cl.put("/api/v1/entry/1", json={"username": "x"}, headers=headers) + res = await cl.put("/api/v1/entry/1", json={"username": "x"}, headers=headers) assert res.status_code == 400 assert res.json() == {"detail": "nope"} -def test_update_config_secret_mode(client): +@pytest.mark.anyio +async def test_update_config_secret_mode(client): cl, token = client called = {} def set_secret(val): called["val"] = val - api._pm.config_manager.set_secret_mode_enabled = set_secret + api.app.state.pm.config_manager.set_secret_mode_enabled = set_secret headers = {"Authorization": f"Bearer {token}"} - res = cl.put( + res = await cl.put( "/api/v1/config/secret_mode_enabled", json={"value": True}, headers=headers, @@ -129,24 +135,28 @@ def test_update_config_secret_mode(client): assert called["val"] is True -def test_totp_export_endpoint(client): +@pytest.mark.anyio +async def test_totp_export_endpoint(client): cl, token = client - api._pm.entry_manager.export_totp_entries = lambda seed: {"entries": ["x"]} - api._pm.parent_seed = "seed" - headers = {"Authorization": f"Bearer {token}"} - res = cl.get("/api/v1/totp/export", headers=headers) + api.app.state.pm.entry_manager.export_totp_entries = lambda seed: {"entries": ["x"]} + api.app.state.pm.parent_seed = "seed" + headers = {"Authorization": f"Bearer {token}", "X-SeedPass-Password": "pw"} + res = await cl.get("/api/v1/totp/export", headers=headers) assert res.status_code == 200 assert res.json() == {"entries": ["x"]} -def test_totp_codes_endpoint(client): +@pytest.mark.anyio +async def test_totp_codes_endpoint(client): cl, token = client - api._pm.entry_manager.list_entries = lambda **kw: [(0, "Email", None, None, False)] - api._pm.entry_manager.get_totp_code = lambda i, s: "123456" - api._pm.entry_manager.get_totp_time_remaining = lambda i: 30 - api._pm.parent_seed = "seed" - headers = {"Authorization": f"Bearer {token}"} - res = cl.get("/api/v1/totp", headers=headers) + api.app.state.pm.entry_manager.list_entries = lambda **kw: [ + (0, "Email", None, None, False) + ] + api.app.state.pm.entry_manager.get_totp_code = lambda i, s: "123456" + api.app.state.pm.entry_manager.get_totp_time_remaining = lambda i: 30 + api.app.state.pm.parent_seed = "seed" + headers = {"Authorization": f"Bearer {token}", "X-SeedPass-Password": "pw"} + res = await cl.get("/api/v1/totp", headers=headers) assert res.status_code == 200 assert res.json() == { "codes": [ @@ -155,49 +165,39 @@ def test_totp_codes_endpoint(client): } -def test_parent_seed_endpoint(client, tmp_path): +@pytest.mark.anyio +async def test_parent_seed_endpoint_removed(client): cl, token = client - api._pm.parent_seed = "seed" - called = {} - api._pm.encryption_manager = SimpleNamespace( - encrypt_and_save_file=lambda data, path: called.setdefault("path", path) + res = await cl.get( + "/api/v1/parent-seed", headers={"Authorization": f"Bearer {token}"} ) - headers = {"Authorization": f"Bearer {token}"} - - res = cl.get("/api/v1/parent-seed", headers=headers) - assert res.status_code == 200 - assert res.json() == {"seed": "seed"} - - out = tmp_path / "bk.enc" - res = cl.get("/api/v1/parent-seed", params={"file": str(out)}, headers=headers) - assert res.status_code == 200 - assert res.json() == {"status": "saved", "path": str(out)} - assert called["path"] == out + assert res.status_code == 404 -def test_fingerprint_endpoints(client): +@pytest.mark.anyio +async def test_fingerprint_endpoints(client): cl, token = client calls = {} - api._pm.add_new_fingerprint = lambda: calls.setdefault("add", True) - api._pm.fingerprint_manager.remove_fingerprint = lambda fp: calls.setdefault( - "remove", fp + api.app.state.pm.add_new_fingerprint = lambda: calls.setdefault("add", True) + api.app.state.pm.fingerprint_manager.remove_fingerprint = ( + lambda fp: calls.setdefault("remove", fp) ) - api._pm.select_fingerprint = lambda fp: calls.setdefault("select", fp) + api.app.state.pm.select_fingerprint = lambda fp: calls.setdefault("select", fp) headers = {"Authorization": f"Bearer {token}"} - res = cl.post("/api/v1/fingerprint", headers=headers) + res = await cl.post("/api/v1/fingerprint", headers=headers) assert res.status_code == 200 assert res.json() == {"status": "ok"} assert calls.get("add") is True - res = cl.delete("/api/v1/fingerprint/abc", headers=headers) + res = await cl.delete("/api/v1/fingerprint/abc", headers=headers) assert res.status_code == 200 assert res.json() == {"status": "deleted"} assert calls.get("remove") == "abc" - res = cl.post( + res = await cl.post( "/api/v1/fingerprint/select", json={"fingerprint": "xyz"}, headers=headers, @@ -207,44 +207,49 @@ def test_fingerprint_endpoints(client): assert calls.get("select") == "xyz" -def test_checksum_endpoints(client): +@pytest.mark.anyio +async def test_checksum_endpoints(client): cl, token = client calls = {} - api._pm.handle_verify_checksum = lambda: calls.setdefault("verify", True) - api._pm.handle_update_script_checksum = lambda: calls.setdefault("update", True) + api.app.state.pm.handle_verify_checksum = lambda: calls.setdefault("verify", True) + api.app.state.pm.handle_update_script_checksum = lambda: calls.setdefault( + "update", True + ) headers = {"Authorization": f"Bearer {token}"} - res = cl.post("/api/v1/checksum/verify", headers=headers) + res = await cl.post("/api/v1/checksum/verify", headers=headers) assert res.status_code == 200 assert res.json() == {"status": "ok"} assert calls.get("verify") is True - res = cl.post("/api/v1/checksum/update", headers=headers) + res = await cl.post("/api/v1/checksum/update", headers=headers) assert res.status_code == 200 assert res.json() == {"status": "ok"} assert calls.get("update") is True -def test_vault_import_via_path(client, tmp_path): +@pytest.mark.anyio +async def test_vault_import_via_path(client, tmp_path): cl, token = client called = {} def import_db(path): called["path"] = path - api._pm.handle_import_database = import_db - api._pm.fingerprint_dir = tmp_path # Mock fingerprint_dir for resolving relative paths - api._pm.sync_vault = lambda: called.setdefault("sync", True) - file_path = tmp_path / "b.json" + api.app.state.pm.handle_import_database = import_db + api.app.state.pm.sync_vault = lambda: called.setdefault("sync", True) + api.app.state.pm.encryption_manager = SimpleNamespace( + resolve_relative_path=lambda p: p + ) + file_path = tmp_path / "b.json.enc" file_path.write_text("{}") headers = {"Authorization": f"Bearer {token}"} - # Pass relative path, which should resolve to file_path - res = cl.post( + res = await cl.post( "/api/v1/vault/import", - json={"path": "b.json"}, + json={"path": str(file_path)}, headers=headers, ) assert res.status_code == 200 @@ -253,21 +258,22 @@ def test_vault_import_via_path(client, tmp_path): assert called.get("sync") is True -def test_vault_import_via_upload(client, tmp_path): +@pytest.mark.anyio +async def test_vault_import_via_upload(client, tmp_path): cl, token = client called = {} def import_db(path): called["path"] = path - api._pm.handle_import_database = import_db - api._pm.sync_vault = lambda: called.setdefault("sync", True) + api.app.state.pm.handle_import_database = import_db + api.app.state.pm.sync_vault = lambda: called.setdefault("sync", True) file_path = tmp_path / "c.json" file_path.write_text("{}") headers = {"Authorization": f"Bearer {token}"} with open(file_path, "rb") as fh: - res = cl.post( + res = await cl.post( "/api/v1/vault/import", files={"file": ("c.json", fh.read())}, headers=headers, @@ -278,29 +284,94 @@ def test_vault_import_via_upload(client, tmp_path): assert called.get("sync") is True -def test_vault_lock_endpoint(client): +@pytest.mark.anyio +async def test_vault_import_upload_too_large(client): + cl, token = client + called = {} + api.app.state.pm.handle_import_database = lambda path: called.setdefault( + "import_called", True + ) + api.app.state.pm.sync_vault = lambda: called.setdefault("sync_called", True) + + old_limit = api._MAX_IMPORT_BYTES + api._MAX_IMPORT_BYTES = 8 + try: + headers = {"Authorization": f"Bearer {token}"} + res = await cl.post( + "/api/v1/vault/import", + files={"file": ("big.json.enc", b"123456789")}, + headers=headers, + ) + finally: + api._MAX_IMPORT_BYTES = old_limit + + assert res.status_code == 413 + assert "exceeds max size" in res.json()["detail"] + assert called == {} + + +@pytest.mark.anyio +async def test_vault_import_invalid_extension(client): + cl, token = client + api.app.state.pm.handle_import_database = lambda path: None + api.app.state.pm.sync_vault = lambda: None + api.app.state.pm.encryption_manager = SimpleNamespace( + resolve_relative_path=lambda p: p + ) + + headers = {"Authorization": f"Bearer {token}"} + res = await cl.post( + "/api/v1/vault/import", + json={"path": "bad.txt"}, + headers=headers, + ) + assert res.status_code == 400 + + +@pytest.mark.anyio +async def test_vault_import_path_traversal_blocked(client, tmp_path): + cl, token = client + key = base64.urlsafe_b64encode(os.urandom(32)) + api.app.state.pm.encryption_manager = EncryptionManager(key, tmp_path) + api.app.state.pm.handle_import_database = lambda path: None + api.app.state.pm.sync_vault = lambda: None + + headers = {"Authorization": f"Bearer {token}"} + res = await cl.post( + "/api/v1/vault/import", + json={"path": "../evil.json.enc"}, + headers=headers, + ) + assert res.status_code == 400 + + +@pytest.mark.anyio +async def test_vault_lock_endpoint(client): cl, token = client called = {} def lock(): called["locked"] = True - api._pm.locked = True + api.app.state.pm.locked = True - api._pm.lock_vault = lock - api._pm.locked = False + api.app.state.pm.lock_vault = lock + api.app.state.pm.locked = False headers = {"Authorization": f"Bearer {token}"} - res = cl.post("/api/v1/vault/lock", headers=headers) + res = await cl.post("/api/v1/vault/lock", headers=headers) assert res.status_code == 200 assert res.json() == {"status": "locked"} assert called.get("locked") is True - assert api._pm.locked is True - api._pm.unlock_vault = lambda pw: setattr(api._pm, "locked", False) - api._pm.unlock_vault("pw") - assert api._pm.locked is False + assert api.app.state.pm.locked is True + api.app.state.pm.unlock_vault = lambda pw: setattr( + api.app.state.pm, "locked", False + ) + api.app.state.pm.unlock_vault("pw") + assert api.app.state.pm.locked is False -def test_secret_mode_endpoint(client): +@pytest.mark.anyio +async def test_secret_mode_endpoint(client): cl, token = client called = {} @@ -310,11 +381,11 @@ def test_secret_mode_endpoint(client): def set_delay(val): called.setdefault("delay", val) - api._pm.config_manager.set_secret_mode_enabled = set_secret - api._pm.config_manager.set_clipboard_clear_delay = set_delay + api.app.state.pm.config_manager.set_secret_mode_enabled = set_secret + api.app.state.pm.config_manager.set_clipboard_clear_delay = set_delay headers = {"Authorization": f"Bearer {token}"} - res = cl.post( + res = await cl.post( "/api/v1/secret-mode", json={"enabled": True, "delay": 12}, headers=headers, @@ -325,40 +396,79 @@ def test_secret_mode_endpoint(client): assert called["delay"] == 12 -def test_vault_export_endpoint(client, tmp_path): +@pytest.mark.anyio +async def test_vault_export_endpoint(client, tmp_path): cl, token = client out = tmp_path / "out.json" out.write_text("data") - api._pm.handle_export_database = lambda: out + api.app.state.pm.handle_export_database = lambda *a, **k: out - headers = {"Authorization": f"Bearer {token}"} - res = cl.post("/api/v1/vault/export", headers=headers) + headers = { + "Authorization": f"Bearer {token}", + "X-SeedPass-Password": "pw", + } + res = await cl.post("/api/v1/vault/export", headers=headers) assert res.status_code == 200 assert res.content == b"data" + res = await cl.post( + "/api/v1/vault/export", headers={"Authorization": f"Bearer {token}"} + ) + assert res.status_code == 401 -def test_backup_parent_seed_endpoint(client, tmp_path): + +@pytest.mark.anyio +async def test_backup_parent_seed_endpoint(client, tmp_path): cl, token = client + api.app.state.pm.parent_seed = "seed" called = {} + api.app.state.pm.encryption_manager = SimpleNamespace( + encrypt_and_save_file=lambda data, path: called.setdefault("path", path), + resolve_relative_path=lambda p: p, + ) + path = Path("seed.enc") + headers = { + "Authorization": f"Bearer {token}", + "X-SeedPass-Password": "pw", + } + res = await cl.post( + "/api/v1/vault/backup-parent-seed", + json={"path": str(path), "confirm": True}, + headers=headers, + ) + assert res.status_code == 200 + assert res.json() == {"status": "saved", "path": str(path)} + assert called["path"] == path - def backup(path=None): - called["path"] = path - - api._pm.handle_backup_reveal_parent_seed = backup - path = tmp_path / "seed.enc" - headers = {"Authorization": f"Bearer {token}"} - res = cl.post( + res = await cl.post( "/api/v1/vault/backup-parent-seed", json={"path": str(path)}, headers=headers, ) - assert res.status_code == 200 - assert res.json() == {"status": "ok"} - assert called["path"] == path + assert res.status_code == 400 -def test_relay_management_endpoints(client, dummy_nostr_client, monkeypatch): +@pytest.mark.anyio +async def test_backup_parent_seed_path_traversal_blocked(client, tmp_path): + cl, token = client + api.app.state.pm.parent_seed = "seed" + key = base64.urlsafe_b64encode(os.urandom(32)) + api.app.state.pm.encryption_manager = EncryptionManager(key, tmp_path) + headers = { + "Authorization": f"Bearer {token}", + "X-SeedPass-Password": "pw", + } + res = await cl.post( + "/api/v1/vault/backup-parent-seed", + json={"path": "../evil.enc", "confirm": True}, + headers=headers, + ) + assert res.status_code == 400 + + +@pytest.mark.anyio +async def test_relay_management_endpoints(client, dummy_nostr_client, monkeypatch): cl, token = client nostr_client, _ = dummy_nostr_client relays = ["wss://a", "wss://b"] @@ -371,8 +481,8 @@ def test_relay_management_endpoints(client, dummy_nostr_client, monkeypatch): def set_relays(new, require_pin=False): called["set"] = new - api._pm.config_manager.load_config = load_config - api._pm.config_manager.set_relays = set_relays + api.app.state.pm.config_manager.load_config = load_config + api.app.state.pm.config_manager.set_relays = set_relays monkeypatch.setattr( NostrClient, "initialize_client_pool", @@ -381,33 +491,34 @@ def test_relay_management_endpoints(client, dummy_nostr_client, monkeypatch): monkeypatch.setattr( nostr_client, "close_client_pool", lambda: called.setdefault("close", True) ) - api._pm.nostr_client = nostr_client - api._pm.nostr_client.relays = relays.copy() + api.app.state.pm.nostr_client = nostr_client + api.app.state.pm.nostr_client.relays = relays.copy() headers = {"Authorization": f"Bearer {token}"} - res = cl.get("/api/v1/relays", headers=headers) + res = await cl.get("/api/v1/relays", headers=headers) assert res.status_code == 200 assert res.json() == {"relays": relays} - res = cl.post("/api/v1/relays", json={"url": "wss://c"}, headers=headers) + res = await cl.post("/api/v1/relays", json={"url": "wss://c"}, headers=headers) assert res.status_code == 200 assert called["set"] == ["wss://a", "wss://b", "wss://c"] - api._pm.config_manager.load_config = lambda require_pin=False: { + api.app.state.pm.config_manager.load_config = lambda require_pin=False: { "relays": ["wss://a", "wss://b", "wss://c"] } - res = cl.delete("/api/v1/relays/2", headers=headers) + res = await cl.delete("/api/v1/relays/2", headers=headers) assert res.status_code == 200 assert called["set"] == ["wss://a", "wss://c"] - res = cl.post("/api/v1/relays/reset", headers=headers) + res = await cl.post("/api/v1/relays/reset", headers=headers) assert res.status_code == 200 assert called.get("init") is True - assert api._pm.nostr_client.relays == list(DEFAULT_RELAYS) + assert api.app.state.pm.nostr_client.relays == list(DEFAULT_RELAYS) -def test_generate_password_no_special_chars(client): +@pytest.mark.anyio +async def test_generate_password_no_special_chars(client): cl, token = client class DummyEnc: @@ -415,14 +526,18 @@ def test_generate_password_no_special_chars(client): return b"\x00" * 32 class DummyBIP85: - def derive_entropy(self, index: int, bytes_len: int, app_no: int = 32) -> bytes: - return bytes(range(bytes_len)) + def derive_entropy( + self, index: int, entropy_bytes: int, app_no: int = 32 + ) -> bytes: + return bytes(range(entropy_bytes)) - api._pm.password_generator = PasswordGenerator(DummyEnc(), "seed", DummyBIP85()) - api._pm.parent_seed = "seed" + api.app.state.pm.password_generator = PasswordGenerator( + DummyEnc(), "seed", DummyBIP85() + ) + api.app.state.pm.parent_seed = "seed" headers = {"Authorization": f"Bearer {token}"} - res = cl.post( + res = await cl.post( "/api/v1/password", json={"length": 16, "include_special_chars": False}, headers=headers, @@ -432,7 +547,8 @@ def test_generate_password_no_special_chars(client): assert not any(c in string.punctuation for c in pw) -def test_generate_password_allowed_chars(client): +@pytest.mark.anyio +async def test_generate_password_allowed_chars(client): cl, token = client class DummyEnc: @@ -440,15 +556,19 @@ def test_generate_password_allowed_chars(client): return b"\x00" * 32 class DummyBIP85: - def derive_entropy(self, index: int, bytes_len: int, app_no: int = 32) -> bytes: - return bytes((index + i) % 256 for i in range(bytes_len)) + def derive_entropy( + self, index: int, entropy_bytes: int, app_no: int = 32 + ) -> bytes: + return bytes((index + i) % 256 for i in range(entropy_bytes)) - api._pm.password_generator = PasswordGenerator(DummyEnc(), "seed", DummyBIP85()) - api._pm.parent_seed = "seed" + api.app.state.pm.password_generator = PasswordGenerator( + DummyEnc(), "seed", DummyBIP85() + ) + api.app.state.pm.parent_seed = "seed" headers = {"Authorization": f"Bearer {token}"} allowed = "@$" - res = cl.post( + res = await cl.post( "/api/v1/password", json={"length": 16, "allowed_special_chars": allowed}, headers=headers, diff --git a/src/tests/test_api_notifications.py b/src/tests/test_api_notifications.py index e0805a9a..1d9069f9 100644 --- a/src/tests/test_api_notifications.py +++ b/src/tests/test_api_notifications.py @@ -1,45 +1,58 @@ -from test_api import client from types import SimpleNamespace import queue +import pytest import seedpass.api as api -def test_notifications_endpoint(client): +@pytest.mark.anyio +async def test_notifications_endpoint(client): cl, token = client - api._pm.notifications = queue.Queue() - api._pm.notifications.put(SimpleNamespace(message="m1", level="INFO")) - api._pm.notifications.put(SimpleNamespace(message="m2", level="WARNING")) - res = cl.get("/api/v1/notifications", headers={"Authorization": f"Bearer {token}"}) + api.app.state.pm.notifications = queue.Queue() + api.app.state.pm.notifications.put(SimpleNamespace(message="m1", level="INFO")) + api.app.state.pm.notifications.put(SimpleNamespace(message="m2", level="WARNING")) + res = await cl.get( + "/api/v1/notifications", headers={"Authorization": f"Bearer {token}"} + ) assert res.status_code == 200 assert res.json() == [ {"level": "INFO", "message": "m1"}, {"level": "WARNING", "message": "m2"}, ] - assert api._pm.notifications.empty() + assert api.app.state.pm.notifications.empty() -def test_notifications_endpoint_clears_queue(client): +@pytest.mark.anyio +async def test_notifications_endpoint_clears_queue(client): cl, token = client - api._pm.notifications = queue.Queue() - api._pm.notifications.put(SimpleNamespace(message="hi", level="INFO")) - res = cl.get("/api/v1/notifications", headers={"Authorization": f"Bearer {token}"}) + api.app.state.pm.notifications = queue.Queue() + api.app.state.pm.notifications.put(SimpleNamespace(message="hi", level="INFO")) + res = await cl.get( + "/api/v1/notifications", headers={"Authorization": f"Bearer {token}"} + ) assert res.status_code == 200 assert res.json() == [{"level": "INFO", "message": "hi"}] - assert api._pm.notifications.empty() - res = cl.get("/api/v1/notifications", headers={"Authorization": f"Bearer {token}"}) + assert api.app.state.pm.notifications.empty() + res = await cl.get( + "/api/v1/notifications", headers={"Authorization": f"Bearer {token}"} + ) assert res.json() == [] -def test_notifications_endpoint_does_not_clear_current(client): +@pytest.mark.anyio +async def test_notifications_endpoint_does_not_clear_current(client): cl, token = client - api._pm.notifications = queue.Queue() + api.app.state.pm.notifications = queue.Queue() msg = SimpleNamespace(message="keep", level="INFO") - api._pm.notifications.put(msg) - api._pm._current_notification = msg - api._pm.get_current_notification = lambda: api._pm._current_notification + api.app.state.pm.notifications.put(msg) + api.app.state.pm._current_notification = msg + api.app.state.pm.get_current_notification = ( + lambda: api.app.state.pm._current_notification + ) - res = cl.get("/api/v1/notifications", headers={"Authorization": f"Bearer {token}"}) + res = await cl.get( + "/api/v1/notifications", headers={"Authorization": f"Bearer {token}"} + ) assert res.status_code == 200 assert res.json() == [{"level": "INFO", "message": "keep"}] - assert api._pm.notifications.empty() - assert api._pm.get_current_notification() is msg + assert api.app.state.pm.notifications.empty() + assert api.app.state.pm.get_current_notification() is msg diff --git a/src/tests/test_api_profile_stats.py b/src/tests/test_api_profile_stats.py index 153dbd39..2b646c9d 100644 --- a/src/tests/test_api_profile_stats.py +++ b/src/tests/test_api_profile_stats.py @@ -1,13 +1,13 @@ -from test_api import client +import pytest -def test_profile_stats_endpoint(client): +@pytest.mark.anyio +async def test_profile_stats_endpoint(client): cl, token = client stats = {"total_entries": 1} - # monkeypatch set _pm.get_profile_stats after client fixture started import seedpass.api as api - api._pm.get_profile_stats = lambda: stats - res = cl.get("/api/v1/stats", headers={"Authorization": f"Bearer {token}"}) + api.app.state.pm.get_profile_stats = lambda: stats + res = await cl.get("/api/v1/stats", headers={"Authorization": f"Bearer {token}"}) assert res.status_code == 200 assert res.json() == stats diff --git a/src/tests/test_api_rate_limit.py b/src/tests/test_api_rate_limit.py new file mode 100644 index 00000000..c3531ae9 --- /dev/null +++ b/src/tests/test_api_rate_limit.py @@ -0,0 +1,50 @@ +import importlib +from pathlib import Path +from types import SimpleNamespace +import importlib +import pytest +from httpx import ASGITransport, AsyncClient + +import sys + +sys.path.append(str(Path(__file__).resolve().parents[1])) + + +@pytest.mark.anyio +async def test_rate_limit_exceeded(monkeypatch): + monkeypatch.setenv("SEEDPASS_RATE_LIMIT", "2") + monkeypatch.setenv("SEEDPASS_RATE_WINDOW", "60") + import seedpass.api as api + + importlib.reload(api) + + dummy = SimpleNamespace( + entry_manager=SimpleNamespace( + search_entries=lambda q: [ + (1, "Site", "user", "url", False, SimpleNamespace(value="password")) + ] + ), + config_manager=SimpleNamespace(load_config=lambda require_pin=False: {}), + fingerprint_manager=SimpleNamespace(list_fingerprints=lambda: []), + nostr_client=SimpleNamespace( + key_manager=SimpleNamespace(get_npub=lambda: "np") + ), + verify_password=lambda pw: True, + ) + monkeypatch.setattr(api, "PasswordManager", lambda: dummy) + token = api.start_server() + transport = ASGITransport(app=api.app) + async with AsyncClient(transport=transport, base_url="http://test") as client: + headers = {"Authorization": f"Bearer {token}"} + + for _ in range(2): + res = await client.get( + "/api/v1/entry", params={"query": "s"}, headers=headers + ) + assert res.status_code == 200 + + res = await client.get("/api/v1/entry", params={"query": "s"}, headers=headers) + assert res.status_code == 429 + bucket_keys = list(api.app.state.rate_limit_buckets.keys()) + assert bucket_keys + assert all(token not in key for key in bucket_keys) diff --git a/src/tests/test_api_reload_relays.py b/src/tests/test_api_reload_relays.py new file mode 100644 index 00000000..e9dc900b --- /dev/null +++ b/src/tests/test_api_reload_relays.py @@ -0,0 +1,29 @@ +import logging +from types import SimpleNamespace + +from seedpass import api + + +def test_reload_relays_logs_errors(caplog): + def close(): + raise RuntimeError("close fail") + + def init(): + raise OSError("init fail") + + pm = SimpleNamespace( + nostr_client=SimpleNamespace( + close_client_pool=close, + initialize_client_pool=init, + relays=[], + ) + ) + request = SimpleNamespace(app=SimpleNamespace(state=SimpleNamespace(pm=pm))) + + with caplog.at_level(logging.WARNING): + api._reload_relays(request, ["ws://relay"]) + + assert "Failed to close NostrClient pool" in caplog.text + assert "close fail" in caplog.text + assert "Failed to initialize NostrClient with relays" in caplog.text + assert "init fail" in caplog.text diff --git a/src/tests/test_archive_restore.py b/src/tests/test_archive_restore.py index 7e2bba61..e766e35e 100644 --- a/src/tests/test_archive_restore.py +++ b/src/tests/test_archive_restore.py @@ -193,3 +193,44 @@ def test_archived_entries_menu_hides_active(monkeypatch, capsys): out = capsys.readouterr().out assert "archived.com" in out assert "active.com" not in out + + +def test_view_archived_entries_refreshes_after_view_action(monkeypatch): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + backup_mgr = BackupManager(tmp_path, cfg_mgr) + entry_mgr = EntryManager(vault, backup_mgr) + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = enc_mgr + pm.vault = vault + pm.entry_manager = entry_mgr + pm.backup_manager = backup_mgr + pm.parent_seed = TEST_SEED + pm.nostr_client = SimpleNamespace() + pm.fingerprint_dir = tmp_path + pm.is_dirty = False + pm.notifications = queue.Queue() + + idx = entry_mgr.add_entry("example.com", 8) + entry_mgr.archive_entry(idx) + assert entry_mgr.retrieve_entry(idx)["archived"] is True + + monkeypatch.setattr( + pm, + "show_entry_details_by_index", + lambda index: entry_mgr.restore_entry(index), + ) + monkeypatch.setattr("seedpass.core.manager.pause", lambda: None) + inputs = iter([str(idx), "v"]) + monkeypatch.setattr("builtins.input", lambda *_: next(inputs)) + + pm.handle_view_archived_entries() + + assert entry_mgr.retrieve_entry(idx)["archived"] is False + note = pm.notifications.get_nowait() + assert note.level == "WARNING" + assert note.message == "No archived entries found." diff --git a/src/tests/test_atomic_write.py b/src/tests/test_atomic_write.py new file mode 100644 index 00000000..2b57d7c1 --- /dev/null +++ b/src/tests/test_atomic_write.py @@ -0,0 +1,30 @@ +import json +from multiprocessing import Process +from pathlib import Path + +from utils.atomic_write import atomic_write + + +def _writer(path: Path, content: dict, loops: int) -> None: + for _ in range(loops): + atomic_write(path, lambda f: json.dump(content, f), mode="w") + + +def test_atomic_write_concurrent(tmp_path: Path) -> None: + """Concurrent writers should not leave partial files.""" + + file_path = tmp_path / "data.json" + contents = [{"proc": i} for i in range(5)] + + procs = [ + Process(target=_writer, args=(file_path, content, 50)) for content in contents + ] + + for p in procs: + p.start() + for p in procs: + p.join() + + final_text = file_path.read_text() + final_obj = json.loads(final_text) + assert final_obj in contents diff --git a/src/tests/test_audit_logger.py b/src/tests/test_audit_logger.py new file mode 100644 index 00000000..884a1391 --- /dev/null +++ b/src/tests/test_audit_logger.py @@ -0,0 +1,85 @@ +import json +import hashlib +import hmac +import queue +from pathlib import Path +from types import SimpleNamespace + +import importlib +import pytest + +from seedpass.core.manager import PasswordManager, AuditLogger +import seedpass.core.manager as manager_module + + +def test_audit_logger_records_events(monkeypatch, tmp_path): + monkeypatch.setattr(Path, "home", lambda: tmp_path) + + pm = PasswordManager.__new__(PasswordManager) + pm.fingerprint_dir = tmp_path + pm.current_fingerprint = "user123" + pm.profile_stack = [] + pm.setup_encryption_manager = lambda *a, **k: None + pm.initialize_bip85 = lambda: None + pm.initialize_managers = lambda: None + pm.update_activity = lambda: None + pm.verify_password = lambda pw: True + pm.notifications = queue.Queue() + pm.parent_seed = "seed phrase" + pm.config_manager = SimpleNamespace(get_quick_unlock=lambda: True) + + manager_module.clear_header_with_notification = lambda *a, **k: None + + pm.unlock_vault(password="pw") + + dest = tmp_path / "db.json.enc" + monkeypatch.setattr(manager_module, "export_backup", lambda *a, **k: dest) + pm.vault = object() + pm.backup_manager = object() + monkeypatch.setattr("seedpass.core.manager.confirm_action", lambda *_a, **_k: True) + pm.handle_export_database(dest) + + confirms = iter([True, False]) + monkeypatch.setattr( + "seedpass.core.manager.confirm_action", lambda *_a, **_k: next(confirms) + ) + pm.encryption_manager = SimpleNamespace(encrypt_and_save_file=lambda *a, **k: None) + pm.handle_backup_reveal_parent_seed(password="pw") + + log_path = tmp_path / ".seedpass" / "audit.log" + lines = [json.loads(l) for l in log_path.read_text().splitlines()] + events = [e["event"] for e in lines] + assert "quick_unlock" in events + assert "backup_export" in events + assert "seed_reveal" in events + + +def _verify_chain(path: Path, key: bytes) -> bool: + prev = "0" * 64 + for line in path.read_text().splitlines(): + data = json.loads(line) + sig = data.pop("sig") + payload = json.dumps(data, sort_keys=True, separators=(",", ":")) + expected = hmac.new( + key, f"{prev}{payload}".encode(), hashlib.sha256 + ).hexdigest() + if sig != expected: + return False + prev = sig + return True + + +def test_audit_log_tamper_evident(monkeypatch, tmp_path): + monkeypatch.setattr(Path, "home", lambda: tmp_path) + key = hashlib.sha256(b"seed").digest() + logger = AuditLogger(key) + logger.log("one", {}) + logger.log("two", {}) + log_path = tmp_path / ".seedpass" / "audit.log" + assert _verify_chain(log_path, key) + lines = log_path.read_text().splitlines() + tampered = json.loads(lines[0]) + tampered["event"] = "evil" + lines[0] = json.dumps(tampered) + log_path.write_text("\n".join(lines) + "\n") + assert not _verify_chain(log_path, key) diff --git a/src/tests/test_auto_sync.py b/src/tests/test_auto_sync.py index 26f0e22b..670fc5f9 100644 --- a/src/tests/test_auto_sync.py +++ b/src/tests/test_auto_sync.py @@ -15,6 +15,7 @@ def test_auto_sync_triggers_post(monkeypatch): is_dirty=True, last_update=time.time() - 0.2, last_activity=time.time(), + current_fingerprint="fp", nostr_client=SimpleNamespace(close_client_pool=lambda: None), handle_add_password=lambda: None, handle_retrieve_entry=lambda: None, diff --git a/src/tests/test_background_error_reporting.py b/src/tests/test_background_error_reporting.py new file mode 100644 index 00000000..a6c6ce4e --- /dev/null +++ b/src/tests/test_background_error_reporting.py @@ -0,0 +1,56 @@ +import logging +import queue + +import seedpass.core.manager as manager_module + + +def _make_pm(): + pm = manager_module.PasswordManager.__new__(manager_module.PasswordManager) + pm.offline_mode = False + pm.notifications = queue.Queue() + pm.error_queue = queue.Queue() + pm.notify = lambda msg, level="INFO": pm.notifications.put( + manager_module.Notification(msg, level) + ) + pm.nostr_client = object() + return pm + + +def test_start_background_sync_error(monkeypatch, caplog): + pm = _make_pm() + + async def failing_sync(*_args, **_kwargs): + raise RuntimeError("boom") + + monkeypatch.setattr(pm, "attempt_initial_sync_async", failing_sync) + monkeypatch.setattr(pm, "sync_index_from_nostr_async", failing_sync) + + pm.start_background_sync() + pm._sync_task.join(timeout=1) + + with caplog.at_level(logging.WARNING): + pm.poll_background_errors() + + note = pm.notifications.get_nowait() + assert "boom" in note.message + assert "boom" in caplog.text + + +def test_start_background_relay_check_error(monkeypatch, caplog): + pm = _make_pm() + + class DummyClient: + def check_relay_health(self, *_args, **_kwargs): + raise RuntimeError("relay boom") + + pm.nostr_client = DummyClient() + + pm.start_background_relay_check() + pm._relay_thread.join(timeout=1) + + with caplog.at_level(logging.WARNING): + pm.poll_background_errors() + + note = pm.notifications.get_nowait() + assert "relay boom" in note.message + assert "relay boom" in caplog.text diff --git a/src/tests/test_background_sync_always.py b/src/tests/test_background_sync_always.py index f266489f..ec346ae6 100644 --- a/src/tests/test_background_sync_always.py +++ b/src/tests/test_background_sync_always.py @@ -20,6 +20,7 @@ def test_switch_fingerprint_triggers_bg_sync(monkeypatch, tmp_path): pm.current_fingerprint = None pm.encryption_manager = object() pm.config_manager = SimpleNamespace(get_quick_unlock=lambda: False) + pm.nostr_account_idx = 0 monkeypatch.setattr("builtins.input", lambda *_a, **_k: "1") monkeypatch.setattr( diff --git a/src/tests/test_background_vault_sync_paths.py b/src/tests/test_background_vault_sync_paths.py new file mode 100644 index 00000000..40464fd7 --- /dev/null +++ b/src/tests/test_background_vault_sync_paths.py @@ -0,0 +1,58 @@ +import asyncio + +from seedpass.core.manager import PasswordManager +from seedpass.core import manager as manager_module + + +def test_start_background_vault_sync_thread_worker_path(monkeypatch): + pm = PasswordManager.__new__(PasswordManager) + pm.offline_mode = False + + events = [] + + async def fake_sync_vault_async(*, alt_summary=None): + return {"alt_summary": alt_summary} + + monkeypatch.setattr(pm, "sync_vault_async", fake_sync_vault_async) + monkeypatch.setattr( + manager_module.bus, "publish", lambda *args: events.append(args) + ) + + class ImmediateThread: + def __init__(self, target, daemon): + self._target = target + self.daemon = daemon + + def start(self): + self._target() + + monkeypatch.setattr(manager_module.threading, "Thread", ImmediateThread) + + pm.start_background_vault_sync("thread-path") + + assert ("sync_started",) in events + assert ("sync_finished", {"alt_summary": "thread-path"}) in events + + +def test_start_background_vault_sync_async_worker_path(monkeypatch): + pm = PasswordManager.__new__(PasswordManager) + pm.offline_mode = False + + events = [] + + async def fake_sync_vault_async(*, alt_summary=None): + return {"alt_summary": alt_summary} + + monkeypatch.setattr(pm, "sync_vault_async", fake_sync_vault_async) + monkeypatch.setattr( + manager_module.bus, "publish", lambda *args: events.append(args) + ) + + async def runner(): + pm.start_background_vault_sync("async-path") + await asyncio.sleep(0.02) + + asyncio.run(runner()) + + assert ("sync_started",) in events + assert ("sync_finished", {"alt_summary": "async-path"}) in events diff --git a/src/tests/test_backup_restore_startup.py b/src/tests/test_backup_restore_startup.py new file mode 100644 index 00000000..3b6256db --- /dev/null +++ b/src/tests/test_backup_restore_startup.py @@ -0,0 +1,56 @@ +import main +from pathlib import Path + + +def test_cli_flag_restores_before_init(monkeypatch, tmp_path): + calls = [] + backup = tmp_path / "bak.json" + backup.write_text("{}") + + def fake_restore(path, fingerprint): + calls.append(("restore", Path(path), fingerprint)) + + class DummyPM: + def __init__(self, fingerprint=None): + calls.append(("init", fingerprint)) + self.secret_mode_enabled = True + self.inactivity_timeout = 0 + + monkeypatch.setattr(main, "restore_backup_index", fake_restore) + monkeypatch.setattr(main, "PasswordManager", DummyPM) + monkeypatch.setattr(main, "display_menu", lambda pm, **k: None) + + rc = main.main(["--fingerprint", "fp", "--restore-backup", str(backup)]) + assert rc == 0 + assert calls[0][0] == "restore" + assert calls[1][0] == "init" + assert calls[0][1] == backup + assert calls[0][2] == "fp" + + +def test_menu_option_restores_before_init(monkeypatch, tmp_path): + calls = [] + backup = tmp_path / "bak.json" + backup.write_text("{}") + + def fake_restore(path, fingerprint): + calls.append(("restore", Path(path), fingerprint)) + + class DummyPM: + def __init__(self, fingerprint=None): + calls.append(("init", fingerprint)) + self.secret_mode_enabled = True + self.inactivity_timeout = 0 + + monkeypatch.setattr(main, "restore_backup_index", fake_restore) + monkeypatch.setattr(main, "PasswordManager", DummyPM) + monkeypatch.setattr(main, "display_menu", lambda pm, **k: None) + inputs = iter(["2", str(backup)]) + monkeypatch.setattr("builtins.input", lambda _prompt="": next(inputs)) + + rc = main.main(["--fingerprint", "fp"]) + assert rc == 0 + assert calls[0][0] == "restore" + assert calls[1][0] == "init" + assert calls[0][1] == backup + assert calls[0][2] == "fp" diff --git a/src/tests/test_bip85_derivation_path.py b/src/tests/test_bip85_derivation_path.py new file mode 100644 index 00000000..12807037 --- /dev/null +++ b/src/tests/test_bip85_derivation_path.py @@ -0,0 +1,52 @@ +from local_bip85.bip85 import BIP85 + + +class DummyChild: + def PrivateKey(self): + return self + + def Raw(self): + return self + + def ToBytes(self): + return b"\x00" * 32 + + +class DummyCtx: + def __init__(self): + self.last_path = None + + def DerivePath(self, path: str): + self.last_path = path + return DummyChild() + + +def test_derivation_paths_for_entropy_lengths(): + bip85 = BIP85(b"\x00" * 64) + ctx = DummyCtx() + bip85.bip32_ctx = ctx + + vectors = [ + (16, 12), + (24, 18), + (32, 24), + ] + + for entropy_bytes, word_count in vectors: + bip85.derive_entropy( + index=0, + entropy_bytes=entropy_bytes, + app_no=39, + word_count=word_count, + ) + assert ctx.last_path == f"m/83696968'/39'/0'/{word_count}'/0'" + + +def test_default_word_count_from_entropy_bytes(): + bip85 = BIP85(b"\x00" * 64) + ctx = DummyCtx() + bip85.bip32_ctx = ctx + + bip85.derive_entropy(index=5, entropy_bytes=20, app_no=39) + + assert ctx.last_path == "m/83696968'/39'/0'/20'/5'" diff --git a/src/tests/test_bip85_init.py b/src/tests/test_bip85_init.py new file mode 100644 index 00000000..d69659cd --- /dev/null +++ b/src/tests/test_bip85_init.py @@ -0,0 +1,39 @@ +import sys +from pathlib import Path + +sys.path.append(str(Path(__file__).resolve().parents[1])) + +from bip_utils import Bip39SeedGenerator +from local_bip85.bip85 import BIP85 +from helpers import TEST_SEED +from seedpass.core.manager import PasswordManager + +MASTER_XPRV = "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb" + + +def test_init_with_seed_bytes(): + seed_bytes = Bip39SeedGenerator(TEST_SEED).Generate() + bip85 = BIP85(seed_bytes) + assert isinstance(bip85, BIP85) + + +def test_init_with_xprv(): + bip85 = BIP85(MASTER_XPRV) + assert isinstance(bip85, BIP85) + + +def test_initialize_bip85_works_while_locked(): + pm = PasswordManager.__new__(PasswordManager) + pm.parent_seed = TEST_SEED + pm.is_locked = True + pm._bip85_cache = {(39, 0): b"stale"} + pm.KEY_STORAGE = None + pm.KEY_INDEX = None + pm.KEY_PW_DERIVE = None + pm.KEY_TOTP_DET = None + pm.master_key = None + + pm.initialize_bip85() + + assert isinstance(pm.bip85, BIP85) + assert pm._bip85_cache == {} diff --git a/src/tests/test_check_critical_coverage.py b/src/tests/test_check_critical_coverage.py new file mode 100644 index 00000000..32428e8e --- /dev/null +++ b/src/tests/test_check_critical_coverage.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +import importlib.util +import sys +from pathlib import Path + +import pytest + + +def _load_module(): + repo_root = Path(__file__).resolve().parents[2] + script_path = repo_root / "scripts" / "check_critical_coverage.py" + spec = importlib.util.spec_from_file_location( + "check_critical_coverage", script_path + ) + assert spec is not None and spec.loader is not None + module = importlib.util.module_from_spec(spec) + sys.modules[spec.name] = module + spec.loader.exec_module(module) + return module + + +coverage_gate = _load_module() + + +def test_parse_threshold_overrides_valid(): + parsed = coverage_gate._parse_threshold_overrides( + ["src/main.py=40", "src/seedpass/core/manager.py=55.5"] + ) + assert parsed["src/main.py"] == 40.0 + assert parsed["src/seedpass/core/manager.py"] == 55.5 + + +@pytest.mark.parametrize( + "value", + [ + "src/main.py", + "src/main.py=abc", + "src/main.py=-1", + "src/main.py=101", + "=50", + ], +) +def test_parse_threshold_overrides_invalid(value): + with pytest.raises(ValueError): + coverage_gate._parse_threshold_overrides([value]) + + +def test_find_file_payload_accepts_absolute_path_suffix(): + files_payload = { + "/tmp/work/src/main.py": {"summary": {"percent_covered": 50.0}}, + "/tmp/work/src/seedpass/core/manager.py": { + "summary": {"percent_covered": 60.0} + }, + } + payload = coverage_gate._find_file_payload(files_payload, "src/main.py") + assert payload == {"summary": {"percent_covered": 50.0}} + + +def test_compute_function_coverage_reports_uncovered(tmp_path): + module_file = tmp_path / "example.py" + module_file.write_text( + "\n".join( + [ + "def covered():", + " return 1", + "", + "def uncovered():", + " return 2", + "", + "class A:", + " def method(self):", + " return 3", + ] + ), + encoding="utf-8", + ) + coverage = coverage_gate._compute_function_coverage( + module_file, executed_lines={1, 2} + ) + by_name = {item.name: item for item in coverage} + assert by_name["covered"].covered is True + assert by_name["uncovered"].covered is False + assert by_name["A.method"].covered is False diff --git a/src/tests/test_cli_agent_mode.py b/src/tests/test_cli_agent_mode.py new file mode 100644 index 00000000..294a0f64 --- /dev/null +++ b/src/tests/test_cli_agent_mode.py @@ -0,0 +1,290 @@ +import json +import sys +from pathlib import Path +from types import SimpleNamespace + +from typer.testing import CliRunner + +sys.path.append(str(Path(__file__).resolve().parents[1])) + +from seedpass.cli import app +from seedpass.cli import agent as agent_cli +from seedpass.core.entry_types import EntryType + +runner = CliRunner() + + +def test_agent_policy_show_defaults(monkeypatch, tmp_path): + monkeypatch.setattr(agent_cli, "APP_DIR", tmp_path) + result = runner.invoke(app, ["agent", "policy-show"]) + assert result.exit_code == 0 + payload = json.loads(result.stdout) + assert payload["allow_export_import"] is False + assert EntryType.PASSWORD.value in payload["allow_kinds"] + + +def test_agent_policy_set_persists(monkeypatch, tmp_path): + monkeypatch.setattr(agent_cli, "APP_DIR", tmp_path) + result = runner.invoke( + app, + [ + "agent", + "policy-set", + "--allow-kind", + "password", + "--allow-kind", + "totp", + "--deny-private-kind", + "seed", + "--allow-export-import", + ], + ) + assert result.exit_code == 0 + payload = json.loads(result.stdout) + assert payload["allow_kinds"] == ["password", "totp"] + assert payload["deny_private_reveal"] == ["seed"] + assert payload["allow_export_import"] is True + + +def test_agent_init_creates_profile(monkeypatch, tmp_path): + monkeypatch.setattr(agent_cli, "APP_DIR", tmp_path) + monkeypatch.setenv("SEEDPASS_PASSWORD", "AgentPass123!") + result = runner.invoke( + app, + [ + "agent", + "init", + "--seed", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", + ], + ) + assert result.exit_code == 0 + payload = json.loads(result.stdout) + assert payload["status"] == "ok" + assert payload["fingerprint"] + profile_dir = Path(payload["profile_dir"]) + assert profile_dir.exists() + assert (profile_dir / "parent_seed.enc").exists() + + +def test_agent_init_requires_password_env(monkeypatch, tmp_path): + monkeypatch.setattr(agent_cli, "APP_DIR", tmp_path) + monkeypatch.delenv("SEEDPASS_PASSWORD", raising=False) + result = runner.invoke( + app, + [ + "agent", + "init", + "--seed", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", + ], + ) + assert result.exit_code == 2 + combined = f"{result.stdout}{result.stderr}" + assert "Missing password env var" in combined + + +def test_agent_get_requires_fingerprint(monkeypatch): + monkeypatch.setenv("SEEDPASS_PASSWORD", "pw") + result = runner.invoke(app, ["agent", "get", "example"]) + assert result.exit_code == 2 + + +def test_agent_get_password_json(monkeypatch): + monkeypatch.setenv("SEEDPASS_PASSWORD", "pw") + monkeypatch.setattr( + agent_cli, + "PasswordManager", + lambda fingerprint, password: SimpleNamespace( + fingerprint=fingerprint, password=password + ), + ) + + class DummyEntryService: + def __init__(self, _pm): + pass + + def search_entries(self, _q): + return [(2, "Example", "", "", False, EntryType.PASSWORD)] + + def retrieve_entry(self, _i): + return {"type": EntryType.PASSWORD.value, "label": "Example", "length": 12} + + def generate_password(self, _length, _index): + return "secret-pass" + + monkeypatch.setattr(agent_cli, "EntryService", DummyEntryService) + monkeypatch.setattr( + agent_cli, + "_load_policy", + lambda **kwargs: {"allow_kinds": ["password"], "deny_private_reveal": []}, + ) + + result = runner.invoke(app, ["--fingerprint", "ABC123", "agent", "get", "example"]) + assert result.exit_code == 0 + payload = json.loads(result.stdout) + assert payload["status"] == "ok" + assert payload["fingerprint"] == "ABC123" + assert payload["secret"] == "secret-pass" + assert payload["kind"] == "password" + + +def test_agent_get_denied_by_policy(monkeypatch): + monkeypatch.setenv("SEEDPASS_PASSWORD", "pw") + monkeypatch.setattr( + agent_cli, + "PasswordManager", + lambda fingerprint, password: SimpleNamespace( + fingerprint=fingerprint, password=password + ), + ) + + class DummyEntryService: + def __init__(self, _pm): + pass + + def search_entries(self, _q): + return [(4, "Seed", "", "", False, EntryType.SEED)] + + def retrieve_entry(self, _i): + return {"kind": EntryType.SEED.value, "label": "Seed"} + + monkeypatch.setattr(agent_cli, "EntryService", DummyEntryService) + monkeypatch.setattr( + agent_cli, + "_load_policy", + lambda **kwargs: { + "allow_kinds": ["password", "totp", "key_value"], + "deny_private_reveal": ["seed"], + }, + ) + + result = runner.invoke(app, ["--fingerprint", "ABC123", "agent", "get", "seed"]) + assert result.exit_code == 1 + payload = json.loads(result.stdout) + assert payload["status"] == "denied" + assert payload["reason"] in {"kind_not_allowed", "private_kind_blocked"} + + +def test_agent_get_ambiguous_returns_error_payload(monkeypatch): + monkeypatch.setenv("SEEDPASS_PASSWORD", "pw") + monkeypatch.setattr( + agent_cli, + "PasswordManager", + lambda fingerprint, password: SimpleNamespace( + fingerprint=fingerprint, password=password + ), + ) + + class DummyEntryService: + def __init__(self, _pm): + pass + + def search_entries(self, _q): + return [ + (2, "Example1", "", "", False, EntryType.PASSWORD), + (3, "Example2", "", "", False, EntryType.PASSWORD), + ] + + monkeypatch.setattr(agent_cli, "EntryService", DummyEntryService) + monkeypatch.setattr( + agent_cli, + "_load_policy", + lambda **kwargs: {"allow_kinds": ["password"], "deny_private_reveal": []}, + ) + + result = runner.invoke(app, ["--fingerprint", "ABC123", "agent", "get", "example"]) + assert result.exit_code == 1 + payload = json.loads(result.stdout) + assert payload["status"] == "error" + assert payload["reason"] == "ambiguous_or_missing" + assert payload["match_count"] == 2 + + +def test_agent_get_key_value_json(monkeypatch): + monkeypatch.setenv("SEEDPASS_PASSWORD", "pw") + monkeypatch.setattr( + agent_cli, + "PasswordManager", + lambda fingerprint, password: SimpleNamespace( + fingerprint=fingerprint, password=password + ), + ) + + class DummyEntryService: + def __init__(self, _pm): + pass + + def search_entries(self, _q): + return [(2, "Key", "", "", False, EntryType.KEY_VALUE)] + + def retrieve_entry(self, _i): + return {"kind": EntryType.KEY_VALUE.value, "label": "Key", "value": "v123"} + + monkeypatch.setattr(agent_cli, "EntryService", DummyEntryService) + monkeypatch.setattr( + agent_cli, + "_load_policy", + lambda **kwargs: {"allow_kinds": ["key_value"], "deny_private_reveal": []}, + ) + + result = runner.invoke(app, ["--fingerprint", "ABC123", "agent", "get", "key"]) + assert result.exit_code == 0 + payload = json.loads(result.stdout) + assert payload["status"] == "ok" + assert payload["kind"] == "key_value" + assert payload["secret"] == "v123" + + +def test_agent_get_unsupported_kind_payload(monkeypatch): + monkeypatch.setenv("SEEDPASS_PASSWORD", "pw") + monkeypatch.setattr( + agent_cli, + "PasswordManager", + lambda fingerprint, password: SimpleNamespace( + fingerprint=fingerprint, password=password + ), + ) + + class DummyEntryService: + def __init__(self, _pm): + pass + + def search_entries(self, _q): + return [(4, "SSH", "", "", False, EntryType.SSH)] + + def retrieve_entry(self, _i): + return {"kind": EntryType.SSH.value, "label": "SSH"} + + monkeypatch.setattr(agent_cli, "EntryService", DummyEntryService) + monkeypatch.setattr( + agent_cli, + "_load_policy", + lambda **kwargs: {"allow_kinds": ["ssh"], "deny_private_reveal": []}, + ) + + result = runner.invoke(app, ["--fingerprint", "ABC123", "agent", "get", "ssh"]) + assert result.exit_code == 1 + payload = json.loads(result.stdout) + assert payload["status"] == "error" + assert payload["reason"] == "unsupported_kind_for_agent_get" + + +def test_agent_policy_show_invalid_json(monkeypatch, tmp_path): + monkeypatch.setattr(agent_cli, "APP_DIR", tmp_path) + (tmp_path / "agent_policy.json").write_text("{", encoding="utf-8") + result = runner.invoke(app, ["agent", "policy-show"]) + assert result.exit_code == 2 + combined = f"{result.stdout}{result.stderr}" + assert "not valid JSON" in combined + + +def test_agent_get_denied_when_policy_invalid(monkeypatch, tmp_path): + monkeypatch.setattr(agent_cli, "APP_DIR", tmp_path) + (tmp_path / "agent_policy.json").write_text("{", encoding="utf-8") + monkeypatch.setenv("SEEDPASS_PASSWORD", "pw") + result = runner.invoke(app, ["--fingerprint", "ABC123", "agent", "get", "example"]) + assert result.exit_code == 1 + payload = json.loads(result.stdout) + assert payload["status"] == "denied" + assert payload["reason"] == "invalid_policy" diff --git a/src/tests/test_cli_clipboard_flag.py b/src/tests/test_cli_clipboard_flag.py new file mode 100644 index 00000000..a51a5498 --- /dev/null +++ b/src/tests/test_cli_clipboard_flag.py @@ -0,0 +1,43 @@ +from typer.testing import CliRunner + +from seedpass.cli import app, entry as cli_entry +from seedpass.core.entry_types import EntryType +from utils.clipboard import ClipboardUnavailableError + +runner = CliRunner() + + +def _stub_service(ctx, raise_error=True): + class Service: + def search_entries(self, query, kinds=None): + return [(1, "label", None, None, False, EntryType.PASSWORD)] + + def retrieve_entry(self, idx): + return {"type": EntryType.PASSWORD.value, "length": 12} + + def generate_password(self, length, index): + if raise_error and not ctx.obj.get("no_clipboard"): + raise ClipboardUnavailableError("missing") + return "pwd" + + return Service() + + +def test_entry_get_handles_missing_clipboard(monkeypatch): + monkeypatch.setattr( + cli_entry, "_get_entry_service", lambda ctx: _stub_service(ctx, True) + ) + result = runner.invoke(app, ["entry", "get", "label"], catch_exceptions=False) + assert result.exit_code == 1 + assert "no-clipboard" in result.stderr.lower() + + +def test_entry_get_no_clipboard_flag(monkeypatch): + monkeypatch.setattr( + cli_entry, "_get_entry_service", lambda ctx: _stub_service(ctx, True) + ) + result = runner.invoke( + app, ["--no-clipboard", "entry", "get", "label"], catch_exceptions=False + ) + assert result.exit_code == 0 + assert "pwd" in result.stdout diff --git a/src/tests/test_cli_config_set_extra.py b/src/tests/test_cli_config_set_extra.py index 6c06b0c2..b6303a98 100644 --- a/src/tests/test_cli_config_set_extra.py +++ b/src/tests/test_cli_config_set_extra.py @@ -3,7 +3,7 @@ from types import SimpleNamespace from typer.testing import CliRunner from seedpass.cli import app -from seedpass import cli +from seedpass.cli import common as cli_common runner = CliRunner() @@ -39,7 +39,7 @@ def test_config_set_variants(monkeypatch, key, value, method, expected): config_manager=SimpleNamespace(**{method: func}), select_fingerprint=lambda fp: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["config", "set", key, value]) diff --git a/src/tests/test_cli_core_services.py b/src/tests/test_cli_core_services.py index df2a6f3d..d81178ce 100644 --- a/src/tests/test_cli_core_services.py +++ b/src/tests/test_cli_core_services.py @@ -5,6 +5,7 @@ from typer.testing import CliRunner from seedpass import cli from seedpass.cli import app +from seedpass.cli import common as cli_common from seedpass.core.entry_types import EntryType runner = CliRunner() @@ -18,7 +19,7 @@ def test_cli_vault_unlock(monkeypatch): return 0.5 pm = SimpleNamespace(unlock_vault=unlock_vault, select_fingerprint=lambda fp: None) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) monkeypatch.setattr(cli.typer, "prompt", lambda *a, **k: "pw") result = runner.invoke(app, ["vault", "unlock"]) assert result.exit_code == 0 @@ -49,7 +50,7 @@ def test_cli_entry_add_search_sync(monkeypatch): sync_vault=lambda: {"manifest_id": "m", "chunk_ids": [], "delta_ids": []}, select_fingerprint=lambda fp: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) # entry add result = runner.invoke(app, ["entry", "add", "Label"]) diff --git a/src/tests/test_cli_doc_examples.py b/src/tests/test_cli_doc_examples.py index 7cf6c69a..f9ec5c5a 100644 --- a/src/tests/test_cli_doc_examples.py +++ b/src/tests/test_cli_doc_examples.py @@ -8,13 +8,15 @@ sys.path.append(str(Path(__file__).resolve().parents[1] / "src")) from typer.testing import CliRunner from seedpass import cli +from seedpass.cli import common as cli_common +from seedpass.cli import api as cli_api from seedpass.core.entry_types import EntryType class DummyPM: def __init__(self): self.entry_manager = SimpleNamespace( - list_entries=lambda sort_by="index", filter_kind=None, include_archived=False: [ + list_entries=lambda sort_by="index", filter_kinds=None, include_archived=False: [ (1, "Label", "user", "url", False) ], search_entries=lambda q, kinds=None: [ @@ -23,7 +25,7 @@ class DummyPM: retrieve_entry=lambda idx: {"type": EntryType.PASSWORD.value, "length": 8}, get_totp_code=lambda idx, seed: "123456", add_entry=lambda label, length, username, url, **kwargs: 1, - add_totp=lambda label, seed, index=None, secret=None, period=30, digits=6: "totp://", + add_totp=lambda label, seed, index=None, secret=None, period=30, digits=6, deterministic=False: "totp://", add_ssh_key=lambda label, seed, index=None, notes="": 2, add_pgp_key=lambda label, seed, index=None, key_type="ed25519", user_id="", notes="": 3, add_nostr_key=lambda label, seed, index=None, notes="": 4, @@ -40,7 +42,7 @@ class DummyPM: ) self.parent_seed = "seed" self.handle_display_totp_codes = lambda: None - self.handle_export_database = lambda path: None + self.handle_export_database = lambda path, **kwargs: None self.handle_import_database = lambda path: None self.change_password = lambda *a, **kw: None self.lock_vault = lambda: None @@ -75,7 +77,7 @@ class DummyPM: set_offline_mode=lambda v: None, get_secret_mode_enabled=lambda: True, get_clipboard_clear_delay=lambda: 30, - get_offline_mode=lambda: False, + get_offline_mode=lambda: True, ) self.secret_mode_enabled = True self.clipboard_clear_delay = 30 @@ -97,13 +99,9 @@ runner = CliRunner() def _setup(monkeypatch): - monkeypatch.setattr(cli, "PasswordManager", lambda: DummyPM()) - monkeypatch.setattr(cli.uvicorn, "run", lambda *a, **kw: None) - monkeypatch.setattr( - cli.api_module, - "start_server", - lambda fingerprint=None, token=None: "token", - ) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: DummyPM()) + monkeypatch.setattr(cli_api.uvicorn, "run", lambda *a, **kw: None) + monkeypatch.setattr(cli_api.api_module, "start_server", lambda fp: "token") monkeypatch.setitem( sys.modules, "requests", SimpleNamespace(post=lambda *a, **kw: None) ) diff --git a/src/tests/test_cli_entry_add_commands.py b/src/tests/test_cli_entry_add_commands.py index e27a03d1..71592874 100644 --- a/src/tests/test_cli_entry_add_commands.py +++ b/src/tests/test_cli_entry_add_commands.py @@ -3,7 +3,7 @@ from types import SimpleNamespace from typer.testing import CliRunner from seedpass.cli import app -from seedpass import cli +from seedpass.cli import common as cli_common from helpers import TEST_SEED runner = CliRunner() @@ -65,8 +65,14 @@ runner = CliRunner() "--digits", "7", ], - ("Label", "seed"), - {"index": 1, "secret": "abc", "period": 45, "digits": 7}, + ("Label", None), + { + "index": 1, + "secret": "abc", + "period": 45, + "digits": 7, + "deterministic": False, + }, "otpauth://uri", ), ( @@ -148,7 +154,7 @@ def test_entry_add_commands( select_fingerprint=lambda fp: None, start_background_vault_sync=start_background_vault_sync, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["entry", command] + cli_args) assert result.exit_code == 0 assert stdout in result.stdout diff --git a/src/tests/test_cli_export_import.py b/src/tests/test_cli_export_import.py index e01b38d0..7b1a53ee 100644 --- a/src/tests/test_cli_export_import.py +++ b/src/tests/test_cli_export_import.py @@ -17,8 +17,8 @@ def _setup_pm(tmp_path: Path): cfg = ConfigManager(vault, tmp_path) backup = BackupManager(tmp_path, cfg) pm = SimpleNamespace( - handle_export_database=lambda p: export_backup( - vault, backup, p, parent_seed=TEST_SEED + handle_export_database=lambda p, encrypt=True: export_backup( + vault, backup, p, parent_seed=TEST_SEED, encrypt=encrypt ), handle_import_database=lambda p: import_backup( vault, backup, p, parent_seed=TEST_SEED @@ -91,3 +91,36 @@ def test_cli_import_round_trip(monkeypatch, tmp_path): rc = main.main(["import", "--file", str(export_path)]) assert rc == 0 assert vault.load_index() == original + + +def test_cli_export_import_unencrypted(monkeypatch, tmp_path): + pm, vault = _setup_pm(tmp_path) + data = { + "schema_version": 4, + "entries": { + "0": { + "label": "example", + "type": "password", + "notes": "", + "custom_fields": [], + "origin": "", + "tags": [], + } + }, + } + vault.save_index(data) + + monkeypatch.setattr(main, "PasswordManager", lambda *a, **k: pm) + monkeypatch.setattr(main, "configure_logging", lambda: None) + monkeypatch.setattr(main, "initialize_app", lambda: None) + monkeypatch.setattr(main.signal, "signal", lambda *a, **k: None) + + export_path = tmp_path / "out.json" + rc = main.main(["export", "--file", str(export_path), "--unencrypted"]) + assert rc == 0 + assert export_path.exists() + + vault.save_index({"schema_version": 4, "entries": {}}) + rc = main.main(["import", "--file", str(export_path)]) + assert rc == 0 + assert vault.load_index() == data diff --git a/src/tests/test_cli_integration.py b/src/tests/test_cli_integration.py index a2978bbe..a7279cda 100644 --- a/src/tests/test_cli_integration.py +++ b/src/tests/test_cli_integration.py @@ -1,11 +1,9 @@ import importlib import shutil -from contextlib import redirect_stdout -from io import StringIO from pathlib import Path from types import SimpleNamespace -from tests.helpers import TEST_PASSWORD, TEST_SEED +from helpers import TEST_PASSWORD, TEST_SEED import colorama import constants @@ -58,31 +56,11 @@ def test_cli_integration(monkeypatch, tmp_path): monkeypatch.setattr(manager_module.PasswordManager, "add_new_fingerprint", auto_add) monkeypatch.setattr("builtins.input", lambda *a, **k: "1") - buf = StringIO() - with redirect_stdout(buf): - try: - cli_module.app(["fingerprint", "add"]) - except SystemExit as e: - assert e.code == 0 - buf.truncate(0) - buf.seek(0) + cli_module.app(["fingerprint", "add"], standalone_mode=False) - with redirect_stdout(buf): - try: - cli_module.app(["entry", "add", "Example", "--length", "8"]) - except SystemExit as e: - assert e.code == 0 - buf.truncate(0) - buf.seek(0) + cli_module.app(["entry", "add", "Example", "--length", "8"], standalone_mode=False) - with redirect_stdout(buf): - try: - cli_module.app(["entry", "get", "Example"]) - except SystemExit as e: - assert e.code == 0 - lines = [line for line in buf.getvalue().splitlines() if line.strip()] - password = lines[-1] - assert len(password.strip()) >= 8 + cli_module.app(["entry", "get", "Example"], standalone_mode=False) fm = manager_module.FingerprintManager(constants.APP_DIR) fp = fm.current_fingerprint diff --git a/src/tests/test_cli_relays.py b/src/tests/test_cli_relays.py index fcfe5fc6..1e6d3ac8 100644 --- a/src/tests/test_cli_relays.py +++ b/src/tests/test_cli_relays.py @@ -2,7 +2,7 @@ from types import SimpleNamespace from typer.testing import CliRunner from seedpass.cli import app -from seedpass import cli +from seedpass.cli import common as cli_common class DummyService: @@ -37,8 +37,8 @@ def test_cli_relay_crud(monkeypatch): def pm_factory(*a, **k): return SimpleNamespace() - monkeypatch.setattr(cli, "PasswordManager", pm_factory) - monkeypatch.setattr(cli, "NostrService", lambda pm: DummyService(relays)) + monkeypatch.setattr(cli_common, "PasswordManager", pm_factory) + monkeypatch.setattr(cli_common, "NostrService", lambda pm: DummyService(relays)) result = runner.invoke(app, ["nostr", "list-relays"]) assert "1: wss://a" in result.stdout diff --git a/src/tests/test_cli_subcommands.py b/src/tests/test_cli_subcommands.py index 6c3d9443..6e9a7449 100644 --- a/src/tests/test_cli_subcommands.py +++ b/src/tests/test_cli_subcommands.py @@ -60,7 +60,7 @@ def test_totp_command(monkeypatch, capsys): monkeypatch.setattr(main, "initialize_app", lambda: None) monkeypatch.setattr(main.signal, "signal", lambda *a, **k: None) monkeypatch.setattr( - main, "copy_to_clipboard", lambda v, d: called.setdefault("val", v) + main, "copy_to_clipboard", lambda v, d: (called.setdefault("val", v), True)[1] ) rc = main.main(["totp", "ex"]) assert rc == 0 diff --git a/src/tests/test_cli_toggle_offline_mode.py b/src/tests/test_cli_toggle_offline_mode.py index 0a464772..a005f9bc 100644 --- a/src/tests/test_cli_toggle_offline_mode.py +++ b/src/tests/test_cli_toggle_offline_mode.py @@ -2,12 +2,12 @@ from types import SimpleNamespace from typer.testing import CliRunner from seedpass.cli import app -from seedpass import cli +from seedpass.cli import common as cli_common runner = CliRunner() -def _make_pm(called, enabled=False): +def _make_pm(called, enabled=True): cfg = SimpleNamespace( get_offline_mode=lambda: enabled, set_offline_mode=lambda v: called.setdefault("enabled", v), @@ -23,17 +23,17 @@ def _make_pm(called, enabled=False): def test_toggle_offline_updates(monkeypatch): called = {} pm = _make_pm(called) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) - result = runner.invoke(app, ["config", "toggle-offline"], input="y\n") + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) + result = runner.invoke(app, ["config", "toggle-offline"], input="n\n") assert result.exit_code == 0 - assert called == {"enabled": True} - assert "Offline mode enabled." in result.stdout + assert called == {"enabled": False} + assert "Offline mode disabled." in result.stdout def test_toggle_offline_keep(monkeypatch): called = {} pm = _make_pm(called, enabled=True) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["config", "toggle-offline"], input="\n") assert result.exit_code == 0 assert called == {"enabled": True} diff --git a/src/tests/test_cli_toggle_secret_mode.py b/src/tests/test_cli_toggle_secret_mode.py index 883afb0b..32062be4 100644 --- a/src/tests/test_cli_toggle_secret_mode.py +++ b/src/tests/test_cli_toggle_secret_mode.py @@ -3,7 +3,7 @@ from types import SimpleNamespace from typer.testing import CliRunner from seedpass.cli import app -from seedpass import cli +from seedpass.cli import common as cli_common runner = CliRunner() @@ -27,7 +27,7 @@ def _make_pm(called, enabled=False, delay=45): def test_toggle_secret_mode_updates(monkeypatch): called = {} pm = _make_pm(called) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["config", "toggle-secret-mode"], input="y\n10\n") assert result.exit_code == 0 assert called == {"enabled": True, "delay": 10} @@ -37,7 +37,7 @@ def test_toggle_secret_mode_updates(monkeypatch): def test_toggle_secret_mode_keep(monkeypatch): called = {} pm = _make_pm(called, enabled=True, delay=30) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["config", "toggle-secret-mode"], input="\n\n") assert result.exit_code == 0 assert called == {"enabled": True, "delay": 30} diff --git a/src/tests/test_cli_vault_stats.py b/src/tests/test_cli_vault_stats.py index 0e479563..78e3fffb 100644 --- a/src/tests/test_cli_vault_stats.py +++ b/src/tests/test_cli_vault_stats.py @@ -3,7 +3,7 @@ from types import SimpleNamespace from typer.testing import CliRunner from seedpass.cli import app -from seedpass import cli +from seedpass.cli import common as cli_common runner = CliRunner() @@ -16,7 +16,7 @@ def test_vault_stats_command(monkeypatch): pm = SimpleNamespace( get_profile_stats=lambda: stats, select_fingerprint=lambda fp: None ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["vault", "stats"]) assert result.exit_code == 0 out = result.stdout diff --git a/src/tests/test_clipboard_utils.py b/src/tests/test_clipboard_utils.py index 5aa50686..ac3bd81e 100644 --- a/src/tests/test_clipboard_utils.py +++ b/src/tests/test_clipboard_utils.py @@ -1,12 +1,15 @@ from pathlib import Path import pyperclip import threading +import shutil import sys sys.path.append(str(Path(__file__).resolve().parents[1])) -from utils.clipboard import copy_to_clipboard +import pytest + +from utils.clipboard import ClipboardUnavailableError, copy_to_clipboard def test_copy_to_clipboard_clears(monkeypatch): @@ -66,3 +69,15 @@ def test_copy_to_clipboard_does_not_clear_if_changed(monkeypatch): fake_copy("other") callbacks["func"]() assert clipboard["text"] == "other" + + +def test_copy_to_clipboard_missing_dependency(monkeypatch): + def fail_copy(*args, **kwargs): + raise pyperclip.PyperclipException("no copy") + + monkeypatch.setattr(pyperclip, "copy", fail_copy) + monkeypatch.setattr(pyperclip, "paste", lambda: "") + monkeypatch.setattr(shutil, "which", lambda cmd: None) + + with pytest.raises(ClipboardUnavailableError): + copy_to_clipboard("secret", 1) diff --git a/src/tests/test_concurrency_stress.py b/src/tests/test_concurrency_stress.py index 2c145c45..1f3ce415 100644 --- a/src/tests/test_concurrency_stress.py +++ b/src/tests/test_concurrency_stress.py @@ -3,6 +3,7 @@ from pathlib import Path from multiprocessing import Process, Queue import pytest from helpers import TEST_SEED, TEST_PASSWORD +from utils.fingerprint import generate_fingerprint sys.path.append(str(Path(__file__).resolve().parents[1])) @@ -51,7 +52,8 @@ def _backup(index_key: bytes, dir_path: Path, loops: int, out: Queue) -> None: @pytest.mark.parametrize("_", range(3)) def test_concurrency_stress(tmp_path: Path, loops: int, _): index_key = derive_index_key(TEST_SEED) - seed_key = derive_key_from_password(TEST_PASSWORD) + fp = generate_fingerprint(TEST_SEED) + seed_key = derive_key_from_password(TEST_PASSWORD, fp) EncryptionManager(seed_key, tmp_path).encrypt_parent_seed(TEST_SEED) enc = EncryptionManager(index_key, tmp_path) Vault(enc, tmp_path).save_index({"counter": 0}) diff --git a/src/tests/test_config_manager.py b/src/tests/test_config_manager.py index f1f4b0e8..4095bd30 100644 --- a/src/tests/test_config_manager.py +++ b/src/tests/test_config_manager.py @@ -23,7 +23,7 @@ def test_config_defaults_and_round_trip(): assert cfg["pin_hash"] == "" assert cfg["password_hash"] == "" assert cfg["additional_backup_path"] == "" - assert cfg["quick_unlock"] is False + assert cfg["quick_unlock_enabled"] is False assert cfg["kdf_iterations"] == 50_000 cfg_mgr.set_pin("1234") diff --git a/src/tests/test_core_api_services.py b/src/tests/test_core_api_services.py new file mode 100644 index 00000000..cfeb1b30 --- /dev/null +++ b/src/tests/test_core_api_services.py @@ -0,0 +1,529 @@ +import pytest +from unittest.mock import MagicMock, patch, call +from pathlib import Path +from threading import Lock +import json +from dataclasses import dataclass + +from seedpass.core.api import ( + VaultService, + ProfileService, + SyncService, + EntryService, + ConfigService, + UtilityService, + NostrService, + VaultExportRequest, + VaultExportResponse, + VaultImportRequest, + ChangePasswordRequest, + UnlockRequest, + UnlockResponse, + BackupParentSeedRequest, + ProfileSwitchRequest, + ProfileRemoveRequest, + PasswordPolicyOptions, + GeneratePasswordRequest, + GeneratePasswordResponse, + AddPasswordEntryRequest, +) +from seedpass.core.manager import PasswordManager +from seedpass.core.entry_types import EntryType + + +@dataclass +class MockPolicy: + include_special_chars: bool = False + min_uppercase: int = 0 + + +@pytest.fixture +def mock_manager(): + """Create a mock PasswordManager with all sub-components mocked.""" + manager = MagicMock(spec=PasswordManager) + + # Mock sub-managers + manager.entry_manager = MagicMock() + manager.config_manager = MagicMock() + manager.fingerprint_manager = MagicMock() + manager.encryption_manager = MagicMock() + manager.vault = MagicMock() + manager.password_generator = MagicMock() + manager.nostr_client = MagicMock() + manager.state_manager = MagicMock() + + # Mock specific attributes + manager.KEY_TOTP_DET = b"mock_totp_key" + manager.parent_seed = "mock_parent_seed" + manager.current_fingerprint = "fp1" + + return manager + + +@pytest.fixture +def mock_bus(): + """Mock the pubsub bus.""" + with patch("seedpass.core.api.bus") as mock: + yield mock + + +class TestVaultService: + @pytest.fixture + def service(self, mock_manager): + return VaultService(mock_manager) + + def test_export_vault(self, service, mock_manager): + req = VaultExportRequest(path=Path("/tmp/export.json")) + resp = service.export_vault(req) + + mock_manager.handle_export_database.assert_called_once_with(req.path) + assert resp.path == req.path + + def test_import_vault(self, service, mock_manager): + req = VaultImportRequest(path=Path("/tmp/import.json")) + service.import_vault(req) + + mock_manager.handle_import_database.assert_called_once_with(req.path) + mock_manager.sync_vault.assert_called_once() + + def test_export_profile(self, service, mock_manager): + mock_index = {"entries": {}} + mock_manager.vault.load_index.return_value = mock_index + mock_manager.vault.encryption_manager.encrypt_data.return_value = b"encrypted" + + result = service.export_profile() + + mock_manager.vault.load_index.assert_called_once() + expected_payload = json.dumps( + mock_index, sort_keys=True, separators=(",", ":") + ).encode("utf-8") + mock_manager.vault.encryption_manager.encrypt_data.assert_called_once_with( + expected_payload + ) + assert result == b"encrypted" + + def test_import_profile(self, service, mock_manager): + data = b"encrypted_data" + decrypted_json = json.dumps({"entries": {}}) + mock_manager.vault.encryption_manager.decrypt_data.return_value = ( + decrypted_json.encode("utf-8") + ) + + service.import_profile(data) + + mock_manager.vault.encryption_manager.decrypt_data.assert_called_once_with( + data, context="profile" + ) + mock_manager.vault.save_index.assert_called_once_with( + json.loads(decrypted_json) + ) + mock_manager.sync_vault.assert_called_once() + + def test_change_password(self, service, mock_manager): + req = ChangePasswordRequest(old_password="old", new_password="new") + service.change_password(req) + + mock_manager.change_password.assert_called_once_with("old", "new") + + def test_unlock(self, service, mock_manager): + mock_manager.unlock_vault.return_value = 0.5 + req = UnlockRequest(password="secret") + resp = service.unlock(req) + + mock_manager.unlock_vault.assert_called_once_with("secret") + assert resp.duration == 0.5 + + def test_lock(self, service, mock_manager): + service.lock() + mock_manager.lock_vault.assert_called_once() + + def test_backup_parent_seed(self, service, mock_manager): + req = BackupParentSeedRequest(path=Path("/tmp/seed.enc"), password="pw") + service.backup_parent_seed(req) + + mock_manager.handle_backup_reveal_parent_seed.assert_called_once_with( + req.path, password=req.password + ) + + def test_stats(self, service, mock_manager): + expected_stats = {"entries": 10} + mock_manager.get_profile_stats.return_value = expected_stats + + stats = service.stats() + + mock_manager.get_profile_stats.assert_called_once() + assert stats == expected_stats + + +class TestProfileService: + @pytest.fixture + def service(self, mock_manager): + return ProfileService(mock_manager) + + def test_list_profiles(self, service, mock_manager): + mock_manager.fingerprint_manager.list_fingerprints.return_value = ["fp1", "fp2"] + profiles = service.list_profiles() + + mock_manager.fingerprint_manager.list_fingerprints.assert_called_once() + assert profiles == ["fp1", "fp2"] + + def test_add_profile(self, service, mock_manager): + mock_manager.fingerprint_manager.current_fingerprint = "new_fp" + result = service.add_profile() + + mock_manager.add_new_fingerprint.assert_called_once() + assert result == "new_fp" + + def test_remove_profile(self, service, mock_manager): + req = ProfileRemoveRequest(fingerprint="fp1") + service.remove_profile(req) + + mock_manager.fingerprint_manager.remove_fingerprint.assert_called_once_with( + "fp1" + ) + + def test_switch_profile(self, service, mock_manager): + req = ProfileSwitchRequest(fingerprint="fp2", password="pw") + service.switch_profile(req) + + mock_manager.select_fingerprint.assert_called_once_with("fp2", password="pw") + + +class TestSyncService: + @pytest.fixture + def service(self, mock_manager): + return SyncService(mock_manager) + + def test_sync(self, service, mock_manager, mock_bus): + mock_result = {"manifest_id": "m1"} + mock_manager.sync_vault.return_value = mock_result + + result = service.sync() + + mock_bus.publish.assert_has_calls( + [call("sync_started"), call("sync_finished", mock_result)] + ) + mock_manager.sync_vault.assert_called_once() + assert result.manifest_id == "m1" + + def test_sync_none(self, service, mock_manager, mock_bus): + mock_manager.sync_vault.return_value = None + + result = service.sync() + + mock_bus.publish.assert_has_calls( + [call("sync_started"), call("sync_finished", None)] + ) + assert result is None + + def test_start_background_sync(self, service, mock_manager): + service.start_background_sync() + mock_manager.start_background_sync.assert_called_once() + + def test_start_background_vault_sync(self, service, mock_manager): + service.start_background_vault_sync("summary") + mock_manager.start_background_vault_sync.assert_called_once_with("summary") + + +class TestEntryService: + @pytest.fixture + def service(self, mock_manager): + return EntryService(mock_manager) + + def test_list_entries(self, service, mock_manager): + mock_manager.entry_manager.list_entries.return_value = [] + entries = service.list_entries() + + mock_manager.entry_manager.list_entries.assert_called_once_with( + sort_by="index", filter_kinds=None, include_archived=False + ) + assert entries == [] + + def test_search_entries(self, service, mock_manager): + mock_manager.entry_manager.search_entries.return_value = [] + results = service.search_entries("query") + + mock_manager.entry_manager.search_entries.assert_called_once_with( + "query", kinds=None + ) + assert results == [] + + def test_retrieve_entry(self, service, mock_manager): + mock_entry = {"id": 1, "label": "test"} + mock_manager.entry_manager.retrieve_entry.return_value = mock_entry + entry = service.retrieve_entry(1) + + mock_manager.entry_manager.retrieve_entry.assert_called_once_with(1) + assert entry == mock_entry + + def test_generate_password_default(self, service, mock_manager): + # Case where _generate_password_for_entry is not available + del mock_manager._generate_password_for_entry + mock_manager.password_generator.generate_password.return_value = "pass123" + mock_manager.entry_manager.retrieve_entry.return_value = {} + + password = service.generate_password(10, 1) + + mock_manager.password_generator.generate_password.assert_called_once_with(10, 1) + assert password == "pass123" + + def test_generate_password_custom(self, service, mock_manager): + # Case where _generate_password_for_entry is available + mock_manager._generate_password_for_entry = MagicMock(return_value="custom123") + mock_manager.entry_manager.retrieve_entry.return_value = {"policy": {}} + + password = service.generate_password(10, 1) + + mock_manager._generate_password_for_entry.assert_called_once() + assert password == "custom123" + + def test_get_totp_code(self, service, mock_manager): + mock_manager.KEY_TOTP_DET = b"key" + mock_manager.entry_manager.get_totp_code.return_value = "123456" + + code = service.get_totp_code(1) + + mock_manager.entry_manager.get_totp_code.assert_called_once_with(1, b"key") + assert code == "123456" + + def test_add_entry(self, service, mock_manager): + mock_manager.entry_manager.add_entry.return_value = 1 + + idx = service.add_entry("label", 12, "user", "url") + + mock_manager.entry_manager.add_entry.assert_called_once() + mock_manager.start_background_vault_sync.assert_called_once() + assert idx == 1 + + def test_add_totp(self, service, mock_manager): + mock_manager.entry_manager.add_totp.return_value = "otpauth://..." + + uri = service.add_totp("label") + + mock_manager.entry_manager.add_totp.assert_called_once() + mock_manager.start_background_vault_sync.assert_called_once() + assert uri == "otpauth://..." + + def test_add_ssh_key(self, service, mock_manager): + mock_manager.entry_manager.add_ssh_key.return_value = 2 + + idx = service.add_ssh_key("label") + + mock_manager.entry_manager.add_ssh_key.assert_called_once() + mock_manager.start_background_vault_sync.assert_called_once() + assert idx == 2 + + def test_add_pgp_key(self, service, mock_manager): + mock_manager.entry_manager.add_pgp_key.return_value = 3 + + idx = service.add_pgp_key("label") + + mock_manager.entry_manager.add_pgp_key.assert_called_once() + mock_manager.start_background_vault_sync.assert_called_once() + assert idx == 3 + + def test_add_nostr_key(self, service, mock_manager): + mock_manager.entry_manager.add_nostr_key.return_value = 4 + + idx = service.add_nostr_key("label") + + mock_manager.entry_manager.add_nostr_key.assert_called_once() + mock_manager.start_background_vault_sync.assert_called_once() + assert idx == 4 + + def test_add_seed(self, service, mock_manager): + mock_manager.entry_manager.add_seed.return_value = 5 + + idx = service.add_seed("label") + + mock_manager.entry_manager.add_seed.assert_called_once() + mock_manager.start_background_vault_sync.assert_called_once() + assert idx == 5 + + def test_add_key_value(self, service, mock_manager): + mock_manager.entry_manager.add_key_value.return_value = 6 + + idx = service.add_key_value("label", "k", "v") + + mock_manager.entry_manager.add_key_value.assert_called_once() + mock_manager.start_background_vault_sync.assert_called_once() + assert idx == 6 + + def test_add_managed_account(self, service, mock_manager): + mock_manager.entry_manager.add_managed_account.return_value = 7 + + idx = service.add_managed_account("label") + + mock_manager.entry_manager.add_managed_account.assert_called_once() + mock_manager.start_background_vault_sync.assert_called_once() + assert idx == 7 + + def test_modify_entry(self, service, mock_manager): + service.modify_entry(1, label="new_label") + + mock_manager.entry_manager.modify_entry.assert_called_once_with( + 1, + username=None, + url=None, + notes=None, + label="new_label", + period=None, + digits=None, + key=None, + value=None, + ) + mock_manager.start_background_vault_sync.assert_called_once() + + def test_archive_entry(self, service, mock_manager): + service.archive_entry(1) + + mock_manager.entry_manager.archive_entry.assert_called_once_with(1) + mock_manager.start_background_vault_sync.assert_called_once() + + def test_restore_entry(self, service, mock_manager): + service.restore_entry(1) + + mock_manager.entry_manager.restore_entry.assert_called_once_with(1) + mock_manager.start_background_vault_sync.assert_called_once() + + def test_export_totp_entries(self, service, mock_manager): + mock_manager.entry_manager.export_totp_entries.return_value = {} + + result = service.export_totp_entries() + + mock_manager.entry_manager.export_totp_entries.assert_called_once() + assert result == {} + + def test_display_totp_codes(self, service, mock_manager): + service.display_totp_codes() + mock_manager.handle_display_totp_codes.assert_called_once() + + +class TestConfigService: + @pytest.fixture + def service(self, mock_manager): + return ConfigService(mock_manager) + + def test_get(self, service, mock_manager): + mock_manager.config_manager.load_config.return_value = {"key": "value"} + val = service.get("key") + + mock_manager.config_manager.load_config.assert_called_once_with( + require_pin=False + ) + assert val == "value" + + def test_set_simple(self, service, mock_manager): + service.set("inactivity_timeout", "10") + mock_manager.config_manager.set_inactivity_timeout.assert_called_once_with(10.0) + + def test_set_bool(self, service, mock_manager): + service.set("secret_mode_enabled", "true") + mock_manager.config_manager.set_secret_mode_enabled.assert_called_once_with( + True + ) + + def test_set_relays(self, service, mock_manager): + # relays setter logic: ("set_relays", lambda v: (v, {"require_pin": False})), + # but the lambda returns a tuple (arg, kwargs) + # and then getattr(cfg, method_name)(arg, **kwargs) is called. + # Wait, the lambda returns (v, {"require_pin": False}) + # So arg is v, kwargs is {"require_pin": False} + + service.set("relays", ["r1"]) + mock_manager.config_manager.set_relays.assert_called_once_with( + ["r1"], require_pin=False + ) + + def test_set_invalid_key(self, service, mock_manager): + with pytest.raises(KeyError): + service.set("invalid_key", "val") + + def test_get_secret_mode_enabled(self, service, mock_manager): + mock_manager.config_manager.get_secret_mode_enabled.return_value = True + assert service.get_secret_mode_enabled() is True + + def test_get_clipboard_clear_delay(self, service, mock_manager): + mock_manager.config_manager.get_clipboard_clear_delay.return_value = 45 + assert service.get_clipboard_clear_delay() == 45 + + def test_set_secret_mode(self, service, mock_manager): + service.set_secret_mode(True, 30) + + mock_manager.config_manager.set_secret_mode_enabled.assert_called_once_with( + True + ) + mock_manager.config_manager.set_clipboard_clear_delay.assert_called_once_with( + 30 + ) + assert mock_manager.secret_mode_enabled is True + assert mock_manager.clipboard_clear_delay == 30 + + def test_get_offline_mode(self, service, mock_manager): + mock_manager.config_manager.get_offline_mode.return_value = False + assert service.get_offline_mode() is False + + def test_set_offline_mode(self, service, mock_manager): + service.set_offline_mode(True) + + mock_manager.config_manager.set_offline_mode.assert_called_once_with(True) + assert mock_manager.offline_mode is True + + +class TestUtilityService: + @pytest.fixture + def service(self, mock_manager): + return UtilityService(mock_manager) + + def test_generate_password(self, service, mock_manager): + mock_manager.password_generator.generate_password.return_value = "pw" + + # Mock policy with a real dataclass + base_policy = MockPolicy(include_special_chars=False, min_uppercase=0) + mock_manager.password_generator.policy = base_policy + + result = service.generate_password( + 10, include_special_chars=True, min_uppercase=5 + ) + + mock_manager.password_generator.generate_password.assert_called_once_with(10) + assert result == "pw" + + # Verify policy was restored + assert mock_manager.password_generator.policy == base_policy + + def test_verify_checksum(self, service, mock_manager): + service.verify_checksum() + mock_manager.handle_verify_checksum.assert_called_once() + + def test_update_checksum(self, service, mock_manager): + service.update_checksum() + mock_manager.handle_update_script_checksum.assert_called_once() + + +class TestNostrService: + @pytest.fixture + def service(self, mock_manager): + return NostrService(mock_manager) + + def test_get_pubkey(self, service, mock_manager): + mock_manager.nostr_client.key_manager.get_npub.return_value = "npub1..." + assert service.get_pubkey() == "npub1..." + + def test_list_relays(self, service, mock_manager): + mock_manager.state_manager.list_relays.return_value = ["r1"] + assert service.list_relays() == ["r1"] + + def test_add_relay(self, service, mock_manager): + mock_manager.state_manager.list_relays.return_value = ["r1", "r2"] + service.add_relay("r2") + + mock_manager.state_manager.add_relay.assert_called_once_with("r2") + assert mock_manager.nostr_client.relays == ["r1", "r2"] + + def test_remove_relay(self, service, mock_manager): + mock_manager.state_manager.list_relays.return_value = [] + service.remove_relay(0) + + mock_manager.state_manager.remove_relay.assert_called_once_with(0) + assert mock_manager.nostr_client.relays == [] diff --git a/src/tests/test_custom_fields_display.py b/src/tests/test_custom_fields_display.py index b2fc9431..0a95084a 100644 --- a/src/tests/test_custom_fields_display.py +++ b/src/tests/test_custom_fields_display.py @@ -1,53 +1,30 @@ import sys from pathlib import Path -from tempfile import TemporaryDirectory from types import SimpleNamespace -from helpers import create_vault, TEST_SEED, TEST_PASSWORD - sys.path.append(str(Path(__file__).resolve().parents[1])) -from seedpass.core.entry_management import EntryManager -from seedpass.core.backup import BackupManager -from seedpass.core.manager import PasswordManager, EncryptionMode -from seedpass.core.config_manager import ConfigManager +def test_retrieve_entry_shows_custom_fields(monkeypatch, capsys, password_manager): + pm = password_manager + pm.password_generator = SimpleNamespace(generate_password=lambda l, i: "pw") + pm.nostr_client = SimpleNamespace() -def test_retrieve_entry_shows_custom_fields(monkeypatch, capsys): - with TemporaryDirectory() as tmpdir: - tmp_path = Path(tmpdir) - vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) - cfg_mgr = ConfigManager(vault, tmp_path) - backup_mgr = BackupManager(tmp_path, cfg_mgr) - entry_mgr = EntryManager(vault, backup_mgr) + pm.entry_manager.add_entry( + "example", + 8, + custom_fields=[ + {"label": "visible", "value": "shown", "is_hidden": False}, + {"label": "token", "value": "secret", "is_hidden": True}, + ], + ) - pm = PasswordManager.__new__(PasswordManager) - pm.encryption_mode = EncryptionMode.SEED_ONLY - pm.encryption_manager = enc_mgr - pm.vault = vault - pm.entry_manager = entry_mgr - pm.backup_manager = backup_mgr - pm.password_generator = SimpleNamespace(generate_password=lambda l, i: "pw") - pm.parent_seed = TEST_SEED - pm.nostr_client = SimpleNamespace() - pm.fingerprint_dir = tmp_path - pm.secret_mode_enabled = False + inputs = iter(["0", "y", "", ""]) + monkeypatch.setattr("builtins.input", lambda *a, **k: next(inputs)) - entry_mgr.add_entry( - "example", - 8, - custom_fields=[ - {"label": "visible", "value": "shown", "is_hidden": False}, - {"label": "token", "value": "secret", "is_hidden": True}, - ], - ) - - inputs = iter(["0", "y", "", ""]) - monkeypatch.setattr("builtins.input", lambda *a, **k: next(inputs)) - - pm.handle_retrieve_entry() - out = capsys.readouterr().out - assert "Additional Fields:" in out - assert "visible: shown" in out - assert "token" in out - assert "secret" in out + pm.handle_retrieve_entry() + out = capsys.readouterr().out + assert "Additional Fields:" in out + assert "visible: shown" in out + assert "token" in out + assert "secret" in out diff --git a/src/tests/test_decrypt_messages.py b/src/tests/test_decrypt_messages.py new file mode 100644 index 00000000..5d595a8a --- /dev/null +++ b/src/tests/test_decrypt_messages.py @@ -0,0 +1,58 @@ +import base64 +import hashlib +import unicodedata + +import pytest +from cryptography.fernet import InvalidToken + +from helpers import TEST_PASSWORD, TEST_SEED +from seedpass.core.encryption import ( + EncryptionManager, + LegacyFormatRequiresMigrationError, +) +from utils.key_derivation import derive_index_key + + +def test_wrong_password_message(tmp_path): + key = derive_index_key(TEST_SEED) + mgr = EncryptionManager(key, tmp_path) + payload = mgr.encrypt_data(b"secret") + + wrong_key = bytearray(key) + wrong_key[0] ^= 1 + wrong_mgr = EncryptionManager(bytes(wrong_key), tmp_path) + + with pytest.raises(InvalidToken, match="invalid key or corrupt file") as exc: + wrong_mgr.decrypt_data(payload, context="index") + assert "index" in str(exc.value) + + +def test_legacy_file_requires_migration_message(tmp_path, monkeypatch): + def _fast_legacy_key(password: str, iterations: int = 100_000) -> bytes: + normalized = unicodedata.normalize("NFKD", password).strip().encode("utf-8") + key = hashlib.pbkdf2_hmac("sha256", normalized, b"", 1, dklen=32) + return base64.urlsafe_b64encode(key) + + monkeypatch.setattr( + "seedpass.core.encryption._derive_legacy_key_from_password", _fast_legacy_key + ) + + legacy_key = _fast_legacy_key(TEST_PASSWORD) + legacy_mgr = EncryptionManager(legacy_key, tmp_path) + token = legacy_mgr.fernet.encrypt(b"secret") + + new_mgr = EncryptionManager(derive_index_key(TEST_SEED), tmp_path) + with pytest.raises(LegacyFormatRequiresMigrationError, match="index") as exc: + new_mgr.decrypt_data(token, context="index") + assert "index" in str(exc.value) + + +def test_corrupted_data_message(tmp_path): + key = derive_index_key(TEST_SEED) + mgr = EncryptionManager(key, tmp_path) + payload = bytearray(mgr.encrypt_data(b"secret")) + payload[-1] ^= 0xFF + + with pytest.raises(InvalidToken, match="invalid key or corrupt file") as exc: + mgr.decrypt_data(bytes(payload), context="index") + assert "index" in str(exc.value) diff --git a/src/tests/test_duplicate_seed_profile_creation.py b/src/tests/test_duplicate_seed_profile_creation.py new file mode 100644 index 00000000..0918af7b --- /dev/null +++ b/src/tests/test_duplicate_seed_profile_creation.py @@ -0,0 +1,53 @@ +import pytest +from pathlib import Path +from tempfile import TemporaryDirectory + +from seedpass.core.manager import PasswordManager +from utils.fingerprint_manager import FingerprintManager +from utils.fingerprint import generate_fingerprint + +VALID_SEED = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" + + +def _setup_pm(tmp_path, monkeypatch): + pm = PasswordManager.__new__(PasswordManager) + pm.fingerprint_manager = FingerprintManager(tmp_path) + pm.config_manager = type("Cfg", (), {"get_kdf_iterations": lambda self: 1})() + monkeypatch.setattr("seedpass.core.manager.prompt_for_password", lambda: "pw") + monkeypatch.setattr("seedpass.core.manager.derive_index_key", lambda seed: b"idx") + monkeypatch.setattr( + "seedpass.core.manager.derive_key_from_password", lambda *a, **k: b"k" + ) + + class DummyEnc: + def __init__(self, *a, **k): + pass + + def encrypt_parent_seed(self, seed): + pass + + monkeypatch.setattr("seedpass.core.manager.EncryptionManager", DummyEnc) + monkeypatch.setattr("seedpass.core.manager.Vault", lambda *a, **k: object()) + monkeypatch.setattr( + "seedpass.core.manager.ConfigManager", lambda **k: pm.config_manager + ) + monkeypatch.setattr(pm, "initialize_bip85", lambda: None) + monkeypatch.setattr(pm, "initialize_managers", lambda: None) + monkeypatch.setattr(pm, "start_background_sync", lambda: None) + monkeypatch.setattr(pm, "store_hashed_password", lambda pw: None) + monkeypatch.setattr("seedpass.core.manager.confirm_action", lambda *_: False) + return pm + + +def test_duplicate_seed_profile_creation(monkeypatch): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + pm = _setup_pm(tmp_path, monkeypatch) + + fp1 = pm._finalize_existing_seed(VALID_SEED, password="pw") + assert fp1 == generate_fingerprint(VALID_SEED) + assert pm.fingerprint_manager.list_fingerprints() == [fp1] + + fp2 = pm._finalize_existing_seed(VALID_SEED, password="pw") + assert fp2 is None + assert pm.fingerprint_manager.list_fingerprints() == [fp1] diff --git a/src/tests/test_edit_tags_from_retrieve.py b/src/tests/test_edit_tags_from_retrieve.py index ab936579..2cf38ddf 100644 --- a/src/tests/test_edit_tags_from_retrieve.py +++ b/src/tests/test_edit_tags_from_retrieve.py @@ -1,49 +1,26 @@ import sys from pathlib import Path -from tempfile import TemporaryDirectory from types import SimpleNamespace -from helpers import create_vault, TEST_SEED, TEST_PASSWORD - sys.path.append(str(Path(__file__).resolve().parents[1])) -from seedpass.core.entry_management import EntryManager -from seedpass.core.backup import BackupManager -from seedpass.core.manager import PasswordManager, EncryptionMode -from seedpass.core.config_manager import ConfigManager - class FakePasswordGenerator: def generate_password(self, length: int, index: int) -> str: # noqa: D401 return "pw" -def test_edit_tags_from_retrieve(monkeypatch): - with TemporaryDirectory() as tmpdir: - tmp_path = Path(tmpdir) - vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) - cfg_mgr = ConfigManager(vault, tmp_path) - backup_mgr = BackupManager(tmp_path, cfg_mgr) - entry_mgr = EntryManager(vault, backup_mgr) +def test_edit_tags_from_retrieve(monkeypatch, password_manager): + pm = password_manager + pm.password_generator = FakePasswordGenerator() + pm.nostr_client = SimpleNamespace() - pm = PasswordManager.__new__(PasswordManager) - pm.encryption_mode = EncryptionMode.SEED_ONLY - pm.encryption_manager = enc_mgr - pm.vault = vault - pm.entry_manager = entry_mgr - pm.backup_manager = backup_mgr - pm.password_generator = FakePasswordGenerator() - pm.parent_seed = TEST_SEED - pm.nostr_client = SimpleNamespace() - pm.fingerprint_dir = tmp_path - pm.secret_mode_enabled = False + index = pm.entry_manager.add_entry("example.com", 8, tags=["old"]) - index = entry_mgr.add_entry("example.com", 8, tags=["old"]) + inputs = iter([str(index), "t", "newtag", ""]) + monkeypatch.setattr("builtins.input", lambda *a, **k: next(inputs)) - inputs = iter([str(index), "t", "newtag", ""]) - monkeypatch.setattr("builtins.input", lambda *a, **k: next(inputs)) + pm.handle_retrieve_entry() - pm.handle_retrieve_entry() - - entry = entry_mgr.retrieve_entry(index) - assert entry.get("tags", []) == ["newtag"] + entry = pm.entry_manager.retrieve_entry(index) + assert entry.get("tags", []) == ["newtag"] diff --git a/src/tests/test_encryption_checksum.py b/src/tests/test_encryption_checksum.py index c95f82d8..82b2dc40 100644 --- a/src/tests/test_encryption_checksum.py +++ b/src/tests/test_encryption_checksum.py @@ -1,5 +1,6 @@ import re import sys +import hashlib from pathlib import Path from tempfile import TemporaryDirectory @@ -23,7 +24,7 @@ def test_encryption_checksum_workflow(): manager.update_checksum() enc_file = tmp_path / "seedpass_entries_db.json.enc" - chk_file = tmp_path / "seedpass_entries_db.json_checksum.txt" + chk_file = tmp_path / "seedpass_entries_db_checksum.txt" checksum = chk_file.read_text().strip() assert re.fullmatch(r"[0-9a-f]{64}", checksum) @@ -33,3 +34,24 @@ def test_encryption_checksum_workflow(): manager.update_checksum() assert verify_and_update_checksum(str(enc_file), str(chk_file)) + + +def test_update_checksum_removes_legacy(tmp_path): + key = base64.urlsafe_b64encode(os.urandom(32)) + manager = EncryptionManager(key, tmp_path) + + manager.save_json_data({"value": 1}) + + legacy = tmp_path / "seedpass_entries_db.json_checksum.txt" + legacy.write_text("legacy") + + manager.update_checksum() + + enc_file = tmp_path / "seedpass_entries_db.json.enc" + new_chk = tmp_path / "seedpass_entries_db_checksum.txt" + + assert new_chk.exists() + assert not legacy.exists() + + expected = hashlib.sha256(enc_file.read_bytes()).hexdigest() + assert new_chk.read_text() == expected diff --git a/src/tests/test_encryption_files.py b/src/tests/test_encryption_files.py index 04fb5110..d374cff3 100644 --- a/src/tests/test_encryption_files.py +++ b/src/tests/test_encryption_files.py @@ -5,6 +5,7 @@ from tempfile import TemporaryDirectory import os import base64 +import pytest sys.path.append(str(Path(__file__).resolve().parents[1])) @@ -40,3 +41,15 @@ def test_encrypt_and_decrypt_file_binary_round_trip(): file_path = Path(tmpdir) / rel raw = file_path.read_bytes() assert raw != payload + + +def test_encrypt_file_rejects_traversal(): + with TemporaryDirectory() as tmpdir: + key = base64.urlsafe_b64encode(os.urandom(32)) + manager = EncryptionManager(key, Path(tmpdir)) + + with pytest.raises(ValueError): + manager.encrypt_and_save_file(b"data", Path("../evil.enc")) + + with pytest.raises(ValueError): + manager.encrypt_and_save_file(b"data", Path("/abs.enc")) diff --git a/src/tests/test_encryption_fuzz.py b/src/tests/test_encryption_fuzz.py new file mode 100644 index 00000000..0899a9d7 --- /dev/null +++ b/src/tests/test_encryption_fuzz.py @@ -0,0 +1,37 @@ +import pytest +from pathlib import Path +from cryptography.fernet import Fernet +from hypothesis import given, strategies as st, settings, HealthCheck + +from seedpass.core.encryption import EncryptionManager + + +@given(blob=st.binary()) +@settings( + deadline=None, + max_examples=25, + suppress_health_check=[HealthCheck.function_scoped_fixture], +) +def test_encrypt_decrypt_roundtrip(blob: bytes, tmp_path: Path) -> None: + """Ensure arbitrary data round-trips through EncryptionManager.""" + key = Fernet.generate_key() + mgr = EncryptionManager(key, tmp_path) + encrypted = mgr.encrypt_data(blob) + assert mgr.decrypt_data(encrypted) == blob + + +@given(blob=st.binary()) +@settings( + deadline=None, + max_examples=25, + suppress_health_check=[HealthCheck.function_scoped_fixture], +) +def test_corrupted_ciphertext_fails(blob: bytes, tmp_path: Path) -> None: + """Corrupted ciphertext should not decrypt successfully.""" + key = Fernet.generate_key() + mgr = EncryptionManager(key, tmp_path) + encrypted = bytearray(mgr.encrypt_data(blob)) + if encrypted: + encrypted[0] ^= 0xFF + with pytest.raises(Exception): + mgr.decrypt_data(bytes(encrypted)) diff --git a/src/tests/test_encryption_validate_seed.py b/src/tests/test_encryption_validate_seed.py new file mode 100644 index 00000000..5806d76e --- /dev/null +++ b/src/tests/test_encryption_validate_seed.py @@ -0,0 +1,30 @@ +import sys +from pathlib import Path + +import pytest +from cryptography.fernet import Fernet + +sys.path.append(str(Path(__file__).resolve().parents[1])) + +from seedpass.core.encryption import EncryptionManager + + +def make_manager(tmp_path): + key = Fernet.generate_key() + return EncryptionManager(key, tmp_path) + + +def test_validate_seed_valid_mnemonic(tmp_path): + manager = make_manager(tmp_path) + valid = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" + is_valid, error = manager.validate_seed(valid) + assert is_valid is True + assert error is None + + +def test_validate_seed_invalid_mnemonic(tmp_path): + manager = make_manager(tmp_path) + invalid = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon" + is_valid, error = manager.validate_seed(invalid) + assert is_valid is False + assert error == "Invalid seed phrase." diff --git a/src/tests/test_entry_policy_override.py b/src/tests/test_entry_policy_override.py index c23c1c85..79b31ff9 100644 --- a/src/tests/test_entry_policy_override.py +++ b/src/tests/test_entry_policy_override.py @@ -21,8 +21,8 @@ class DummyEnc: class DummyBIP85: - def derive_entropy(self, index: int, bytes_len: int, app_no: int = 32) -> bytes: - return bytes((index + i) % 256 for i in range(bytes_len)) + def derive_entropy(self, index: int, entropy_bytes: int, app_no: int = 32) -> bytes: + return bytes((index + i) % 256 for i in range(entropy_bytes)) def make_manager(tmp_path: Path) -> PasswordManager: diff --git a/src/tests/test_event_handler.py b/src/tests/test_event_handler.py deleted file mode 100644 index d84cd561..00000000 --- a/src/tests/test_event_handler.py +++ /dev/null @@ -1,43 +0,0 @@ -import logging - -import sys -from pathlib import Path - -sys.path.append(str(Path(__file__).resolve().parents[1])) - -from nostr import event_handler - - -class SimpleEvent: - def __init__(self, id: str, created_at: int, content: str) -> None: - self.id = id - self.created_at = created_at - self.content = content - - -def test_handle_new_event_logs(caplog): - handler = event_handler.EventHandler() - evt = SimpleEvent("1", 0, "hello") - - caplog.set_level(logging.INFO, logger=event_handler.logger.name) - handler.handle_new_event(evt) - - assert ( - "[New Event] ID: 1 | Created At: 1970-01-01 00:00:00 | Content: hello" - in caplog.text - ) - - -def test_handle_new_event_error(monkeypatch, caplog): - handler = event_handler.EventHandler() - evt = SimpleEvent("2", 0, "boom") - - def raise_info(*args, **kwargs): - raise RuntimeError("fail") - - monkeypatch.setattr(event_handler.logger, "info", raise_info) - caplog.set_level(logging.ERROR, logger=event_handler.logger.name) - - handler.handle_new_event(evt) - - assert "Error handling new event: fail" in caplog.text diff --git a/src/tests/test_full_sync_roundtrip.py b/src/tests/test_full_sync_roundtrip.py index 69a24d3d..c9709f7a 100644 --- a/src/tests/test_full_sync_roundtrip.py +++ b/src/tests/test_full_sync_roundtrip.py @@ -2,7 +2,7 @@ import asyncio from pathlib import Path from tempfile import TemporaryDirectory -from helpers import create_vault, dummy_nostr_client +from helpers import create_vault from seedpass.core.entry_management import EntryManager from seedpass.core.backup import BackupManager diff --git a/src/tests/test_full_sync_roundtrip_new.py b/src/tests/test_full_sync_roundtrip_new.py index 69a24d3d..c9709f7a 100644 --- a/src/tests/test_full_sync_roundtrip_new.py +++ b/src/tests/test_full_sync_roundtrip_new.py @@ -2,7 +2,7 @@ import asyncio from pathlib import Path from tempfile import TemporaryDirectory -from helpers import create_vault, dummy_nostr_client +from helpers import create_vault from seedpass.core.entry_management import EntryManager from seedpass.core.backup import BackupManager diff --git a/src/tests/test_fuzz_key_derivation.py b/src/tests/test_fuzz_key_derivation.py index 8d7c113d..0849408d 100644 --- a/src/tests/test_fuzz_key_derivation.py +++ b/src/tests/test_fuzz_key_derivation.py @@ -3,12 +3,17 @@ from pathlib import Path from hypothesis import given, strategies as st, settings, HealthCheck from mnemonic import Mnemonic +import hashlib +import base64 +import os from utils.key_derivation import ( derive_key_from_password, derive_key_from_password_argon2, derive_index_key, + KdfConfig, ) +from utils.fingerprint import generate_fingerprint from seedpass.core.encryption import EncryptionManager cfg_values = st.one_of( @@ -32,17 +37,29 @@ cfg_values = st.one_of( def test_fuzz_key_round_trip(password, seed_bytes, config, mode, tmp_path: Path): """Ensure EncryptionManager round-trips arbitrary data.""" seed_phrase = Mnemonic("english").to_mnemonic(seed_bytes) + fp = generate_fingerprint(seed_phrase) if mode == "argon2": - key = derive_key_from_password_argon2( - password, time_cost=1, memory_cost=8, parallelism=1 + cfg = KdfConfig( + params={"time_cost": 1, "memory_cost": 8, "parallelism": 1}, + salt_b64=base64.b64encode( + hashlib.sha256(fp.encode()).digest()[:16] + ).decode(), ) + key = derive_key_from_password_argon2(password, cfg) else: - key = derive_key_from_password(password, iterations=1) + key = derive_key_from_password(password, fp, iterations=1) + cfg = KdfConfig( + name="pbkdf2", + params={"iterations": 1}, + salt_b64=base64.b64encode( + hashlib.sha256(fp.encode()).digest()[:16] + ).decode(), + ) enc_mgr = EncryptionManager(key, tmp_path) # Parent seed round trip - enc_mgr.encrypt_parent_seed(seed_phrase) + enc_mgr.encrypt_parent_seed(seed_phrase, kdf=cfg) assert enc_mgr.decrypt_parent_seed() == seed_phrase # JSON data round trip diff --git a/src/tests/test_generate_test_profile_sync.py b/src/tests/test_generate_test_profile_sync.py index 216bb3d6..b8c5435e 100644 --- a/src/tests/test_generate_test_profile_sync.py +++ b/src/tests/test_generate_test_profile_sync.py @@ -5,8 +5,6 @@ from tempfile import TemporaryDirectory import asyncio import gzip -from helpers import dummy_nostr_client - def load_script(): script_path = ( diff --git a/src/tests/test_get_entry_summaries_archived_view.py b/src/tests/test_get_entry_summaries_archived_view.py new file mode 100644 index 00000000..971605ce --- /dev/null +++ b/src/tests/test_get_entry_summaries_archived_view.py @@ -0,0 +1,50 @@ +from pathlib import Path +from tempfile import TemporaryDirectory +from types import SimpleNamespace +import queue + +from helpers import create_vault, TEST_SEED, TEST_PASSWORD + +from seedpass.core.entry_management import EntryManager +from seedpass.core.backup import BackupManager +from seedpass.core.config_manager import ConfigManager +from seedpass.core.manager import PasswordManager, EncryptionMode + + +def test_get_entry_summaries_excludes_archived_and_view_handler(monkeypatch, capsys): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + backup_mgr = BackupManager(tmp_path, cfg_mgr) + entry_mgr = EntryManager(vault, backup_mgr) + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = enc_mgr + pm.vault = vault + pm.entry_manager = entry_mgr + pm.backup_manager = backup_mgr + pm.parent_seed = TEST_SEED + pm.nostr_client = SimpleNamespace() + pm.fingerprint_dir = tmp_path + pm.is_dirty = False + pm.notifications = queue.Queue() + + active_idx = entry_mgr.add_entry("active.com", 8) + archived_idx = entry_mgr.add_entry("archived.com", 8) + entry_mgr.archive_entry(archived_idx) + + summaries = entry_mgr.get_entry_summaries() + assert [s[0] for s in summaries] == [active_idx] + for idx, _, _ in summaries: + assert entry_mgr.retrieve_entry(idx)["archived"] is False + + summaries_all = entry_mgr.get_entry_summaries(include_archived=True) + assert [s[0] for s in summaries_all] == [active_idx, archived_idx] + + monkeypatch.setattr("builtins.input", lambda *_: "") + pm.handle_view_archived_entries() + out = capsys.readouterr().out + assert "archived.com" in out + assert "active.com" not in out diff --git a/src/tests/test_get_entry_summaries_updates.py b/src/tests/test_get_entry_summaries_updates.py new file mode 100644 index 00000000..8a00c5af --- /dev/null +++ b/src/tests/test_get_entry_summaries_updates.py @@ -0,0 +1,48 @@ +from pathlib import Path +from tempfile import TemporaryDirectory + +from helpers import create_vault, TEST_SEED, TEST_PASSWORD + +from seedpass.core.entry_management import EntryManager +from seedpass.core.backup import BackupManager +from seedpass.core.config_manager import ConfigManager + + +def _create_entry_manager(tmp_path: Path) -> EntryManager: + vault, _ = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + backup_mgr = BackupManager(tmp_path, cfg_mgr) + return EntryManager(vault, backup_mgr) + + +def test_get_entry_summaries_updates_label(): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + em = _create_entry_manager(tmp_path) + idx = em.add_entry("old", 8) + + summaries = em.get_entry_summaries() + assert summaries == [(idx, "password", "old")] + + em.modify_entry(idx, label="new") + summaries = em.get_entry_summaries() + assert summaries == [(idx, "password", "new")] + + +def test_get_entry_summaries_updates_archive_restore(): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + em = _create_entry_manager(tmp_path) + keep_idx = em.add_entry("keep", 8) + drop_idx = em.add_entry("drop", 8) + + summaries = em.get_entry_summaries() + assert [s[0] for s in summaries] == [keep_idx, drop_idx] + + em.archive_entry(drop_idx) + summaries = em.get_entry_summaries() + assert [s[0] for s in summaries] == [keep_idx] + + em.restore_entry(drop_idx) + summaries = em.get_entry_summaries() + assert [s[0] for s in summaries] == [keep_idx, drop_idx] diff --git a/src/tests/test_gui_features.py b/src/tests/test_gui_features.py index 90f02799..f7f8b63c 100644 --- a/src/tests/test_gui_features.py +++ b/src/tests/test_gui_features.py @@ -30,8 +30,8 @@ class DummyEntries: self.data = [(1, "Example", None, None, False)] self.code = "111111" - def list_entries(self, sort_by="index", filter_kind=None, include_archived=False): - if filter_kind: + def list_entries(self, sort_by="index", filter_kinds=None, include_archived=False): + if filter_kinds: return [(idx, label, None, None, False) for idx, label, *_ in self.data] return self.data diff --git a/src/tests/test_gui_headless.py b/src/tests/test_gui_headless.py index d7b01290..3e8d56eb 100644 --- a/src/tests/test_gui_headless.py +++ b/src/tests/test_gui_headless.py @@ -33,7 +33,9 @@ class FakeEntries: self.added.append(("password", label, length, username, url)) return 1 - def add_totp(self, label): + def add_totp( + self, label, deterministic=False, index=None, secret=None, period=30, digits=6 + ): self.added.append(("totp", label)) return 1 diff --git a/src/tests/test_gui_sync.py b/src/tests/test_gui_sync.py index 6ef1ed23..cf1aa951 100644 --- a/src/tests/test_gui_sync.py +++ b/src/tests/test_gui_sync.py @@ -9,7 +9,7 @@ from seedpass_gui.app import MainWindow class DummyEntries: - def list_entries(self, sort_by="index", filter_kind=None, include_archived=False): + def list_entries(self, sort_by="index", filter_kinds=None, include_archived=False): return [] def search_entries(self, q): diff --git a/src/tests/test_handle_switch_fingerprint.py b/src/tests/test_handle_switch_fingerprint.py new file mode 100644 index 00000000..ec40ce6e --- /dev/null +++ b/src/tests/test_handle_switch_fingerprint.py @@ -0,0 +1,32 @@ +from main import handle_switch_fingerprint + + +def test_handle_switch_fingerprint_active_profile(monkeypatch, capsys): + class DummyFingerprintManager: + def __init__(self): + self.fingerprints = ["fp1", "fp2"] + + def list_fingerprints(self): + return self.fingerprints + + def display_name(self, fp): + return fp + + class DummyPM: + def __init__(self): + self.fingerprint_manager = DummyFingerprintManager() + self.current_fingerprint = "fp1" + self.decrypted = False + + def select_fingerprint(self, fingerprint): + self.decrypted = True + return True + + pm = DummyPM() + monkeypatch.setattr("builtins.input", lambda _: "1") + + handle_switch_fingerprint(pm) + + captured = capsys.readouterr() + assert "already active" in captured.out.lower() + assert pm.decrypted is False diff --git a/src/tests/test_index_import_export.py b/src/tests/test_index_import_export.py index a9ee75a8..f549278f 100644 --- a/src/tests/test_index_import_export.py +++ b/src/tests/test_index_import_export.py @@ -4,6 +4,7 @@ from tempfile import TemporaryDirectory import pytest import sys from helpers import create_vault, TEST_SEED, TEST_PASSWORD +from utils.fingerprint import generate_fingerprint sys.path.append(str(Path(__file__).resolve().parents[1])) @@ -16,7 +17,8 @@ PASSWORD = "passw0rd" def setup_vault(tmp: Path) -> Vault: - seed_key = derive_key_from_password(PASSWORD) + fp = generate_fingerprint(SEED) + seed_key = derive_key_from_password(PASSWORD, fp) seed_mgr = EncryptionManager(seed_key, tmp) seed_mgr.encrypt_parent_seed(SEED) diff --git a/src/tests/test_invalid_password_message.py b/src/tests/test_invalid_password_message.py new file mode 100644 index 00000000..5fac05ff --- /dev/null +++ b/src/tests/test_invalid_password_message.py @@ -0,0 +1,23 @@ +from pathlib import Path +from tempfile import TemporaryDirectory + +import pytest + +from seedpass.core.manager import PasswordManager +from seedpass.core.config_manager import ConfigManager +from seedpass.core.errors import SeedPassError +from helpers import create_vault, TEST_SEED, TEST_PASSWORD + + +def test_invalid_password_shows_friendly_message_once(capsys): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + vault, _ = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + pm = PasswordManager.__new__(PasswordManager) + pm.config_manager = ConfigManager(vault, tmp_path) + pm.fingerprint_dir = tmp_path + pm.parent_seed = "" + with pytest.raises(SeedPassError): + pm.load_parent_seed(tmp_path, password="wrongpass") + captured = capsys.readouterr().out + assert captured.count("Incorrect password or corrupt file") == 1 diff --git a/src/tests/test_kdf_iteration_fallback.py b/src/tests/test_kdf_iteration_fallback.py new file mode 100644 index 00000000..4d159aa7 --- /dev/null +++ b/src/tests/test_kdf_iteration_fallback.py @@ -0,0 +1,51 @@ +import bcrypt +from pathlib import Path +from tempfile import TemporaryDirectory + +from helpers import TEST_SEED, TEST_PASSWORD +from utils.fingerprint import generate_fingerprint +from utils.key_derivation import derive_index_key, derive_key_from_password +from seedpass.core.encryption import EncryptionManager +from seedpass.core.vault import Vault +from seedpass.core.config_manager import ConfigManager +from seedpass.core.manager import PasswordManager, EncryptionMode + + +def test_kdf_iteration_fallback(monkeypatch): + with TemporaryDirectory() as td: + tmp = Path(td) + fp_name = generate_fingerprint(TEST_SEED) + fp_dir = tmp / fp_name + fp_dir.mkdir() + + seed_key = derive_key_from_password(TEST_PASSWORD, fp_name, iterations=100_000) + EncryptionManager(seed_key, fp_dir).encrypt_parent_seed(TEST_SEED) + + index_key = derive_index_key(TEST_SEED) + enc_mgr = EncryptionManager(index_key, fp_dir) + vault = Vault(enc_mgr, fp_dir) + cfg_mgr = ConfigManager(vault, fp_dir) + cfg = cfg_mgr.load_config(require_pin=False) + cfg["password_hash"] = bcrypt.hashpw( + TEST_PASSWORD.encode(), bcrypt.gensalt() + ).decode() + cfg["kdf_iterations"] = 100_000 + cfg_mgr.save_config(cfg) + + cfg["kdf_iterations"] = 50_000 + cfg_mgr.save_config(cfg) + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.config_manager = cfg_mgr + pm.fingerprint_dir = fp_dir + pm.current_fingerprint = fp_name + pm.verify_password = lambda pw: True + + monkeypatch.setattr( + "seedpass.core.manager.prompt_existing_password", lambda *_: TEST_PASSWORD + ) + + assert pm.setup_encryption_manager(fp_dir, exit_on_fail=False) + assert pm.parent_seed == TEST_SEED + assert cfg_mgr.get_kdf_iterations() == 100_000 diff --git a/src/tests/test_kdf_modes.py b/src/tests/test_kdf_modes.py index 10f721dc..96ceebf4 100644 --- a/src/tests/test_kdf_modes.py +++ b/src/tests/test_kdf_modes.py @@ -1,4 +1,6 @@ import bcrypt +import hashlib +import base64 from pathlib import Path from tempfile import TemporaryDirectory from types import SimpleNamespace @@ -7,6 +9,7 @@ from utils.key_derivation import ( derive_key_from_password, derive_key_from_password_argon2, derive_index_key, + KdfConfig, ) from seedpass.core.encryption import EncryptionManager from seedpass.core.vault import Vault @@ -19,11 +22,26 @@ TEST_PASSWORD = "pw" def _setup_profile(tmp: Path, mode: str): argon_kwargs = dict(time_cost=1, memory_cost=8, parallelism=1) + fp = tmp.name if mode == "argon2": - seed_key = derive_key_from_password_argon2(TEST_PASSWORD, **argon_kwargs) + cfg = KdfConfig( + params=argon_kwargs, + salt_b64=base64.b64encode( + hashlib.sha256(fp.encode()).digest()[:16] + ).decode(), + ) + seed_key = derive_key_from_password_argon2(TEST_PASSWORD, cfg) + EncryptionManager(seed_key, tmp).encrypt_parent_seed(TEST_SEED, kdf=cfg) else: - seed_key = derive_key_from_password(TEST_PASSWORD, iterations=1) - EncryptionManager(seed_key, tmp).encrypt_parent_seed(TEST_SEED) + seed_key = derive_key_from_password(TEST_PASSWORD, fp, iterations=1) + cfg = KdfConfig( + name="pbkdf2", + params={"iterations": 1}, + salt_b64=base64.b64encode( + hashlib.sha256(fp.encode()).digest()[:16] + ).decode(), + ) + EncryptionManager(seed_key, tmp).encrypt_parent_seed(TEST_SEED, kdf=cfg) index_key = derive_index_key(TEST_SEED) enc_mgr = EncryptionManager(index_key, tmp) @@ -44,7 +62,7 @@ def _make_pm(tmp: Path, cfg: ConfigManager): pm.encryption_mode = EncryptionMode.SEED_ONLY pm.config_manager = cfg pm.fingerprint_dir = tmp - pm.current_fingerprint = "fp" + pm.current_fingerprint = tmp.name pm.verify_password = lambda pw: True return pm @@ -64,9 +82,9 @@ def test_setup_encryption_manager_kdf_modes(monkeypatch): ) if mode == "argon2": monkeypatch.setattr( - "seedpass.core.manager.derive_key_from_password_argon2", - lambda pw, salt=None: derive_key_from_password_argon2( - pw, salt=salt if salt is not None else b"\x00" * 16, **argon_kwargs + "seedpass.core.manager.KdfConfig", + lambda salt_b64, **_: KdfConfig( + params=argon_kwargs, salt_b64=salt_b64 ), ) monkeypatch.setattr(PasswordManager, "initialize_bip85", lambda self: None) @@ -75,3 +93,26 @@ def test_setup_encryption_manager_kdf_modes(monkeypatch): ) assert pm.setup_encryption_manager(path, exit_on_fail=False) assert pm.parent_seed == TEST_SEED + + +def test_kdf_param_round_trip(tmp_path): + cfg = KdfConfig( + params={"time_cost": 3, "memory_cost": 32, "parallelism": 1}, + salt_b64=base64.b64encode(b"static-salt-1234").decode(), + ) + key = derive_key_from_password_argon2(TEST_PASSWORD, cfg) + mgr = EncryptionManager(key, tmp_path) + mgr.encrypt_parent_seed(TEST_SEED, kdf=cfg) + stored = mgr.get_file_kdf(Path("parent_seed.enc")) + assert stored.params == cfg.params + + +def test_vault_kdf_migration(tmp_path): + index_key = derive_index_key(TEST_SEED) + mgr = EncryptionManager(index_key, tmp_path) + vault = Vault(mgr, tmp_path) + old_kdf = KdfConfig(name="hkdf", version=0, params={}, salt_b64="") + mgr.save_json_data({"entries": {}}, vault.index_file, kdf=old_kdf) + vault.load_index() + new_kdf = mgr.get_file_kdf(vault.index_file) + assert new_kdf.version == KdfConfig().version diff --git a/src/tests/test_kdf_strength_slider.py b/src/tests/test_kdf_strength_slider.py new file mode 100644 index 00000000..a10017c2 --- /dev/null +++ b/src/tests/test_kdf_strength_slider.py @@ -0,0 +1,19 @@ +from pathlib import Path +from tempfile import TemporaryDirectory +from types import SimpleNamespace + +from helpers import create_vault, TEST_SEED, TEST_PASSWORD +from seedpass.core.config_manager import ConfigManager +from main import handle_set_kdf_iterations + + +def test_kdf_strength_slider_persists(monkeypatch): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + pm = SimpleNamespace(config_manager=cfg_mgr) + inputs = iter(["3"]) + monkeypatch.setattr("builtins.input", lambda *_: next(inputs)) + handle_set_kdf_iterations(pm) + assert cfg_mgr.get_kdf_iterations() == 100_000 diff --git a/src/tests/test_key_derivation.py b/src/tests/test_key_derivation.py index bfa0c653..c5bec438 100644 --- a/src/tests/test_key_derivation.py +++ b/src/tests/test_key_derivation.py @@ -1,25 +1,36 @@ import logging import pytest +import logging +import hashlib +import base64 +from utils.fingerprint import generate_fingerprint from utils.key_derivation import ( derive_key_from_password, derive_key_from_password_argon2, derive_index_key_seed_only, derive_index_key, + KdfConfig, ) -def test_derive_key_deterministic(): +def test_pbkdf2_fingerprint_affects_key(): password = "correct horse battery staple" - key1 = derive_key_from_password(password, iterations=1) - key2 = derive_key_from_password(password, iterations=1) + fp1 = generate_fingerprint("seed one") + fp2 = generate_fingerprint("seed two") + + key1 = derive_key_from_password(password, fp1, iterations=1) + key2 = derive_key_from_password(password, fp1, iterations=1) + key3 = derive_key_from_password(password, fp2, iterations=1) + assert key1 == key2 + assert key1 != key3 assert len(key1) == 44 - logging.info("Deterministic key derivation succeeded") + logging.info("PBKDF2 fingerprint behaviour verified") def test_derive_key_empty_password_error(): with pytest.raises(ValueError): - derive_key_from_password("") + derive_key_from_password("", "fp") logging.info("Empty password correctly raised ValueError") @@ -36,9 +47,23 @@ def test_derive_index_key_seed_only(): assert derive_index_key(seed) == derive_index_key_seed_only(seed) -def test_argon2_key_deterministic(): - pw = "correct horse battery staple" - k1 = derive_key_from_password_argon2(pw, time_cost=1, memory_cost=8, parallelism=1) - k2 = derive_key_from_password_argon2(pw, time_cost=1, memory_cost=8, parallelism=1) +def test_argon2_fingerprint_affects_key(): + password = "correct horse battery staple" + fp1 = generate_fingerprint("seed one") + fp2 = generate_fingerprint("seed two") + + cfg1 = KdfConfig( + params={"time_cost": 1, "memory_cost": 8, "parallelism": 1}, + salt_b64=base64.b64encode(hashlib.sha256(fp1.encode()).digest()[:16]).decode(), + ) + cfg2 = KdfConfig( + params={"time_cost": 1, "memory_cost": 8, "parallelism": 1}, + salt_b64=base64.b64encode(hashlib.sha256(fp2.encode()).digest()[:16]).decode(), + ) + k1 = derive_key_from_password_argon2(password, cfg1) + k2 = derive_key_from_password_argon2(password, cfg1) + k3 = derive_key_from_password_argon2(password, cfg2) + assert k1 == k2 + assert k1 != k3 assert len(k1) == 44 diff --git a/src/tests/test_key_hierarchy.py b/src/tests/test_key_hierarchy.py new file mode 100644 index 00000000..28c5d45e --- /dev/null +++ b/src/tests/test_key_hierarchy.py @@ -0,0 +1,19 @@ +import base64 +from bip_utils import Bip39SeedGenerator +from utils.key_hierarchy import kd +from utils.key_derivation import derive_index_key + + +def test_kd_distinct_infos(): + root = b"root" * 8 + k1 = kd(root, b"info1") + k2 = kd(root, b"info2") + assert k1 != k2 + + +def test_derive_index_key_matches_hierarchy(): + seed = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" + seed_bytes = Bip39SeedGenerator(seed).Generate() + master = kd(seed_bytes, b"seedpass:v1:master") + expected = base64.urlsafe_b64encode(kd(master, b"seedpass:v1:storage")) + assert derive_index_key(seed) == expected diff --git a/src/tests/test_key_value_entry.py b/src/tests/test_key_value_entry.py index 56f1e8eb..b1324ea5 100644 --- a/src/tests/test_key_value_entry.py +++ b/src/tests/test_key_value_entry.py @@ -37,10 +37,30 @@ def test_add_and_modify_key_value(): "tags": [], } + # Appears in listing + assert em.list_entries() == [(idx, "API entry", None, None, False)] + + # Modify key and value em.modify_entry(idx, key="api_key2", value="def456") updated = em.retrieve_entry(idx) assert updated["key"] == "api_key2" assert updated["value"] == "def456" + # Archive and ensure it disappears from the default listing + em.archive_entry(idx) + archived = em.retrieve_entry(idx) + assert archived["archived"] is True + assert em.list_entries() == [] + assert em.list_entries(include_archived=True) == [ + (idx, "API entry", None, None, True) + ] + + # Restore and ensure it reappears + em.restore_entry(idx) + restored = em.retrieve_entry(idx) + assert restored["archived"] is False + assert em.list_entries() == [(idx, "API entry", None, None, False)] + + # Values are not searchable results = em.search_entries("def456") assert results == [] diff --git a/src/tests/test_legacy_format_exception.py b/src/tests/test_legacy_format_exception.py new file mode 100644 index 00000000..6ac55077 --- /dev/null +++ b/src/tests/test_legacy_format_exception.py @@ -0,0 +1,43 @@ +import json +from pathlib import Path + +import pytest +from cryptography.fernet import Fernet + +from seedpass.core.encryption import ( + EncryptionManager, + LegacyFormatRequiresMigrationError, + _derive_legacy_key_from_password, +) +from seedpass.core.vault import Vault + + +def test_decrypt_data_raises_legacy_exception(tmp_path: Path) -> None: + key = Fernet.generate_key() + mgr = EncryptionManager(key, tmp_path) + with pytest.raises(LegacyFormatRequiresMigrationError): + mgr.decrypt_data(b"not a valid token") + + +def test_vault_handles_legacy_exception(tmp_path: Path, monkeypatch) -> None: + password = "secret" + legacy_key = _derive_legacy_key_from_password(password) + legacy_mgr = EncryptionManager(legacy_key, tmp_path) + payload = json.dumps( + {"schema_version": 3, "entries": {"1": {"kind": "password", "password": "x"}}} + ).encode("utf-8") + legacy_bytes = legacy_mgr.fernet.encrypt(payload) + index_file = tmp_path / Vault.INDEX_FILENAME + index_file.write_bytes(legacy_bytes) + + new_mgr = EncryptionManager(Fernet.generate_key(), tmp_path) + vault = Vault(new_mgr, tmp_path) + + monkeypatch.setattr("builtins.input", lambda *args, **kwargs: "1") + monkeypatch.setattr( + "seedpass.core.vault.prompt_existing_password", lambda *args, **kwargs: password + ) + + data, migrated, last = vault.load_index(return_migration_flags=True) + assert "1" in data["entries"] + assert last is False diff --git a/src/tests/test_legacy_migration.py b/src/tests/test_legacy_migration.py index 87cd3edf..0c7d8d56 100644 --- a/src/tests/test_legacy_migration.py +++ b/src/tests/test_legacy_migration.py @@ -1,13 +1,23 @@ import json +import base64 import hashlib from pathlib import Path +import pytest + from helpers import create_vault, TEST_SEED, TEST_PASSWORD from utils.key_derivation import derive_index_key from cryptography.fernet import Fernet +from types import SimpleNamespace +import asyncio +import gzip + +from seedpass.core.manager import PasswordManager, EncryptionMode +from seedpass.core.vault import Vault +from seedpass.core.errors import SeedPassError -def test_legacy_index_migrates(tmp_path: Path): +def test_legacy_index_migrates(monkeypatch, tmp_path: Path): vault, _ = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) key = derive_index_key(TEST_SEED) @@ -33,6 +43,8 @@ def test_legacy_index_migrates(tmp_path: Path): hashlib.sha256(enc).hexdigest() ) + monkeypatch.setattr("builtins.input", lambda *_a, **_k: "y") + loaded = vault.load_index() assert loaded == data @@ -40,3 +52,381 @@ def test_legacy_index_migrates(tmp_path: Path): assert new_file.exists() assert not legacy_file.exists() assert not (tmp_path / "seedpass_passwords_db_checksum.txt").exists() + backup = tmp_path / "legacy_backups" / "seedpass_passwords_db.json.enc" + assert backup.exists() + + +def test_failed_migration_restores_legacy(monkeypatch, tmp_path: Path): + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + + key = derive_index_key(TEST_SEED) + data = {"schema_version": 4, "entries": {}} + enc = Fernet(key).encrypt(json.dumps(data).encode()) + legacy_file = tmp_path / "seedpass_passwords_db.json.enc" + legacy_file.write_bytes(enc) + checksum = hashlib.sha256(enc).hexdigest() + (tmp_path / "seedpass_passwords_db_checksum.txt").write_text(checksum) + + monkeypatch.setattr("builtins.input", lambda *_a, **_k: "y") + + def bad_load_json(_path): + raise ValueError("boom") + + monkeypatch.setattr(enc_mgr, "load_json_data", bad_load_json) + + with pytest.raises(RuntimeError, match="Migration failed:"): + vault.load_index() + + # Legacy file restored and new index removed + assert legacy_file.exists() + assert not (tmp_path / "seedpass_entries_db.json.enc").exists() + assert (tmp_path / "seedpass_passwords_db_checksum.txt").read_text() == checksum + assert not vault.migrated_from_legacy + + +def test_migrated_index_has_v3_prefix(monkeypatch, tmp_path: Path): + vault, _ = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + + key = derive_index_key(TEST_SEED) + data = {"schema_version": 4, "entries": {}} + enc = Fernet(key).encrypt(json.dumps(data).encode()) + legacy_file = tmp_path / "seedpass_passwords_db.json.enc" + legacy_file.write_bytes(enc) + (tmp_path / "seedpass_passwords_db_checksum.txt").write_text( + hashlib.sha256(enc).hexdigest() + ) + + monkeypatch.setattr("builtins.input", lambda *_a, **_k: "y") + + vault.load_index() + + new_file = tmp_path / "seedpass_entries_db.json.enc" + payload = json.loads(new_file.read_text()) + assert base64.b64decode(payload["ct"]).startswith(b"V3|") + assert vault.migrated_from_legacy + + +def test_legacy_index_migration_removes_strays(monkeypatch, tmp_path: Path): + vault, _ = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + + key = derive_index_key(TEST_SEED) + data = {"schema_version": 4, "entries": {}} + enc = Fernet(key).encrypt(json.dumps(data).encode()) + + legacy_file = tmp_path / "seedpass_passwords_db.json.enc" + legacy_file.write_bytes(enc) + (tmp_path / "seedpass_passwords_db_checksum.txt").write_text( + hashlib.sha256(enc).hexdigest() + ) + + stray_file = tmp_path / "seedpass_passwords_db.extra.enc" + stray_file.write_text("junk") + + monkeypatch.setattr("builtins.input", lambda *_a, **_k: "y") + + # First load triggers migration and removes stray legacy files + loaded = vault.load_index() + assert loaded == data + assert not stray_file.exists() + + # Subsequent load should not detect any legacy files + loaded_again = vault.load_index() + assert loaded_again == data + + assert (tmp_path / "seedpass_entries_db.json.enc").exists() + assert list(tmp_path.glob("seedpass_passwords_db*.enc")) == [] + assert not (tmp_path / "seedpass_passwords_db_checksum.txt").exists() + + +def test_migration_syncs_when_confirmed(monkeypatch, tmp_path: Path): + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + + key = derive_index_key(TEST_SEED) + data = {"schema_version": 4, "entries": {}} + enc = Fernet(key).encrypt(json.dumps(data).encode()) + legacy_file = tmp_path / "seedpass_passwords_db.json.enc" + legacy_file.write_bytes(enc) + + monkeypatch.setattr("builtins.input", lambda *_a, **_k: "y") + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = enc_mgr + pm.vault = Vault(enc_mgr, tmp_path) + pm.parent_seed = TEST_SEED + pm.fingerprint_dir = tmp_path + pm.current_fingerprint = tmp_path.name + pm.bip85 = SimpleNamespace() + from seedpass.core.config_manager import ConfigManager + + cfg_mgr = ConfigManager(pm.vault, tmp_path) + cfg = cfg_mgr.load_config(require_pin=False) + cfg["offline_mode"] = False + cfg_mgr.save_config(cfg) + pm.config_manager = cfg_mgr + pm.offline_mode = False + + calls = {"sync": 0} + pm.sync_vault = lambda *a, **k: calls.__setitem__("sync", calls["sync"] + 1) or { + "manifest_id": "m", + "chunk_ids": [], + "delta_ids": [], + } + + monkeypatch.setattr( + "seedpass.core.manager.NostrClient", lambda *a, **k: SimpleNamespace() + ) + monkeypatch.setattr("seedpass.core.manager.confirm_action", lambda *_a, **_k: True) + + pm.initialize_managers() + assert calls["sync"] == 1 + assert enc_mgr.last_migration_performed is False + + +def test_migration_declines_sync(monkeypatch, tmp_path: Path): + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + + key = derive_index_key(TEST_SEED) + data = {"schema_version": 4, "entries": {}} + enc = Fernet(key).encrypt(json.dumps(data).encode()) + legacy_file = tmp_path / "seedpass_passwords_db.json.enc" + legacy_file.write_bytes(enc) + + monkeypatch.setattr("builtins.input", lambda *_a, **_k: "y") + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = enc_mgr + pm.vault = Vault(enc_mgr, tmp_path) + pm.parent_seed = TEST_SEED + pm.fingerprint_dir = tmp_path + pm.current_fingerprint = tmp_path.name + pm.bip85 = SimpleNamespace() + + calls = {"sync": 0} + pm.sync_vault = lambda *a, **k: calls.__setitem__("sync", calls["sync"] + 1) or { + "manifest_id": "m", + "chunk_ids": [], + "delta_ids": [], + } + + monkeypatch.setattr( + "seedpass.core.manager.NostrClient", lambda *a, **k: SimpleNamespace() + ) + monkeypatch.setattr("seedpass.core.manager.confirm_action", lambda *_a, **_k: False) + + pm.initialize_managers() + assert calls["sync"] == 0 + assert enc_mgr.last_migration_performed is False + + +def test_legacy_nostr_payload_syncs_when_confirmed(monkeypatch, tmp_path: Path): + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + + key = derive_index_key(TEST_SEED) + data = {"schema_version": 4, "entries": {}} + legacy_enc = Fernet(key).encrypt(json.dumps(data).encode()) + compressed = gzip.compress(legacy_enc) + + class DummyClient: + def __init__(self): + self.relays = [] + self.last_error = None + self.fingerprint = None + + async def fetch_latest_snapshot(self): + from nostr.backup_models import Manifest + + return Manifest(ver=1, algo="gzip", chunks=[], delta_since=None), [ + compressed + ] + + async def fetch_deltas_since(self, version): + return [] + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = enc_mgr + pm.vault = Vault(enc_mgr, tmp_path) + pm.parent_seed = TEST_SEED + pm.fingerprint_dir = tmp_path + pm.current_fingerprint = tmp_path.name + pm.nostr_client = DummyClient() + pm.offline_mode = False + + calls = {"sync": 0} + + async def fake_sync_vault_async(*_a, **_k): + calls["sync"] += 1 + return True + + pm.sync_vault_async = fake_sync_vault_async + monkeypatch.setattr("seedpass.core.manager.confirm_action", lambda *_a, **_k: True) + + asyncio.run(pm.sync_index_from_nostr_async()) + assert calls["sync"] == 1 + assert pm.vault.load_index() == data + assert enc_mgr.last_migration_performed is False + + +def test_legacy_index_reinit_syncs_once_when_confirmed(monkeypatch, tmp_path: Path): + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + + key = derive_index_key(TEST_SEED) + data = {"schema_version": 4, "entries": {}} + enc = Fernet(key).encrypt(json.dumps(data).encode()) + legacy_file = tmp_path / "seedpass_passwords_db.json.enc" + legacy_file.write_bytes(enc) + + monkeypatch.setattr("builtins.input", lambda *_a, **_k: "y") + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = enc_mgr + pm.vault = Vault(enc_mgr, tmp_path) + pm.parent_seed = TEST_SEED + pm.fingerprint_dir = tmp_path + pm.current_fingerprint = tmp_path.name + pm.bip85 = SimpleNamespace() + pm.offline_mode = True + + monkeypatch.setattr( + "seedpass.core.manager.NostrClient", lambda *a, **k: SimpleNamespace() + ) + + calls = {"sync": 0} + pm.sync_vault = lambda *a, **k: calls.__setitem__("sync", calls["sync"] + 1) or { + "manifest_id": "m", + "chunk_ids": [], + "delta_ids": [], + } + + monkeypatch.setattr("seedpass.core.manager.confirm_action", lambda *_a, **_k: True) + + pm.initialize_managers() + pm.initialize_managers() + + assert calls["sync"] == 0 + assert enc_mgr.last_migration_performed is False + + +def test_schema_migration_no_sync_prompt(monkeypatch, tmp_path: Path): + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + + data = {"schema_version": 3, "entries": {}} + enc_mgr.save_json_data(data, Path("seedpass_entries_db.json.enc")) + enc_mgr.update_checksum(Path("seedpass_entries_db.json.enc")) + assert enc_mgr.last_migration_performed is False + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = enc_mgr + pm.vault = Vault(enc_mgr, tmp_path) + pm.parent_seed = TEST_SEED + pm.fingerprint_dir = tmp_path + pm.current_fingerprint = tmp_path.name + pm.bip85 = SimpleNamespace() + from seedpass.core.config_manager import ConfigManager + + cfg_mgr = ConfigManager(pm.vault, tmp_path) + cfg = cfg_mgr.load_config(require_pin=False) + cfg["offline_mode"] = False + cfg_mgr.save_config(cfg) + pm.config_manager = cfg_mgr + pm.offline_mode = False + + calls = {"sync": 0, "confirm": 0} + + pm.sync_vault = lambda *a, **k: calls.__setitem__("sync", calls["sync"] + 1) or { + "manifest_id": "m", + "chunk_ids": [], + "delta_ids": [], + } + + monkeypatch.setattr( + "seedpass.core.manager.NostrClient", lambda *a, **k: SimpleNamespace() + ) + + def fake_confirm(*_a, **_k): + calls["confirm"] += 1 + return True + + monkeypatch.setattr("seedpass.core.manager.confirm_action", fake_confirm) + + pm.initialize_managers() + assert calls["sync"] == 0 + assert calls["confirm"] == 0 + assert enc_mgr.last_migration_performed is False + + +def test_declined_migration_no_sync_prompt(monkeypatch, tmp_path: Path): + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + + key = derive_index_key(TEST_SEED) + data = {"schema_version": 4, "entries": {}} + enc = Fernet(key).encrypt(json.dumps(data).encode()) + legacy_file = tmp_path / "seedpass_passwords_db.json.enc" + legacy_file.write_bytes(enc) + + monkeypatch.setattr("builtins.input", lambda *_a, **_k: "n") + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = enc_mgr + pm.vault = Vault(enc_mgr, tmp_path) + pm.parent_seed = TEST_SEED + pm.fingerprint_dir = tmp_path + pm.current_fingerprint = tmp_path.name + pm.bip85 = SimpleNamespace() + + calls = {"confirm": 0} + + def fake_confirm(*_a, **_k): + calls["confirm"] += 1 + return True + + monkeypatch.setattr("seedpass.core.manager.confirm_action", fake_confirm) + + with pytest.raises(SeedPassError): + pm.initialize_managers() + + assert calls["confirm"] == 0 + + +def test_failed_migration_no_sync_prompt(monkeypatch, tmp_path: Path): + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + + key = derive_index_key(TEST_SEED) + data = {"schema_version": 4, "entries": {}} + enc = Fernet(key).encrypt(json.dumps(data).encode()) + legacy_file = tmp_path / "seedpass_passwords_db.json.enc" + legacy_file.write_bytes(enc) + + monkeypatch.setattr("builtins.input", lambda *_a, **_k: "y") + + def fail(*_a, **_k): + raise ValueError("boom") + + monkeypatch.setattr(enc_mgr, "load_json_data", fail) + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = enc_mgr + pm.vault = Vault(enc_mgr, tmp_path) + pm.parent_seed = TEST_SEED + pm.fingerprint_dir = tmp_path + pm.current_fingerprint = tmp_path.name + pm.bip85 = SimpleNamespace() + + calls = {"confirm": 0} + + def fake_confirm(*_a, **_k): + calls["confirm"] += 1 + return True + + monkeypatch.setattr("seedpass.core.manager.confirm_action", fake_confirm) + + with pytest.raises(SeedPassError): + pm.initialize_managers() + + assert calls["confirm"] == 0 diff --git a/src/tests/test_legacy_migration_iterations.py b/src/tests/test_legacy_migration_iterations.py new file mode 100644 index 00000000..e2007e67 --- /dev/null +++ b/src/tests/test_legacy_migration_iterations.py @@ -0,0 +1,70 @@ +import base64 +import json +from pathlib import Path +import sys + +sys.path.append(str(Path(__file__).resolve().parents[1])) + +import pytest + +import seedpass.core.encryption as enc_module +import seedpass.core.vault as vault_module +from helpers import TEST_PASSWORD +from seedpass.core.encryption import ( + EncryptionManager, + _derive_legacy_key_from_password, +) +from seedpass.core.config_manager import ConfigManager +from seedpass.core.vault import Vault +from seedpass.core.migrations import LATEST_VERSION + + +def _setup_legacy_file(tmp_path: Path, iterations: int) -> None: + legacy_key = _derive_legacy_key_from_password(TEST_PASSWORD, iterations=iterations) + mgr = EncryptionManager(legacy_key, tmp_path) + data = {"schema_version": LATEST_VERSION, "entries": {"0": {"kind": "test"}}} + json_bytes = json.dumps(data, separators=(",", ":")).encode("utf-8") + legacy_encrypted = mgr.fernet.encrypt(json_bytes) + (tmp_path / "seedpass_entries_db.json.enc").write_bytes(legacy_encrypted) + + +@pytest.mark.parametrize("iterations", [50_000, 100_000]) +def test_migrate_iterations(tmp_path, monkeypatch, iterations): + _setup_legacy_file(tmp_path, iterations) + + new_key = base64.urlsafe_b64encode(b"B" * 32) + mgr = EncryptionManager(new_key, tmp_path) + vault = Vault(mgr, tmp_path) + + prompts: list[int] = [] + + def fake_prompt(_msg: str) -> str: + prompts.append(1) + return TEST_PASSWORD + + monkeypatch.setattr(enc_module, "prompt_existing_password", fake_prompt) + monkeypatch.setattr(vault_module, "prompt_existing_password", fake_prompt) + monkeypatch.setattr("builtins.input", lambda *_a, **_k: "2") + + calls: list[int] = [] + orig_derive = enc_module._derive_legacy_key_from_password + + def tracking_derive(password: str, iterations: int = 100_000) -> bytes: + calls.append(iterations) + return orig_derive(password, iterations=iterations) + + monkeypatch.setattr(enc_module, "_derive_legacy_key_from_password", tracking_derive) + + vault.load_index() + # Loading again should not prompt for password or attempt legacy counts + vault.load_index() + + assert prompts == [1] + expected = [50_000] if iterations == 50_000 else [50_000, 100_000] + assert calls == expected + + cfg = ConfigManager(vault, tmp_path) + assert cfg.get_kdf_iterations() == iterations + + payload = json.loads((tmp_path / "seedpass_entries_db.json.enc").read_text()) + assert base64.b64decode(payload["ct"]).startswith(b"V3|") diff --git a/src/tests/test_legacy_migration_prompt.py b/src/tests/test_legacy_migration_prompt.py new file mode 100644 index 00000000..13b5d439 --- /dev/null +++ b/src/tests/test_legacy_migration_prompt.py @@ -0,0 +1,55 @@ +import base64 +import json +from pathlib import Path + +from seedpass.core.encryption import ( + EncryptionManager, + _derive_legacy_key_from_password, +) +from seedpass.core.vault import Vault +import seedpass.core.vault as vault_module +from seedpass.core.migrations import LATEST_VERSION + + +def _setup_legacy_file(tmp_path: Path, password: str) -> Path: + legacy_key = _derive_legacy_key_from_password(password, iterations=50_000) + legacy_mgr = EncryptionManager(legacy_key, tmp_path) + data = {"schema_version": LATEST_VERSION, "entries": {"0": {"kind": "test"}}} + json_bytes = json.dumps(data, separators=(",", ":")).encode("utf-8") + legacy_encrypted = legacy_mgr.fernet.encrypt(json_bytes) + file_path = tmp_path / "seedpass_entries_db.json.enc" + file_path.write_bytes(legacy_encrypted) + return file_path + + +def test_open_legacy_without_migrating(tmp_path, monkeypatch): + password = "secret" + _setup_legacy_file(tmp_path, password) + new_key = base64.urlsafe_b64encode(b"A" * 32) + mgr = EncryptionManager(new_key, tmp_path) + vault = Vault(mgr, tmp_path) + monkeypatch.setattr( + "seedpass.core.encryption.prompt_existing_password", lambda _: password + ) + monkeypatch.setattr(vault_module, "prompt_existing_password", lambda _: password) + monkeypatch.setattr("builtins.input", lambda _: "1") + vault.load_index() + assert vault.encryption_manager.last_migration_performed is False + assert vault.migrated_from_legacy is False + + +def test_migrate_legacy_sets_flag(tmp_path, monkeypatch): + password = "secret" + _setup_legacy_file(tmp_path, password) + new_key = base64.urlsafe_b64encode(b"B" * 32) + mgr = EncryptionManager(new_key, tmp_path) + vault = Vault(mgr, tmp_path) + monkeypatch.setattr( + "seedpass.core.encryption.prompt_existing_password", lambda _: password + ) + monkeypatch.setattr(vault_module, "prompt_existing_password", lambda _: password) + monkeypatch.setattr("builtins.input", lambda _: "2") + vault.load_index() + payload = json.loads((tmp_path / "seedpass_entries_db.json.enc").read_text()) + assert base64.b64decode(payload["ct"]).startswith(b"V3|") + assert vault.encryption_manager.last_migration_performed is True diff --git a/src/tests/test_legacy_migration_second_session.py b/src/tests/test_legacy_migration_second_session.py new file mode 100644 index 00000000..e20eefea --- /dev/null +++ b/src/tests/test_legacy_migration_second_session.py @@ -0,0 +1,65 @@ +import json +import base64 +import hashlib +from pathlib import Path +from types import SimpleNamespace + +from cryptography.fernet import Fernet + +from helpers import create_vault, TEST_SEED, TEST_PASSWORD +from seedpass.core.manager import PasswordManager, EncryptionMode +from seedpass.core.vault import Vault +from seedpass.core.encryption import EncryptionManager +from utils.key_derivation import derive_index_key +from utils.fingerprint import generate_fingerprint + + +def test_legacy_migration_second_session(monkeypatch, tmp_path: Path) -> None: + fingerprint = generate_fingerprint(TEST_SEED) + fp_dir = tmp_path / fingerprint + fp_dir.mkdir() + vault, _ = create_vault(fp_dir, TEST_SEED, TEST_PASSWORD) + + key = derive_index_key(TEST_SEED) + data = {"schema_version": 4, "entries": {}} + enc = Fernet(key).encrypt(json.dumps(data).encode()) + legacy_file = fp_dir / "seedpass_passwords_db.json.enc" + legacy_file.write_bytes(enc) + (fp_dir / "seedpass_passwords_db_checksum.txt").write_text( + hashlib.sha256(enc).hexdigest() + ) + + monkeypatch.setattr( + "seedpass.core.encryption.prompt_existing_password", lambda *_: TEST_PASSWORD + ) + monkeypatch.setattr("builtins.input", lambda *_a, **_k: "y") + vault.load_index() + new_file = fp_dir / "seedpass_entries_db.json.enc" + payload = json.loads(new_file.read_text()) + assert base64.b64decode(payload["ct"]).startswith(b"V3|") + + new_enc_mgr = EncryptionManager(key, fp_dir) + new_vault = Vault(new_enc_mgr, fp_dir) + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = new_enc_mgr + pm.vault = new_vault + pm.parent_seed = TEST_SEED + pm.fingerprint_dir = fp_dir + pm.current_fingerprint = fp_dir.name + pm.bip85 = SimpleNamespace() + monkeypatch.setattr( + "seedpass.core.manager.NostrClient", lambda *a, **k: SimpleNamespace() + ) + + def fail_prompt(*_a, **_k): # pragma: no cover - ensures no prompts occur + raise AssertionError("Prompt should not be called") + + monkeypatch.setattr("builtins.input", fail_prompt) + monkeypatch.setattr( + "seedpass.core.encryption.prompt_existing_password", fail_prompt + ) + + pm.initialize_managers() + payload = json.loads(new_file.read_text()) + assert base64.b64decode(payload["ct"]).startswith(b"V3|") diff --git a/src/tests/test_list_entries_all_types.py b/src/tests/test_list_entries_all_types.py new file mode 100644 index 00000000..2628869a --- /dev/null +++ b/src/tests/test_list_entries_all_types.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from pathlib import Path +from tempfile import TemporaryDirectory +from types import SimpleNamespace + +from typer.testing import CliRunner + +from seedpass.cli import app as cli_app +from seedpass.cli import entry as entry_cli +from helpers import create_vault, TEST_SEED, TEST_PASSWORD +from seedpass.core.backup import BackupManager +from seedpass.core.config_manager import ConfigManager +from seedpass.core.entry_management import EntryManager +from seedpass.core.manager import PasswordManager, EncryptionMode + + +def _setup_manager(tmp_path: Path) -> tuple[PasswordManager, EntryManager]: + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + backup_mgr = BackupManager(tmp_path, cfg_mgr) + entry_mgr = EntryManager(vault, backup_mgr) + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = enc_mgr + pm.vault = vault + pm.entry_manager = entry_mgr + pm.backup_manager = backup_mgr + pm.parent_seed = TEST_SEED + pm.nostr_client = SimpleNamespace() + pm.fingerprint_dir = tmp_path + pm.secret_mode_enabled = False + return pm, entry_mgr + + +def _create_all_entries(em: EntryManager) -> None: + em.add_entry("pw", 8) + em.add_totp("totp", TEST_SEED) + em.add_ssh_key("ssh", TEST_SEED) + em.add_seed("seed", TEST_SEED, words_num=12) + em.add_nostr_key("nostr", TEST_SEED) + em.add_pgp_key("pgp", TEST_SEED) + em.add_key_value("kv", "k", "v") + em.add_managed_account("acct", TEST_SEED) + + +def test_cli_list_all_types(monkeypatch): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + pm, em = _setup_manager(tmp_path) + _create_all_entries(em) + + def fake_get_entry_service(_ctx): + return SimpleNamespace( + list_entries=lambda sort_by, filter_kinds, include_archived: pm.entry_manager.list_entries( + sort_by=sort_by, + filter_kinds=filter_kinds, + include_archived=include_archived, + ) + ) + + monkeypatch.setattr(entry_cli, "_get_entry_service", fake_get_entry_service) + + runner = CliRunner() + result = runner.invoke(cli_app, ["entry", "list"]) + assert result.exit_code == 0 + out = result.stdout + for label in ["pw", "totp", "ssh", "seed", "nostr", "pgp", "kv", "acct"]: + assert label in out + + +def test_menu_list_all_types(monkeypatch, capsys): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + pm, em = _setup_manager(tmp_path) + _create_all_entries(em) + + inputs = iter(["1", "", ""]) # choose All then exit + monkeypatch.setattr("builtins.input", lambda *_: next(inputs)) + + pm.handle_list_entries() + out = capsys.readouterr().out + for label in ["pw", "totp", "ssh", "seed", "nostr", "pgp", "kv", "acct"]: + assert label in out diff --git a/src/tests/test_list_entries_sort_filter.py b/src/tests/test_list_entries_sort_filter.py index 4361008c..476836fe 100644 --- a/src/tests/test_list_entries_sort_filter.py +++ b/src/tests/test_list_entries_sort_filter.py @@ -57,5 +57,5 @@ def test_filter_by_type(): em = setup_entry_manager(tmp_path) em.add_entry("site", 8, "user") em.add_totp("Example", TEST_SEED) - result = em.list_entries(filter_kind=EntryType.TOTP.value) + result = em.list_entries(filter_kinds=[EntryType.TOTP.value]) assert result == [(1, "Example", None, None, False)] diff --git a/src/tests/test_load_global_config.py b/src/tests/test_load_global_config.py new file mode 100644 index 00000000..1ff93731 --- /dev/null +++ b/src/tests/test_load_global_config.py @@ -0,0 +1,24 @@ +"""Tests for load_global_config failure scenarios.""" + +import logging +from pathlib import Path + +import pytest + +from main import load_global_config + + +def test_load_global_config_invalid_toml(monkeypatch, tmp_path, caplog): + """Invalid TOML should log a warning and return an empty dict.""" + config_dir = tmp_path / ".seedpass" + config_dir.mkdir() + config_file = config_dir / "config.toml" + config_file.write_text("invalid = [") + + monkeypatch.setattr(Path, "home", lambda: tmp_path) + + with caplog.at_level(logging.WARNING): + result = load_global_config() + + assert result == {} + assert "Failed to read" in caplog.text diff --git a/src/tests/test_managed_account_entry.py b/src/tests/test_managed_account_entry.py index abeadac1..52b14498 100644 --- a/src/tests/test_managed_account_entry.py +++ b/src/tests/test_managed_account_entry.py @@ -41,6 +41,9 @@ def test_add_and_get_managed_account_seed(): assert fp assert (tmp_path / "accounts" / fp).exists() + # Appears in listing + assert mgr.list_entries() == [(idx, "acct", None, None, False)] + phrase_a = mgr.get_managed_account_seed(idx, TEST_SEED) phrase_b = mgr.get_managed_account_seed(idx, TEST_SEED) assert phrase_a == phrase_b @@ -51,6 +54,23 @@ def test_add_and_get_managed_account_seed(): assert phrase_a == expected assert generate_fingerprint(phrase_a) == fp + # Archive and ensure it disappears from default listing + mgr.archive_entry(idx) + archived = mgr.retrieve_entry(idx) + assert archived["archived"] is True + assert mgr.list_entries() == [] + assert mgr.list_entries(include_archived=True) == [ + (idx, "acct", None, None, True) + ] + + # Restore and ensure deterministic derivation is unchanged + mgr.restore_entry(idx) + restored = mgr.retrieve_entry(idx) + assert restored["archived"] is False + assert mgr.list_entries() == [(idx, "acct", None, None, False)] + phrase_c = mgr.get_managed_account_seed(idx, TEST_SEED) + assert phrase_c == expected + def test_load_and_exit_managed_account(monkeypatch): with TemporaryDirectory() as tmpdir: diff --git a/src/tests/test_manager_add_password.py b/src/tests/test_manager_add_password.py index 0b09a8aa..52a0c3b0 100644 --- a/src/tests/test_manager_add_password.py +++ b/src/tests/test_manager_add_password.py @@ -5,7 +5,7 @@ from types import SimpleNamespace import pytest -from helpers import create_vault, TEST_SEED, TEST_PASSWORD, dummy_nostr_client +from helpers import create_vault, TEST_SEED, TEST_PASSWORD sys.path.append(str(Path(__file__).resolve().parents[1])) @@ -140,7 +140,7 @@ def test_handle_add_password_secret_mode(monkeypatch, dummy_nostr_client, capsys called = [] monkeypatch.setattr( "seedpass.core.manager.copy_to_clipboard", - lambda text, delay: called.append((text, delay)), + lambda text, delay: (called.append((text, delay)), True)[1], ) pm.handle_add_password() @@ -208,3 +208,131 @@ def test_handle_add_password_quick_mode(monkeypatch, dummy_nostr_client, capsys) } assert f"pw-0-{DEFAULT_PASSWORD_LENGTH}" in out + + +def test_handle_add_password_quick_mode_reprompts_invalid_length( + monkeypatch, dummy_nostr_client, capsys +): + client, _relay = dummy_nostr_client + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + backup_mgr = BackupManager(tmp_path, cfg_mgr) + entry_mgr = EntryManager(vault, backup_mgr) + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = enc_mgr + pm.vault = vault + pm.entry_manager = entry_mgr + pm.backup_manager = backup_mgr + pm.password_generator = FakePasswordGenerator() + pm.parent_seed = TEST_SEED + pm.nostr_client = client + pm.fingerprint_dir = tmp_path + pm.secret_mode_enabled = False + pm.is_dirty = False + + inputs = iter( + [ + "q", + "Example", + "", + "", + "3", + "abc", + "12", + "", + ] + ) + monkeypatch.setattr("builtins.input", lambda *a, **k: next(inputs)) + monkeypatch.setattr("seedpass.core.manager.pause", lambda *a, **k: None) + monkeypatch.setattr(pm, "start_background_vault_sync", lambda *a, **k: None) + + pm.handle_add_password() + out = capsys.readouterr().out + + assert "Error: Password length must be between" in out + assert "Error: Password length must be a number." in out + entries = entry_mgr.list_entries(verbose=False) + assert entries == [(0, "Example", "", "", False)] + entry = entry_mgr.retrieve_entry(0) + assert entry["length"] == 12 + + +def test_handle_add_password_reprompts_invalid_mode( + monkeypatch, dummy_nostr_client, capsys +): + client, _relay = dummy_nostr_client + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + backup_mgr = BackupManager(tmp_path, cfg_mgr) + entry_mgr = EntryManager(vault, backup_mgr) + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = enc_mgr + pm.vault = vault + pm.entry_manager = entry_mgr + pm.backup_manager = backup_mgr + pm.password_generator = FakePasswordGenerator() + pm.parent_seed = TEST_SEED + pm.nostr_client = client + pm.fingerprint_dir = tmp_path + pm.secret_mode_enabled = False + pm.is_dirty = False + + inputs = iter( + [ + "z", # invalid mode + "q", # then quick mode + "Example", + "", + "", + "", + "", + ] + ) + monkeypatch.setattr("builtins.input", lambda *a, **k: next(inputs)) + monkeypatch.setattr("seedpass.core.manager.pause", lambda *a, **k: None) + monkeypatch.setattr(pm, "start_background_vault_sync", lambda *a, **k: None) + + pm.handle_add_password() + out = capsys.readouterr().out + + assert "Invalid mode. Enter 'q' for quick or 'a' for advanced." in out + entries = entry_mgr.list_entries(verbose=False) + assert entries == [(0, "Example", "", "", False)] + + +def test_handle_add_password_empty_mode_cancels(monkeypatch, dummy_nostr_client): + client, _relay = dummy_nostr_client + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + backup_mgr = BackupManager(tmp_path, cfg_mgr) + entry_mgr = EntryManager(vault, backup_mgr) + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = enc_mgr + pm.vault = vault + pm.entry_manager = entry_mgr + pm.backup_manager = backup_mgr + pm.password_generator = FakePasswordGenerator() + pm.parent_seed = TEST_SEED + pm.nostr_client = client + pm.fingerprint_dir = tmp_path + pm.secret_mode_enabled = False + pm.is_dirty = False + + inputs = iter([""]) + monkeypatch.setattr("builtins.input", lambda *a, **k: next(inputs)) + monkeypatch.setattr(pm, "start_background_vault_sync", lambda *a, **k: None) + + pm.handle_add_password() + assert entry_mgr.list_entries(verbose=False) == [] diff --git a/src/tests/test_manager_add_totp.py b/src/tests/test_manager_add_totp.py index 27ed5501..5fe2ccee 100644 --- a/src/tests/test_manager_add_totp.py +++ b/src/tests/test_manager_add_totp.py @@ -60,15 +60,11 @@ def test_handle_add_totp(monkeypatch, capsys): out = capsys.readouterr().out entry = entry_mgr.retrieve_entry(0) - assert entry == { - "type": "totp", - "kind": "totp", - "label": "Example", - "index": 0, - "period": 30, - "digits": 6, - "archived": False, - "notes": "", - "tags": [], - } + assert entry["type"] == "totp" + assert entry["kind"] == "totp" + assert entry["label"] == "Example" + assert entry["deterministic"] is False + assert "index" not in entry + assert "secret" in entry + assert len(entry["secret"]) >= 16 assert "ID 0" in out diff --git a/src/tests/test_manager_display_totp_codes.py b/src/tests/test_manager_display_totp_codes.py index 783e9859..9e62e3d5 100644 --- a/src/tests/test_manager_display_totp_codes.py +++ b/src/tests/test_manager_display_totp_codes.py @@ -1,16 +1,10 @@ import sys from pathlib import Path -from tempfile import TemporaryDirectory -from helpers import create_vault, TEST_SEED, TEST_PASSWORD +from helpers import TEST_SEED sys.path.append(str(Path(__file__).resolve().parents[1])) -from seedpass.core.entry_management import EntryManager -from seedpass.core.backup import BackupManager -from seedpass.core.manager import PasswordManager, EncryptionMode -from seedpass.core.config_manager import ConfigManager - class FakeNostrClient: def __init__(self, *args, **kwargs): @@ -21,81 +15,51 @@ class FakeNostrClient: return None, "abcd" -def test_handle_display_totp_codes(monkeypatch, capsys): - with TemporaryDirectory() as tmpdir: - tmp_path = Path(tmpdir) - vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) - cfg_mgr = ConfigManager(vault, tmp_path) - backup_mgr = BackupManager(tmp_path, cfg_mgr) - entry_mgr = EntryManager(vault, backup_mgr) +def test_handle_display_totp_codes(monkeypatch, capsys, password_manager): + pm = password_manager + pm.nostr_client = FakeNostrClient() - pm = PasswordManager.__new__(PasswordManager) - pm.encryption_mode = EncryptionMode.SEED_ONLY - pm.encryption_manager = enc_mgr - pm.vault = vault - pm.entry_manager = entry_mgr - pm.backup_manager = backup_mgr - pm.parent_seed = TEST_SEED - pm.nostr_client = FakeNostrClient() - pm.fingerprint_dir = tmp_path - pm.is_dirty = False - pm.secret_mode_enabled = False + pm.entry_manager.add_totp("Example", TEST_SEED) - entry_mgr.add_totp("Example", TEST_SEED) + monkeypatch.setattr( + "seedpass.core.totp.TotpManager.current_code_from_secret", + lambda *a, **k: "123456", + ) + monkeypatch.setattr(pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 30) - monkeypatch.setattr(pm.entry_manager, "get_totp_code", lambda *a, **k: "123456") - monkeypatch.setattr( - pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 30 - ) + # interrupt the loop after first iteration + monkeypatch.setattr( + "seedpass.core.manager.timed_input", + lambda *a, **k: (_ for _ in ()).throw(KeyboardInterrupt()), + ) - # interrupt the loop after first iteration - monkeypatch.setattr( - "seedpass.core.manager.timed_input", - lambda *a, **k: (_ for _ in ()).throw(KeyboardInterrupt()), - ) - - pm.handle_display_totp_codes() - out = capsys.readouterr().out - assert "Generated 2FA Codes" in out - assert "[0] Example" in out - assert "123456" in out + pm.handle_display_totp_codes() + out = capsys.readouterr().out + assert "Imported 2FA Codes" in out + assert "[0] Example" in out + assert "123456" in out -def test_display_totp_codes_excludes_archived(monkeypatch, capsys): - with TemporaryDirectory() as tmpdir: - tmp_path = Path(tmpdir) - vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) - cfg_mgr = ConfigManager(vault, tmp_path) - backup_mgr = BackupManager(tmp_path, cfg_mgr) - entry_mgr = EntryManager(vault, backup_mgr) +def test_display_totp_codes_excludes_archived(monkeypatch, capsys, password_manager): + pm = password_manager + pm.nostr_client = FakeNostrClient() - pm = PasswordManager.__new__(PasswordManager) - pm.encryption_mode = EncryptionMode.SEED_ONLY - pm.encryption_manager = enc_mgr - pm.vault = vault - pm.entry_manager = entry_mgr - pm.backup_manager = backup_mgr - pm.parent_seed = TEST_SEED - pm.nostr_client = FakeNostrClient() - pm.fingerprint_dir = tmp_path - pm.is_dirty = False - pm.secret_mode_enabled = False + pm.entry_manager.add_totp("Visible", TEST_SEED) + pm.entry_manager.add_totp("Hidden", TEST_SEED) + pm.entry_manager.modify_entry(1, archived=True) - entry_mgr.add_totp("Visible", TEST_SEED) - entry_mgr.add_totp("Hidden", TEST_SEED) - entry_mgr.modify_entry(1, archived=True) + monkeypatch.setattr( + "seedpass.core.totp.TotpManager.current_code_from_secret", + lambda *a, **k: "123456", + ) + monkeypatch.setattr(pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 30) - monkeypatch.setattr(pm.entry_manager, "get_totp_code", lambda *a, **k: "123456") - monkeypatch.setattr( - pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 30 - ) + monkeypatch.setattr( + "seedpass.core.manager.timed_input", + lambda *a, **k: (_ for _ in ()).throw(KeyboardInterrupt()), + ) - monkeypatch.setattr( - "seedpass.core.manager.timed_input", - lambda *a, **k: (_ for _ in ()).throw(KeyboardInterrupt()), - ) - - pm.handle_display_totp_codes() - out = capsys.readouterr().out - assert "Visible" in out - assert "Hidden" not in out + pm.handle_display_totp_codes() + out = capsys.readouterr().out + assert "Visible" in out + assert "Hidden" not in out diff --git a/src/tests/test_manager_list_entries.py b/src/tests/test_manager_list_entries.py index b687c240..816ec66b 100644 --- a/src/tests/test_manager_list_entries.py +++ b/src/tests/test_manager_list_entries.py @@ -301,7 +301,7 @@ def test_show_entry_details_sensitive(monkeypatch, capsys, entry_type): "seedpass.core.manager.confirm_action", lambda *a, **k: True ) monkeypatch.setattr( - "seedpass.core.manager.copy_to_clipboard", lambda *a, **k: None + "seedpass.core.manager.copy_to_clipboard", lambda *a, **k: True ) monkeypatch.setattr("seedpass.core.manager.timed_input", lambda *a, **k: "b") monkeypatch.setattr("seedpass.core.manager.time.sleep", lambda *a, **k: None) @@ -346,7 +346,8 @@ def test_show_entry_details_sensitive(monkeypatch, capsys, entry_type): entry_mgr.add_totp("Example", TEST_SEED) idx = 0 monkeypatch.setattr( - pm.entry_manager, "get_totp_code", lambda *a, **k: "123456" + "seedpass.core.manager.TotpManager.current_code_from_secret", + lambda *a, **k: "123456", ) monkeypatch.setattr( pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 1 @@ -383,7 +384,8 @@ def test_show_entry_details_with_enum_type(monkeypatch, capsys, entry_type): entry_mgr.add_totp("Example", TEST_SEED) idx = 0 monkeypatch.setattr( - pm.entry_manager, "get_totp_code", lambda *a, **k: "123456" + "seedpass.core.manager.TotpManager.current_code_from_secret", + lambda *a, **k: "123456", ) monkeypatch.setattr( pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 1 diff --git a/src/tests/test_manager_retrieve_totp.py b/src/tests/test_manager_retrieve_totp.py index 8d01c28d..003084ec 100644 --- a/src/tests/test_manager_retrieve_totp.py +++ b/src/tests/test_manager_retrieve_totp.py @@ -45,7 +45,10 @@ def test_handle_retrieve_totp_entry(monkeypatch, capsys): inputs = iter(["0", "n", ""]) monkeypatch.setattr("builtins.input", lambda *a, **k: next(inputs)) - monkeypatch.setattr(pm.entry_manager, "get_totp_code", lambda *a, **k: "123456") + monkeypatch.setattr( + "seedpass.core.manager.TotpManager.current_code_from_secret", + lambda *a, **k: "123456", + ) monkeypatch.setattr( pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 1 ) diff --git a/src/tests/test_manifest_id_privacy.py b/src/tests/test_manifest_id_privacy.py new file mode 100644 index 00000000..35a0ba56 --- /dev/null +++ b/src/tests/test_manifest_id_privacy.py @@ -0,0 +1,16 @@ +import asyncio + + +def test_published_events_no_fingerprint(dummy_nostr_client): + client, relay = dummy_nostr_client + asyncio.run(client.publish_snapshot(b"secret")) + fingerprint = "fp" + events = list(relay.manifests) + list(relay.chunks.values()) + seen = set() + for ev in events: + if id(ev) in seen: + continue + seen.add(id(ev)) + assert fingerprint not in ev.id + for tag in getattr(ev, "tags", []): + assert fingerprint not in tag diff --git a/src/tests/test_manifest_state_restore.py b/src/tests/test_manifest_state_restore.py index c28fad78..5abb75d2 100644 --- a/src/tests/test_manifest_state_restore.py +++ b/src/tests/test_manifest_state_restore.py @@ -2,7 +2,7 @@ import asyncio from pathlib import Path from tempfile import TemporaryDirectory -from helpers import create_vault, dummy_nostr_client, TEST_SEED +from helpers import create_vault, TEST_SEED from seedpass.core.entry_management import EntryManager from seedpass.core.backup import BackupManager @@ -34,8 +34,8 @@ def _init_pm(dir_path: Path, client) -> PasswordManager: return pm -def test_manifest_state_restored(monkeypatch, tmp_path): - client, relay = dummy_nostr_client.__wrapped__(tmp_path / "c1", monkeypatch) +def test_manifest_state_restored(monkeypatch, tmp_path, make_dummy_nostr_client): + client, relay = make_dummy_nostr_client(tmp_path / "c1") with TemporaryDirectory() as tmpdir: fp_dir = Path(tmpdir) pm1 = _init_pm(fp_dir, client) @@ -48,7 +48,7 @@ def test_manifest_state_restored(monkeypatch, tmp_path): assert delta_ts > 0 assert result["manifest_id"] == manifest_id - client2, _ = dummy_nostr_client.__wrapped__(tmp_path / "c2", monkeypatch) + client2, _ = make_dummy_nostr_client(tmp_path / "c2") monkeypatch.setattr( "seedpass.core.manager.NostrClient", lambda *a, **k: client2 ) diff --git a/src/tests/test_migrations.py b/src/tests/test_migrations.py index 7f361ad9..dded9ed6 100644 --- a/src/tests/test_migrations.py +++ b/src/tests/test_migrations.py @@ -78,3 +78,29 @@ def test_error_on_future_version(tmp_path: Path): enc_mgr.save_json_data(future) with pytest.raises(ValueError): vault.load_index() + + +def test_schema_migration_persisted_once(tmp_path: Path): + enc_mgr, vault = setup(tmp_path) + legacy = { + "schema_version": 3, + "entries": { + "0": { + "label": "a", + "length": 8, + "type": "password", + "notes": "", + "custom_fields": [], + "origin": "", + } + }, + } + enc_mgr.save_json_data(legacy) + data, migrated, _ = vault.load_index(return_migration_flags=True) + assert migrated is True + assert data["schema_version"] == LATEST_VERSION + assert data["entries"]["0"]["tags"] == [] + + data_again, migrated_again, _ = vault.load_index(return_migration_flags=True) + assert migrated_again is False + assert data_again == data diff --git a/src/tests/test_multiple_deltas_sync.py b/src/tests/test_multiple_deltas_sync.py index 3b2b2f71..296f6421 100644 --- a/src/tests/test_multiple_deltas_sync.py +++ b/src/tests/test_multiple_deltas_sync.py @@ -2,7 +2,7 @@ import asyncio from pathlib import Path from tempfile import TemporaryDirectory -from helpers import create_vault, dummy_nostr_client +from helpers import create_vault from seedpass.core.entry_management import EntryManager from seedpass.core.backup import BackupManager diff --git a/src/tests/test_new_seed_profile_creation.py b/src/tests/test_new_seed_profile_creation.py new file mode 100644 index 00000000..3812c2c2 --- /dev/null +++ b/src/tests/test_new_seed_profile_creation.py @@ -0,0 +1,55 @@ +import pytest +from pathlib import Path +from tempfile import TemporaryDirectory + +from seedpass.core.manager import PasswordManager +from utils.fingerprint_manager import FingerprintManager +from utils.fingerprint import generate_fingerprint +from seedpass.core.state_manager import StateManager + +VALID_SEED = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" + + +def setup_pm(tmp_path, monkeypatch): + pm = PasswordManager.__new__(PasswordManager) + pm.fingerprint_manager = FingerprintManager(tmp_path) + pm.config_manager = type("Cfg", (), {"get_kdf_iterations": lambda self: 1})() + pm.state_manager = StateManager(tmp_path) + monkeypatch.setattr("seedpass.core.manager.prompt_for_password", lambda: "pw") + monkeypatch.setattr("seedpass.core.manager.derive_index_key", lambda seed: b"idx") + monkeypatch.setattr( + "seedpass.core.manager.derive_key_from_password", lambda *a, **k: b"k" + ) + + class DummyEnc: + def __init__(self, *a, **k): + pass + + def encrypt_parent_seed(self, seed): + pass + + monkeypatch.setattr("seedpass.core.manager.EncryptionManager", DummyEnc) + monkeypatch.setattr("seedpass.core.manager.Vault", lambda *a, **k: object()) + monkeypatch.setattr( + "seedpass.core.manager.ConfigManager", lambda **k: pm.config_manager + ) + monkeypatch.setattr(pm, "initialize_bip85", lambda: None) + monkeypatch.setattr(pm, "initialize_managers", lambda: None) + monkeypatch.setattr(pm, "start_background_sync", lambda: None) + monkeypatch.setattr(pm, "store_hashed_password", lambda pw: None) + return pm + + +def test_generate_new_seed_creates_profile(monkeypatch): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + pm = setup_pm(tmp_path, monkeypatch) + monkeypatch.setattr(pm, "generate_bip85_seed", lambda: VALID_SEED) + monkeypatch.setattr("seedpass.core.manager.confirm_action", lambda *_: True) + + fingerprint = pm.generate_new_seed() + + assert fingerprint == generate_fingerprint(VALID_SEED) + assert pm.fingerprint_manager.list_fingerprints() == [fingerprint] + sm = StateManager(tmp_path / fingerprint) + assert sm.state["nostr_account_idx"] == 1 diff --git a/src/tests/test_nonce_uniqueness.py b/src/tests/test_nonce_uniqueness.py new file mode 100644 index 00000000..a1f84610 --- /dev/null +++ b/src/tests/test_nonce_uniqueness.py @@ -0,0 +1,19 @@ +from pathlib import Path + +from helpers import TEST_SEED +from utils.key_derivation import derive_index_key +from seedpass.core.encryption import EncryptionManager + + +def test_nonce_uniqueness(tmp_path: Path) -> None: + key = derive_index_key(TEST_SEED) + manager = EncryptionManager(key, tmp_path) + plaintext = b"repeat" + nonces = set() + for _ in range(10): + payload = manager.encrypt_data(plaintext) + assert payload.startswith(b"V3|") + nonce = payload[3:15] + assert nonce not in nonces + nonces.add(nonce) + assert len(nonces) == 10 diff --git a/src/tests/test_noninteractive_init_unlock.py b/src/tests/test_noninteractive_init_unlock.py index b6969056..5b16d8dd 100644 --- a/src/tests/test_noninteractive_init_unlock.py +++ b/src/tests/test_noninteractive_init_unlock.py @@ -7,7 +7,7 @@ import constants import seedpass.core.manager as manager_module from utils.fingerprint_manager import FingerprintManager from seedpass.core.config_manager import ConfigManager -from tests.helpers import TEST_SEED, TEST_PASSWORD, create_vault +from helpers import TEST_SEED, TEST_PASSWORD, create_vault def test_init_with_password(monkeypatch): diff --git a/src/tests/test_nostr_client.py b/src/tests/test_nostr_client.py index 0fc5a611..61bb457f 100644 --- a/src/tests/test_nostr_client.py +++ b/src/tests/test_nostr_client.py @@ -90,7 +90,7 @@ def _setup_client(tmpdir, fake_cls): def test_initialize_client_pool_add_relays_used(tmp_path): client = _setup_client(tmp_path, FakeAddRelaysClient) fc = client.client - client.connect() + asyncio.run(client.connect()) assert [[str(r) for r in relays] for relays in fc.added] == [client.relays] assert fc.connected is True @@ -98,7 +98,7 @@ def test_initialize_client_pool_add_relays_used(tmp_path): def test_initialize_client_pool_add_relay_fallback(tmp_path): client = _setup_client(tmp_path, FakeAddRelayClient) fc = client.client - client.connect() + asyncio.run(client.connect()) assert [str(r) for r in fc.added] == client.relays assert fc.connected is True @@ -166,17 +166,42 @@ def test_retrieve_json_sync_backoff(tmp_path, monkeypatch): sleeps: list[float] = [] - def fake_sleep(d): + async def fake_sleep(d, *_a, **_k): sleeps.append(d) - monkeypatch.setattr(nostr_client.time, "sleep", fake_sleep) + monkeypatch.setattr(asyncio, "sleep", fake_sleep) async def fake_async(self): return None monkeypatch.setattr(NostrClient, "_retrieve_json_from_nostr", fake_async) - result = client.retrieve_json_from_nostr_sync() + result = asyncio.run(client.retrieve_json_from_nostr()) assert result is None assert sleeps == [1, 2] + + +def test_client_methods_run_in_event_loop(tmp_path, monkeypatch): + client = _setup_client(tmp_path, FakeAddRelayClient) + + async def fake_init(self): + self._connected = True + + async def fake_send_event(_event): + return None + + async def fake_retrieve(self): + return b"data" + + monkeypatch.setattr(NostrClient, "_initialize_client_pool", fake_init) + monkeypatch.setattr(client.client, "send_event", fake_send_event, raising=False) + monkeypatch.setattr(NostrClient, "_retrieve_json_from_nostr", fake_retrieve) + + async def run_all(): + await client.connect() + await client.publish_event("e") + data = await client.retrieve_json_from_nostr() + assert data == b"data" + + asyncio.run(run_all()) diff --git a/src/tests/test_nostr_dummy_client.py b/src/tests/test_nostr_dummy_client.py index 763e5b0d..5087794f 100644 --- a/src/tests/test_nostr_dummy_client.py +++ b/src/tests/test_nostr_dummy_client.py @@ -3,7 +3,7 @@ import gzip import math import pytest -from helpers import create_vault, dummy_nostr_client, TEST_SEED +from helpers import create_vault, TEST_SEED from seedpass.core.entry_management import EntryManager from seedpass.core.backup import BackupManager from seedpass.core.config_manager import ConfigManager diff --git a/src/tests/test_nostr_legacy_decrypt_fallback.py b/src/tests/test_nostr_legacy_decrypt_fallback.py new file mode 100644 index 00000000..c130230f --- /dev/null +++ b/src/tests/test_nostr_legacy_decrypt_fallback.py @@ -0,0 +1,38 @@ +import json +import base64 +import hashlib +import unicodedata +import logging +from cryptography.fernet import Fernet + +from helpers import create_vault, TEST_PASSWORD +import seedpass.core.encryption as enc_module + + +def test_legacy_password_only_fallback(monkeypatch, tmp_path, caplog): + calls: list[int] = [] + + def _fast_legacy_key(password: str, iterations: int = 100_000) -> bytes: + calls.append(iterations) + normalized = unicodedata.normalize("NFKD", password).strip().encode("utf-8") + key = hashlib.pbkdf2_hmac("sha256", normalized, b"", 1, dklen=32) + return base64.urlsafe_b64encode(key) + + # Speed up legacy key derivation + monkeypatch.setattr( + enc_module, "_derive_legacy_key_from_password", _fast_legacy_key + ) + monkeypatch.setattr( + enc_module, "prompt_existing_password", lambda *_a, **_k: TEST_PASSWORD + ) + + vault, enc_mgr = create_vault(tmp_path) + data = {"schema_version": 4, "entries": {}} + legacy_key = _fast_legacy_key(TEST_PASSWORD, iterations=50_000) + encrypted = Fernet(legacy_key).encrypt(json.dumps(data).encode()) + + caplog.set_level(logging.WARNING) + assert enc_mgr.decrypt_and_save_index_from_nostr(encrypted) + assert vault.load_index() == data + assert any("legacy password-only" in rec.message for rec in caplog.records) + assert calls == [50_000, 50_000] diff --git a/src/tests/test_nostr_legacy_key_fallback.py b/src/tests/test_nostr_legacy_key_fallback.py new file mode 100644 index 00000000..07f42558 --- /dev/null +++ b/src/tests/test_nostr_legacy_key_fallback.py @@ -0,0 +1,83 @@ +import asyncio +import base64 +import hashlib +import json + +from helpers import DummyEvent, DummyFilter +from nostr.backup_models import KIND_MANIFEST, KIND_SNAPSHOT_CHUNK +from nostr_sdk import Keys + + +def test_fetch_snapshot_legacy_key_fallback(dummy_nostr_client, monkeypatch): + client, relay = dummy_nostr_client + + # Track legacy key generation + called = {"legacy": False} + + class LegacyKeys: + def private_key_hex(self): + return "3" * 64 + + def public_key_hex(self): + return "4" * 64 + + def fake_generate(): + called["legacy"] = True + return LegacyKeys() + + monkeypatch.setattr( + client.key_manager, "generate_legacy_nostr_keys", fake_generate, raising=False + ) + + expected_pubkey = Keys.parse("3" * 64).public_key() + + class RecordingFilter(DummyFilter): + def author(self, pk): + self.author_pk = pk + return self + + monkeypatch.setattr("nostr.client.Filter", RecordingFilter) + + chunk_bytes = b"chunkdata" + chunk_hash = hashlib.sha256(chunk_bytes).hexdigest() + manifest_json = json.dumps( + { + "ver": 1, + "algo": "gzip", + "chunks": [ + { + "id": "seedpass-chunk-0000", + "size": len(chunk_bytes), + "hash": chunk_hash, + "event_id": None, + } + ], + } + ) + manifest_event = DummyEvent(KIND_MANIFEST, manifest_json, tags=["legacy"]) + chunk_event = DummyEvent( + KIND_SNAPSHOT_CHUNK, + base64.b64encode(chunk_bytes).decode("utf-8"), + tags=["seedpass-chunk-0000"], + ) + + call = {"count": 0, "authors": []} + + async def fake_fetch_events(f, _timeout): + call["count"] += 1 + call["authors"].append(getattr(f, "author_pk", None)) + if call["count"] == 1: + return type("R", (), {"to_vec": lambda self: []})() + elif call["count"] == 2: + return type("R", (), {"to_vec": lambda self: [manifest_event]})() + else: + return type("R", (), {"to_vec": lambda self: [chunk_event]})() + + monkeypatch.setattr(relay, "fetch_events", fake_fetch_events) + + result = asyncio.run(client.fetch_latest_snapshot()) + assert called["legacy"] + assert result is not None + manifest, chunks = result + assert b"".join(chunks) == chunk_bytes + assert call["authors"][-1].to_hex() == expected_pubkey.to_hex() diff --git a/src/tests/test_nostr_restore_flow.py b/src/tests/test_nostr_restore_flow.py index 759f6f86..1c5c1f86 100644 --- a/src/tests/test_nostr_restore_flow.py +++ b/src/tests/test_nostr_restore_flow.py @@ -1,7 +1,7 @@ from pathlib import Path import main -from helpers import create_vault, dummy_nostr_client, TEST_SEED, TEST_PASSWORD +from helpers import create_vault, TEST_SEED, TEST_PASSWORD from seedpass.core.entry_management import EntryManager from seedpass.core.backup import BackupManager from seedpass.core.config_manager import ConfigManager @@ -28,8 +28,8 @@ def _init_pm(dir_path: Path, client) -> PasswordManager: return pm -def test_restore_flow_from_snapshot(monkeypatch, tmp_path): - client, relay = dummy_nostr_client.__wrapped__(tmp_path / "srv", monkeypatch) +def test_restore_flow_from_snapshot(monkeypatch, tmp_path, make_dummy_nostr_client): + client, relay = make_dummy_nostr_client(tmp_path / "srv") dir_a = tmp_path / "A" dir_b = tmp_path / "B" diff --git a/src/tests/test_nostr_sdk_workflow.py b/src/tests/test_nostr_sdk_workflow.py index e601a147..c04b6b54 100644 --- a/src/tests/test_nostr_sdk_workflow.py +++ b/src/tests/test_nostr_sdk_workflow.py @@ -4,7 +4,6 @@ import threading import time from websocket import create_connection -import asyncio import websockets from nostr.key_manager import KeyManager from nostr_sdk import nostr_sdk as sdk diff --git a/src/tests/test_offline_mode_default_enabled.py b/src/tests/test_offline_mode_default_enabled.py new file mode 100644 index 00000000..a3a667ea --- /dev/null +++ b/src/tests/test_offline_mode_default_enabled.py @@ -0,0 +1,14 @@ +from pathlib import Path +from tempfile import TemporaryDirectory + +from seedpass.core.config_manager import ConfigManager +from helpers import create_vault, TEST_SEED, TEST_PASSWORD + + +def test_offline_mode_default_enabled(): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + config = cfg_mgr.load_config(require_pin=False) + assert config["offline_mode"] is True diff --git a/src/tests/test_offline_mode_profile_creation.py b/src/tests/test_offline_mode_profile_creation.py new file mode 100644 index 00000000..74436c6a --- /dev/null +++ b/src/tests/test_offline_mode_profile_creation.py @@ -0,0 +1,32 @@ +from pathlib import Path +from tempfile import TemporaryDirectory + +import pytest + +from main import handle_toggle_offline_mode +from seedpass.core.manager import PasswordManager +from helpers import create_vault, TEST_SEED, TEST_PASSWORD +from utils.fingerprint import generate_fingerprint + + +def test_toggle_offline_mode_after_profile_creation(monkeypatch): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + monkeypatch.setattr(Path, "home", lambda: tmp_path) + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + pm = PasswordManager.__new__(PasswordManager) + pm.vault = vault + pm.encryption_manager = enc_mgr + pm.fingerprint_dir = tmp_path + pm.current_fingerprint = generate_fingerprint(TEST_SEED) + pm.offline_mode = False + pm.config_manager = None + + inputs = iter(["y"]) + monkeypatch.setattr("builtins.input", lambda *a: next(inputs)) + handle_toggle_offline_mode(pm) + + assert pm.offline_mode is True + assert pm.config_manager is not None + cfg = pm.config_manager.load_config(require_pin=False) + assert cfg["offline_mode"] is True diff --git a/src/tests/test_password_change.py b/src/tests/test_password_change.py index efe001df..cf149aaf 100644 --- a/src/tests/test_password_change.py +++ b/src/tests/test_password_change.py @@ -35,6 +35,7 @@ def test_change_password_triggers_nostr_backup(monkeypatch): pm.parent_seed = TEST_SEED pm.store_hashed_password = lambda pw: None pm.verify_password = lambda pw: True + pm.nostr_account_idx = 0 with patch("seedpass.core.manager.NostrClient") as MockClient: mock_instance = MockClient.return_value diff --git a/src/tests/test_password_generation_policy.py b/src/tests/test_password_generation_policy.py index 0a90101c..62a20953 100644 --- a/src/tests/test_password_generation_policy.py +++ b/src/tests/test_password_generation_policy.py @@ -13,8 +13,8 @@ class DummyEnc: class DummyBIP85: - def derive_entropy(self, index: int, bytes_len: int, app_no: int = 32) -> bytes: - return bytes((index + i) % 256 for i in range(bytes_len)) + def derive_entropy(self, index: int, entropy_bytes: int, app_no: int = 32) -> bytes: + return bytes((index + i) % 256 for i in range(entropy_bytes)) def make_generator(policy=None): diff --git a/src/tests/test_password_helpers.py b/src/tests/test_password_helpers.py index b41f1869..fb80683f 100644 --- a/src/tests/test_password_helpers.py +++ b/src/tests/test_password_helpers.py @@ -8,8 +8,8 @@ class DummyEnc: class DummyBIP85: - def derive_entropy(self, index: int, bytes_len: int, app_no: int = 32) -> bytes: - return bytes((index + i) % 256 for i in range(bytes_len)) + def derive_entropy(self, index: int, entropy_bytes: int, app_no: int = 32) -> bytes: + return bytes((index + i) % 256 for i in range(entropy_bytes)) def make_generator(): diff --git a/src/tests/test_password_length_constraints.py b/src/tests/test_password_length_constraints.py index a800f9f4..a6490eea 100644 --- a/src/tests/test_password_length_constraints.py +++ b/src/tests/test_password_length_constraints.py @@ -14,8 +14,8 @@ class DummyEnc: class DummyBIP85: - def derive_entropy(self, index: int, bytes_len: int, app_no: int = 32) -> bytes: - return bytes((index + i) % 256 for i in range(bytes_len)) + def derive_entropy(self, index: int, entropy_bytes: int, app_no: int = 32) -> bytes: + return bytes((index + i) % 256 for i in range(entropy_bytes)) def make_generator(): diff --git a/src/tests/test_password_properties.py b/src/tests/test_password_properties.py index 0c5f2bab..ca0e7485 100644 --- a/src/tests/test_password_properties.py +++ b/src/tests/test_password_properties.py @@ -15,8 +15,8 @@ class DummyEnc: class DummyBIP85: - def derive_entropy(self, index: int, bytes_len: int, app_no: int = 32) -> bytes: - return bytes((index + i) % 256 for i in range(bytes_len)) + def derive_entropy(self, index: int, entropy_bytes: int, app_no: int = 32) -> bytes: + return bytes((index + i) % 256 for i in range(entropy_bytes)) def make_generator(): diff --git a/src/tests/test_password_shuffle_consistency.py b/src/tests/test_password_shuffle_consistency.py new file mode 100644 index 00000000..8436d71c --- /dev/null +++ b/src/tests/test_password_shuffle_consistency.py @@ -0,0 +1,32 @@ +import sys +from pathlib import Path + +sys.path.append(str(Path(__file__).resolve().parents[1])) + +from seedpass.core.password_generation import PasswordGenerator, PasswordPolicy + + +class DummyEnc: + def derive_seed_from_mnemonic(self, mnemonic): + return b"\x00" * 32 + + +class DummyBIP85: + def derive_entropy(self, index: int, entropy_bytes: int, app_no: int = 32) -> bytes: + return bytes((index + i) % 256 for i in range(entropy_bytes)) + + +def make_generator(): + pg = PasswordGenerator.__new__(PasswordGenerator) + pg.encryption_manager = DummyEnc() + pg.bip85 = DummyBIP85() + pg.policy = PasswordPolicy() + return pg + + +def test_password_generation_consistent_output(): + pg = make_generator() + expected = "0j6R3e-%4xN@N{Jb" + assert pg.generate_password(length=16, index=1) == expected + # Generating again should produce the same password + assert pg.generate_password(length=16, index=1) == expected diff --git a/src/tests/test_password_special_chars.py b/src/tests/test_password_special_chars.py index 38d66399..83ec587e 100644 --- a/src/tests/test_password_special_chars.py +++ b/src/tests/test_password_special_chars.py @@ -15,8 +15,8 @@ class DummyEnc: class DummyBIP85: - def derive_entropy(self, index: int, bytes_len: int, app_no: int = 32) -> bytes: - return bytes((index + i) % 256 for i in range(bytes_len)) + def derive_entropy(self, index: int, entropy_bytes: int, app_no: int = 32) -> bytes: + return bytes((index + i) % 256 for i in range(entropy_bytes)) def make_generator(policy=None): diff --git a/src/tests/test_password_special_modes.py b/src/tests/test_password_special_modes.py index 50a4019f..f2871c22 100644 --- a/src/tests/test_password_special_modes.py +++ b/src/tests/test_password_special_modes.py @@ -14,8 +14,8 @@ class DummyEnc: class DummyBIP85: - def derive_entropy(self, index: int, bytes_len: int, app_no: int = 32) -> bytes: - return bytes((index + i) % 256 for i in range(bytes_len)) + def derive_entropy(self, index: int, entropy_bytes: int, app_no: int = 32) -> bytes: + return bytes((index + i) % 256 for i in range(entropy_bytes)) def make_generator(policy=None): diff --git a/src/tests/test_password_unlock_after_change.py b/src/tests/test_password_unlock_after_change.py index a0bda0a1..d0756a22 100644 --- a/src/tests/test_password_unlock_after_change.py +++ b/src/tests/test_password_unlock_after_change.py @@ -14,19 +14,22 @@ from seedpass.core.backup import BackupManager from seedpass.core.config_manager import ConfigManager from seedpass.core.manager import PasswordManager, EncryptionMode from utils.key_derivation import derive_index_key, derive_key_from_password +from utils.fingerprint import generate_fingerprint SEED = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" def test_password_change_and_unlock(monkeypatch): with TemporaryDirectory() as tmpdir: - fp = Path(tmpdir) + fp_name = generate_fingerprint(SEED) + fp = Path(tmpdir) / fp_name + fp.mkdir() old_pw = "oldpw" new_pw = "newpw" # initial encryption setup index_key = derive_index_key(SEED) - seed_key = derive_key_from_password(old_pw) + seed_key = derive_key_from_password(old_pw, fp_name) enc_mgr = EncryptionManager(index_key, fp) seed_mgr = EncryptionManager(seed_key, fp) vault = Vault(enc_mgr, fp) @@ -54,11 +57,12 @@ def test_password_change_and_unlock(monkeypatch): pm.vault = vault pm.password_generator = SimpleNamespace(encryption_manager=enc_mgr) pm.fingerprint_dir = fp - pm.current_fingerprint = "fp" + pm.current_fingerprint = fp_name pm.parent_seed = SEED pm.nostr_client = SimpleNamespace( publish_snapshot=lambda *a, **k: (None, "abcd") ) + pm.nostr_account_idx = 0 monkeypatch.setattr( "seedpass.core.manager.prompt_existing_password", lambda *_: old_pw diff --git a/src/tests/test_pgp_entry.py b/src/tests/test_pgp_entry.py index c1fd37f8..9cb7c28a 100644 --- a/src/tests/test_pgp_entry.py +++ b/src/tests/test_pgp_entry.py @@ -39,3 +39,21 @@ def test_pgp_key_determinism(): entry = data["entries"][str(idx)] assert entry["key_type"] == "ed25519" assert entry["user_id"] == "Test" + + +def test_pgp_rsa_key_determinism(): + """RSA PGP keys should be derived deterministically.""" + + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + backup_mgr = BackupManager(tmp_path, cfg_mgr) + entry_mgr = EntryManager(vault, backup_mgr) + + idx = entry_mgr.add_pgp_key("pgp", TEST_SEED, key_type="rsa", user_id="Test") + key1, fp1 = entry_mgr.get_pgp_key(idx, TEST_SEED) + key2, fp2 = entry_mgr.get_pgp_key(idx, TEST_SEED) + + assert fp1 == fp2 + assert key1 == key2 diff --git a/src/tests/test_portable_backup.py b/src/tests/test_portable_backup.py index f42a9eea..699adb57 100644 --- a/src/tests/test_portable_backup.py +++ b/src/tests/test_portable_backup.py @@ -9,19 +9,23 @@ import sys sys.path.append(str(Path(__file__).resolve().parents[1])) +import seedpass.core.encryption as enc_module from seedpass.core.encryption import EncryptionManager from seedpass.core.vault import Vault from seedpass.core.backup import BackupManager from seedpass.core.config_manager import ConfigManager from seedpass.core.portable_backup import export_backup, import_backup +from seedpass.core.portable_backup import PortableMode from utils.key_derivation import derive_index_key, derive_key_from_password +from utils.fingerprint import generate_fingerprint SEED = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" PASSWORD = "passw0rd" def setup_vault(tmp: Path): - seed_key = derive_key_from_password(PASSWORD) + fp = generate_fingerprint(SEED) + seed_key = derive_key_from_password(PASSWORD, fp) seed_mgr = EncryptionManager(seed_key, tmp) seed_mgr.encrypt_parent_seed(SEED) @@ -50,9 +54,26 @@ def test_round_trip(monkeypatch): assert vault.load_index()["pw"] == data["pw"] +def test_round_trip_unencrypted(monkeypatch): + with TemporaryDirectory() as td: + tmp = Path(td) + vault, backup, _ = setup_vault(tmp) + data = {"pw": 1} + vault.save_index(data) + + path = export_backup(vault, backup, parent_seed=SEED, encrypt=False) + wrapper = json.loads(path.read_text()) + assert wrapper["encryption_mode"] == PortableMode.NONE.value + + vault.save_index({"pw": 0}) + import_backup(vault, backup, path, parent_seed=SEED) + assert vault.load_index()["pw"] == data["pw"] + + from cryptography.fernet import InvalidToken +@pytest.mark.skipif(sys.platform.startswith("win"), reason="flaky on Windows") def test_corruption_detection(monkeypatch): with TemporaryDirectory() as td: tmp = Path(td) @@ -67,6 +88,16 @@ def test_corruption_detection(monkeypatch): content["payload"] = base64.b64encode(payload).decode() path.write_text(json.dumps(content)) + def _fast_legacy_key(password: str, iterations: int = 100_000) -> bytes: + return base64.urlsafe_b64encode(b"0" * 32) + + monkeypatch.setattr( + enc_module, "_derive_legacy_key_from_password", _fast_legacy_key + ) + monkeypatch.setattr( + enc_module, "prompt_existing_password", lambda *_a, **_k: PASSWORD + ) + with pytest.raises(InvalidToken): import_backup(vault, backup, path, parent_seed=SEED) @@ -125,7 +156,8 @@ def test_export_creates_additional_backup_and_import(monkeypatch): with TemporaryDirectory() as td, TemporaryDirectory() as extra: tmp = Path(td) - seed_key = derive_key_from_password(PASSWORD) + fp = generate_fingerprint(SEED) + seed_key = derive_key_from_password(PASSWORD, fp) seed_mgr = EncryptionManager(seed_key, tmp) seed_mgr.encrypt_parent_seed(SEED) diff --git a/src/tests/test_profile_cleanup.py b/src/tests/test_profile_cleanup.py index d85653f6..659e7052 100644 --- a/src/tests/test_profile_cleanup.py +++ b/src/tests/test_profile_cleanup.py @@ -20,6 +20,7 @@ def setup_pm(tmp_path): pm.encryption_mode = manager_module.EncryptionMode.SEED_ONLY pm.fingerprint_manager = manager_module.FingerprintManager(constants.APP_DIR) pm.current_fingerprint = None + pm.state_manager = manager_module.StateManager(constants.APP_DIR) return pm, constants, manager_module @@ -41,8 +42,8 @@ def test_generate_seed_cleanup_on_failure(monkeypatch): # fingerprint list should be empty and only fingerprints.json should remain assert pm.fingerprint_manager.list_fingerprints() == [] - contents = list(const.APP_DIR.iterdir()) - assert len(contents) == 1 and contents[0].name == "fingerprints.json" + contents = sorted(p.name for p in const.APP_DIR.iterdir()) + assert contents == ["fingerprints.json", "seedpass_state.json"] fp_file = pm.fingerprint_manager.fingerprints_file with open(fp_file) as f: data = json.load(f) diff --git a/src/tests/test_profile_deletion_sync.py b/src/tests/test_profile_deletion_sync.py new file mode 100644 index 00000000..2bc3f0f2 --- /dev/null +++ b/src/tests/test_profile_deletion_sync.py @@ -0,0 +1,55 @@ +import time +from types import SimpleNamespace + +import pytest +import sys +from pathlib import Path + +sys.path.append(str(Path(__file__).resolve().parents[1])) +import main +from utils.fingerprint_manager import FingerprintManager +from helpers import TEST_SEED + + +def test_profile_deletion_stops_sync(monkeypatch, tmp_path): + fm = FingerprintManager(tmp_path) + fp = fm.add_fingerprint(TEST_SEED) + + calls = {"post": 0, "cleanup": 0} + + def fake_post(_pm): + calls["post"] += 1 + + monkeypatch.setattr(main, "handle_post_to_nostr", fake_post) + monkeypatch.setattr("builtins.input", lambda *_: "1") + monkeypatch.setattr(main, "confirm_action", lambda *_: True) + + pm = SimpleNamespace( + fingerprint_manager=fm, + current_fingerprint=fp, + is_dirty=False, + last_update=time.time(), + last_activity=time.time(), + nostr_client=SimpleNamespace(close_client_pool=lambda: None), + handle_add_password=lambda: None, + handle_retrieve_entry=lambda: None, + handle_modify_entry=lambda: None, + update_activity=lambda: None, + lock_vault=lambda: None, + unlock_vault=lambda: None, + start_background_sync=lambda: None, + start_background_relay_check=lambda: None, + cleanup=lambda: calls.__setitem__("cleanup", calls["cleanup"] + 1), + ) + + main.handle_post_to_nostr(pm) + assert calls["post"] == 1 + + with pytest.raises(SystemExit): + main.handle_remove_fingerprint(pm) + + assert calls["post"] == 1 + assert calls["cleanup"] == 1 + pm.current_fingerprint = fm.current_fingerprint + assert pm.current_fingerprint is None + assert pm.is_dirty is False diff --git a/src/tests/test_profiles.py b/src/tests/test_profiles.py index 8c4bcb28..a7cfb4f2 100644 --- a/src/tests/test_profiles.py +++ b/src/tests/test_profiles.py @@ -6,7 +6,7 @@ sys.path.append(str(Path(__file__).resolve().parents[1])) from utils.fingerprint_manager import FingerprintManager from seedpass.core.manager import PasswordManager, EncryptionMode -from helpers import create_vault, dummy_nostr_client +from helpers import create_vault import gzip from nostr.backup_models import Manifest, ChunkMeta @@ -28,6 +28,7 @@ def test_add_and_switch_fingerprint(monkeypatch): pm.fingerprint_manager = fm pm.encryption_manager = object() pm.current_fingerprint = None + pm.nostr_account_idx = 0 monkeypatch.setattr("builtins.input", lambda *_args, **_kwargs: "1") monkeypatch.setattr( diff --git a/src/tests/test_publish_json_result.py b/src/tests/test_publish_json_result.py index 5172427b..81245060 100644 --- a/src/tests/test_publish_json_result.py +++ b/src/tests/test_publish_json_result.py @@ -82,9 +82,11 @@ def test_publish_snapshot_success(): with patch.object( client.client, "send_event", side_effect=fake_send ) as mock_send: - manifest, event_id = asyncio.run(client.publish_snapshot(b"data")) + with patch("nostr.snapshot.new_manifest_id", return_value=("id", b"nonce")): + manifest, event_id = asyncio.run(client.publish_snapshot(b"data")) assert isinstance(manifest, Manifest) - assert event_id == "seedpass-manifest-fp" + assert event_id == "id" + assert manifest.nonce == base64.b64encode(b"nonce").decode("utf-8") assert mock_send.await_count >= 1 diff --git a/src/tests/test_quick_unlock_default.py b/src/tests/test_quick_unlock_default.py new file mode 100644 index 00000000..1f635c65 --- /dev/null +++ b/src/tests/test_quick_unlock_default.py @@ -0,0 +1,34 @@ +import logging +from types import SimpleNamespace +from pathlib import Path +import sys + +import pytest + +sys.path.append(str(Path(__file__).resolve().parents[1])) + +from seedpass.core.manager import PasswordManager +from seedpass.core.config_manager import ConfigManager +from helpers import create_vault, TEST_SEED, TEST_PASSWORD + + +def test_quick_unlock_default_off(tmp_path): + vault, _ = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + assert cfg_mgr.get_quick_unlock() is False + + +def test_quick_unlock_logs_event(tmp_path, caplog): + pm = PasswordManager.__new__(PasswordManager) + pm.fingerprint_dir = tmp_path + pm.current_fingerprint = "user123" + pm.setup_encryption_manager = lambda *a, **k: None + pm.initialize_bip85 = lambda: None + pm.initialize_managers = lambda: None + pm.update_activity = lambda: None + pm.config_manager = SimpleNamespace(get_quick_unlock=lambda: True) + + with caplog.at_level(logging.INFO): + pm.unlock_vault(password="pw") + + assert any("Quick unlock used by user123" in rec.message for rec in caplog.records) diff --git a/src/tests/test_quick_unlock_profile_creation.py b/src/tests/test_quick_unlock_profile_creation.py new file mode 100644 index 00000000..6eaf2301 --- /dev/null +++ b/src/tests/test_quick_unlock_profile_creation.py @@ -0,0 +1,28 @@ +from pathlib import Path +from tempfile import TemporaryDirectory + +from main import handle_toggle_quick_unlock +from seedpass.core.manager import PasswordManager +from helpers import create_vault, TEST_SEED, TEST_PASSWORD +from utils.fingerprint import generate_fingerprint + + +def test_toggle_quick_unlock_after_profile_creation(monkeypatch): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + monkeypatch.setattr(Path, "home", lambda: tmp_path) + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + pm = PasswordManager.__new__(PasswordManager) + pm.vault = vault + pm.encryption_manager = enc_mgr + pm.fingerprint_dir = tmp_path + pm.current_fingerprint = generate_fingerprint(TEST_SEED) + pm.config_manager = None + + inputs = iter(["y"]) + monkeypatch.setattr("builtins.input", lambda *a: next(inputs)) + handle_toggle_quick_unlock(pm) + + assert pm.config_manager is not None + cfg = pm.config_manager.load_config(require_pin=False) + assert cfg["quick_unlock_enabled"] is True diff --git a/src/tests/test_restore_from_nostr_setup.py b/src/tests/test_restore_from_nostr_setup.py index 96bc70e2..8df98c91 100644 --- a/src/tests/test_restore_from_nostr_setup.py +++ b/src/tests/test_restore_from_nostr_setup.py @@ -1,6 +1,6 @@ from pathlib import Path -from helpers import create_vault, dummy_nostr_client, TEST_SEED, TEST_PASSWORD +from helpers import create_vault, TEST_SEED, TEST_PASSWORD from seedpass.core.entry_management import EntryManager from seedpass.core.backup import BackupManager @@ -28,8 +28,10 @@ def _init_pm(dir_path: Path, client) -> PasswordManager: return pm -def test_handle_new_seed_setup_restore_from_nostr(monkeypatch, tmp_path, capsys): - client, _relay = dummy_nostr_client.__wrapped__(tmp_path / "srv", monkeypatch) +def test_handle_new_seed_setup_restore_from_nostr( + monkeypatch, tmp_path, capsys, make_dummy_nostr_client +): + client, _relay = make_dummy_nostr_client(tmp_path / "srv") dir_a = tmp_path / "A" dir_b = tmp_path / "B" @@ -74,12 +76,69 @@ def test_handle_new_seed_setup_restore_from_nostr(monkeypatch, tmp_path, capsys) assert labels == ["site1"] +def test_handle_new_seed_setup_restore_from_local_backup(monkeypatch, tmp_path, capsys): + dir_a = tmp_path / "A" + dir_b = tmp_path / "B" + dir_a.mkdir() + dir_b.mkdir() + + pm_src = _init_pm(dir_a, None) + pm_src.notify = lambda *a, **k: None + pm_src.entry_manager.add_entry("site1", 12) + pm_src.backup_manager.create_backup() + backup_path = next( + pm_src.backup_manager.backup_dir.glob("entries_db_backup_*.json.enc") + ) + + pm_new = PasswordManager.__new__(PasswordManager) + pm_new.encryption_mode = EncryptionMode.SEED_ONLY + pm_new.notify = lambda *a, **k: None + + called = {"init": False} + + def init_fp_mgr(): + called["init"] = True + pm_new.fingerprint_manager = object() + + monkeypatch.setattr(pm_new, "initialize_fingerprint_manager", init_fp_mgr) + + def finalize(seed, *, password=None): + assert pm_new.fingerprint_manager is not None + vault, enc_mgr = create_vault(dir_b, seed, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, dir_b) + backup_mgr = BackupManager(dir_b, cfg_mgr) + entry_mgr = EntryManager(vault, backup_mgr) + pm_new.encryption_manager = enc_mgr + pm_new.vault = vault + pm_new.entry_manager = entry_mgr + pm_new.backup_manager = backup_mgr + pm_new.config_manager = cfg_mgr + pm_new.fingerprint_dir = dir_b + pm_new.current_fingerprint = "fp" + return "fp" + + monkeypatch.setattr(pm_new, "_finalize_existing_seed", finalize) + monkeypatch.setattr("seedpass.core.manager.masked_input", lambda *_: TEST_SEED) + + inputs = iter(["5", str(backup_path)]) + monkeypatch.setattr("builtins.input", lambda *a, **k: next(inputs)) + + pm_new.handle_new_seed_setup() + out = capsys.readouterr().out + assert "Index file restored from backup" in out + labels = [e[1] for e in pm_new.entry_manager.list_entries()] + assert labels == ["site1"] + assert called["init"] + + async def _no_snapshot(): return None -def test_restore_from_nostr_warns(monkeypatch, tmp_path, capsys): - client, _relay = dummy_nostr_client.__wrapped__(tmp_path / "srv", monkeypatch) +def test_restore_from_nostr_warns( + monkeypatch, tmp_path, capsys, make_dummy_nostr_client +): + client, _relay = make_dummy_nostr_client(tmp_path / "srv") monkeypatch.setattr(client, "fetch_latest_snapshot", _no_snapshot) pm = PasswordManager.__new__(PasswordManager) @@ -95,8 +154,10 @@ def test_restore_from_nostr_warns(monkeypatch, tmp_path, capsys): assert "No Nostr backup" in out -def test_restore_from_nostr_abort(monkeypatch, tmp_path, capsys): - client, _relay = dummy_nostr_client.__wrapped__(tmp_path / "srv", monkeypatch) +def test_restore_from_nostr_abort( + monkeypatch, tmp_path, capsys, make_dummy_nostr_client +): + client, _relay = make_dummy_nostr_client(tmp_path / "srv") monkeypatch.setattr(client, "fetch_latest_snapshot", _no_snapshot) pm = PasswordManager.__new__(PasswordManager) diff --git a/src/tests/test_retrieve_pause_sensitive_entries.py b/src/tests/test_retrieve_pause_sensitive_entries.py index 7cdaa5bc..f952d5e4 100644 --- a/src/tests/test_retrieve_pause_sensitive_entries.py +++ b/src/tests/test_retrieve_pause_sensitive_entries.py @@ -1,16 +1,10 @@ import sys from pathlib import Path -from tempfile import TemporaryDirectory -from helpers import create_vault, TEST_SEED, TEST_PASSWORD +from helpers import TEST_SEED sys.path.append(str(Path(__file__).resolve().parents[1])) -from seedpass.core.entry_management import EntryManager -from seedpass.core.backup import BackupManager -from seedpass.core.manager import PasswordManager, EncryptionMode -from seedpass.core.config_manager import ConfigManager - import pytest @@ -23,36 +17,23 @@ import pytest (lambda mgr: mgr.add_nostr_key("nostr", TEST_SEED), False), ], ) -def test_pause_before_entry_actions(monkeypatch, adder, needs_confirm): - with TemporaryDirectory() as tmpdir: - tmp_path = Path(tmpdir) - vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) - cfg_mgr = ConfigManager(vault, tmp_path) - backup_mgr = BackupManager(tmp_path, cfg_mgr) - entry_mgr = EntryManager(vault, backup_mgr) +def test_pause_before_entry_actions( + monkeypatch, adder, needs_confirm, password_manager +): + pm = password_manager - pm = PasswordManager.__new__(PasswordManager) - pm.encryption_mode = EncryptionMode.SEED_ONLY - pm.encryption_manager = enc_mgr - pm.vault = vault - pm.entry_manager = entry_mgr - pm.backup_manager = backup_mgr - pm.parent_seed = TEST_SEED - pm.fingerprint_dir = tmp_path - pm.secret_mode_enabled = False + index = adder(pm.entry_manager) - index = adder(entry_mgr) - - pause_calls = [] + pause_calls = [] + monkeypatch.setattr( + "seedpass.core.manager.pause", lambda *a, **k: pause_calls.append(True) + ) + monkeypatch.setattr(pm, "_entry_actions_menu", lambda *a, **k: None) + monkeypatch.setattr("builtins.input", lambda *a, **k: str(index)) + if needs_confirm: monkeypatch.setattr( - "seedpass.core.manager.pause", lambda *a, **k: pause_calls.append(True) + "seedpass.core.manager.confirm_action", lambda *a, **k: True ) - monkeypatch.setattr(pm, "_entry_actions_menu", lambda *a, **k: None) - monkeypatch.setattr("builtins.input", lambda *a, **k: str(index)) - if needs_confirm: - monkeypatch.setattr( - "seedpass.core.manager.confirm_action", lambda *a, **k: True - ) - pm.handle_retrieve_entry() - assert len(pause_calls) == 1 + pm.handle_retrieve_entry() + assert len(pause_calls) == 1 diff --git a/src/tests/test_secret_mode.py b/src/tests/test_secret_mode.py index 6c4339de..be5222d3 100644 --- a/src/tests/test_secret_mode.py +++ b/src/tests/test_secret_mode.py @@ -46,7 +46,7 @@ def test_password_retrieve_secret_mode(monkeypatch, capsys): called = [] monkeypatch.setattr( "seedpass.core.manager.copy_to_clipboard", - lambda text, t: called.append((text, t)), + lambda text, t: (called.append((text, t)), True)[1], ) pm.handle_retrieve_entry() @@ -62,7 +62,10 @@ def test_totp_display_secret_mode(monkeypatch, capsys): pm, entry_mgr = setup_pm(tmp) entry_mgr.add_totp("Example", TEST_SEED) - monkeypatch.setattr(pm.entry_manager, "get_totp_code", lambda *a, **k: "123456") + monkeypatch.setattr( + "seedpass.core.totp.TotpManager.current_code_from_secret", + lambda *a, **k: "123456", + ) monkeypatch.setattr( pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 30 ) @@ -73,7 +76,7 @@ def test_totp_display_secret_mode(monkeypatch, capsys): called = [] monkeypatch.setattr( "seedpass.core.manager.copy_to_clipboard", - lambda text, t: called.append((text, t)), + lambda text, t: (called.append((text, t)), True)[1], ) pm.handle_display_totp_codes() @@ -95,7 +98,7 @@ def test_password_retrieve_no_secret_mode(monkeypatch, capsys): called = [] monkeypatch.setattr( "seedpass.core.manager.copy_to_clipboard", - lambda *a, **k: called.append((a, k)), + lambda *a, **k: (called.append((a, k)), True)[1], ) pm.handle_retrieve_entry() @@ -112,7 +115,10 @@ def test_totp_display_no_secret_mode(monkeypatch, capsys): pm.secret_mode_enabled = False entry_mgr.add_totp("Example", TEST_SEED) - monkeypatch.setattr(pm.entry_manager, "get_totp_code", lambda *a, **k: "123456") + monkeypatch.setattr( + "seedpass.core.totp.TotpManager.current_code_from_secret", + lambda *a, **k: "123456", + ) monkeypatch.setattr( pm.entry_manager, "get_totp_time_remaining", lambda *a, **k: 30 ) @@ -123,7 +129,7 @@ def test_totp_display_no_secret_mode(monkeypatch, capsys): called = [] monkeypatch.setattr( "seedpass.core.manager.copy_to_clipboard", - lambda *a, **k: called.append((a, k)), + lambda *a, **k: (called.append((a, k)), True)[1], ) pm.handle_display_totp_codes() diff --git a/src/tests/test_secret_mode_profile_creation.py b/src/tests/test_secret_mode_profile_creation.py new file mode 100644 index 00000000..cd3446c5 --- /dev/null +++ b/src/tests/test_secret_mode_profile_creation.py @@ -0,0 +1,59 @@ +from pathlib import Path +from tempfile import TemporaryDirectory +from types import SimpleNamespace + +import pytest + +from main import handle_toggle_secret_mode +from seedpass.core.manager import PasswordManager +from helpers import create_vault, TEST_SEED, TEST_PASSWORD +from utils.fingerprint import generate_fingerprint + + +def test_add_new_fingerprint_initializes_managers(monkeypatch, tmp_path): + pm = PasswordManager.__new__(PasswordManager) + monkeypatch.setattr(Path, "home", lambda: tmp_path) + pm.initialize_fingerprint_manager() + called = {} + + def fake_setup_existing_seed(method="paste"): + pm.current_fingerprint = "fp1" + pm.fingerprint_manager.current_fingerprint = "fp1" + pm.fingerprint_dir = tmp_path / "fp1" + pm.fingerprint_dir.mkdir() + return "fp1" + + monkeypatch.setattr(pm, "setup_existing_seed", fake_setup_existing_seed) + monkeypatch.setattr( + pm, "initialize_managers", lambda: called.setdefault("init", True) + ) + monkeypatch.setattr("builtins.input", lambda *a: "1") + pm.config_manager = None + pm.add_new_fingerprint() + assert called.get("init") is True + + +def test_toggle_secret_mode_after_profile_creation(monkeypatch): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + monkeypatch.setattr(Path, "home", lambda: tmp_path) + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + pm = PasswordManager.__new__(PasswordManager) + pm.vault = vault + pm.encryption_manager = enc_mgr + pm.fingerprint_dir = tmp_path + pm.current_fingerprint = generate_fingerprint(TEST_SEED) + pm.secret_mode_enabled = False + pm.clipboard_clear_delay = 45 + pm.config_manager = None + + inputs = iter(["y", "10"]) + monkeypatch.setattr("builtins.input", lambda *a: next(inputs)) + handle_toggle_secret_mode(pm) + + assert pm.secret_mode_enabled is True + assert pm.clipboard_clear_delay == 10 + assert pm.config_manager is not None + cfg = pm.config_manager.load_config(require_pin=False) + assert cfg["secret_mode_enabled"] is True + assert cfg["clipboard_clear_delay"] == 10 diff --git a/src/tests/test_seed_generation.py b/src/tests/test_seed_generation.py index eb6b6ca8..59227075 100644 --- a/src/tests/test_seed_generation.py +++ b/src/tests/test_seed_generation.py @@ -21,6 +21,7 @@ def setup_password_manager(): pm.fingerprint_manager = manager_module.FingerprintManager(constants.APP_DIR) pm.current_fingerprint = None pm.save_and_encrypt_seed = lambda seed, fingerprint_dir: None + pm.state_manager = manager_module.StateManager(constants.APP_DIR) return pm, constants diff --git a/src/tests/test_seed_import.py b/src/tests/test_seed_import.py index 7cbbe6d4..6d3f860a 100644 --- a/src/tests/test_seed_import.py +++ b/src/tests/test_seed_import.py @@ -3,6 +3,7 @@ from pathlib import Path from tempfile import TemporaryDirectory from helpers import TEST_PASSWORD from utils.key_derivation import derive_key_from_password +from utils.fingerprint import generate_fingerprint from mnemonic import Mnemonic sys.path.append(str(Path(__file__).resolve().parents[1])) @@ -13,10 +14,10 @@ from seedpass.core.manager import PasswordManager, EncryptionMode def test_seed_encryption_round_trip(): with TemporaryDirectory() as tmpdir: - key = derive_key_from_password(TEST_PASSWORD) - enc_mgr = EncryptionManager(key, Path(tmpdir)) - seed = Mnemonic("english").generate(strength=128) + fp = generate_fingerprint(seed) + key = derive_key_from_password(TEST_PASSWORD, fp) + enc_mgr = EncryptionManager(key, Path(tmpdir)) enc_mgr.encrypt_parent_seed(seed) decrypted = enc_mgr.decrypt_parent_seed() diff --git a/src/tests/test_seed_migration.py b/src/tests/test_seed_migration.py index 845dfaa5..5951e917 100644 --- a/src/tests/test_seed_migration.py +++ b/src/tests/test_seed_migration.py @@ -1,9 +1,12 @@ import sys +import json +import base64 from pathlib import Path from cryptography.fernet import Fernet from helpers import TEST_PASSWORD, TEST_SEED from utils.key_derivation import derive_key_from_password +from utils.fingerprint import generate_fingerprint sys.path.append(str(Path(__file__).resolve().parents[1])) @@ -11,7 +14,8 @@ from seedpass.core.encryption import EncryptionManager def test_parent_seed_migrates_from_fernet(tmp_path: Path) -> None: - key = derive_key_from_password(TEST_PASSWORD) + fp = generate_fingerprint(TEST_SEED) + key = derive_key_from_password(TEST_PASSWORD, fp) fernet = Fernet(key) encrypted = fernet.encrypt(TEST_SEED.encode()) legacy_file = tmp_path / "parent_seed.enc" @@ -26,4 +30,5 @@ def test_parent_seed_migrates_from_fernet(tmp_path: Path) -> None: assert new_file.exists() assert new_file.read_bytes() != encrypted - assert new_file.read_bytes().startswith(b"V2:") + payload = json.loads(new_file.read_text()) + assert base64.b64decode(payload["ct"]).startswith(b"V3|") diff --git a/src/tests/test_seed_prompt.py b/src/tests/test_seed_prompt.py index 3711cd48..163b7ffd 100644 --- a/src/tests/test_seed_prompt.py +++ b/src/tests/test_seed_prompt.py @@ -1,4 +1,5 @@ import types +import pytest from utils import seed_prompt @@ -46,6 +47,37 @@ def test_masked_input_windows_space(monkeypatch, capsys): assert out.count("*") == 4 +def test_masked_input_posix_ctrl_c(monkeypatch): + seq = iter(["\x03"]) + monkeypatch.setattr(seed_prompt.sys.stdin, "read", lambda n=1: next(seq)) + monkeypatch.setattr(seed_prompt.sys.stdin, "fileno", lambda: 0) + + calls: list[tuple[str, int]] = [] + fake_termios = types.SimpleNamespace( + tcgetattr=lambda fd: "old", + tcsetattr=lambda fd, *_: calls.append(("tcsetattr", fd)), + TCSADRAIN=1, + ) + fake_tty = types.SimpleNamespace(setraw=lambda fd: calls.append(("setraw", fd))) + monkeypatch.setattr(seed_prompt, "termios", fake_termios) + monkeypatch.setattr(seed_prompt, "tty", fake_tty) + monkeypatch.setattr(seed_prompt.sys, "platform", "linux", raising=False) + + with pytest.raises(KeyboardInterrupt): + seed_prompt.masked_input("Enter: ") + assert calls == [("setraw", 0), ("tcsetattr", 0)] + + +def test_masked_input_windows_ctrl_c(monkeypatch): + seq = iter(["\x03"]) + fake_msvcrt = types.SimpleNamespace(getwch=lambda: next(seq)) + monkeypatch.setattr(seed_prompt, "msvcrt", fake_msvcrt) + monkeypatch.setattr(seed_prompt.sys, "platform", "win32", raising=False) + + with pytest.raises(KeyboardInterrupt): + seed_prompt.masked_input("Password: ") + + def test_prompt_seed_words_valid(monkeypatch): from mnemonic import Mnemonic diff --git a/src/tests/test_seed_word_by_word_flow.py b/src/tests/test_seed_word_by_word_flow.py new file mode 100644 index 00000000..3f5a6587 --- /dev/null +++ b/src/tests/test_seed_word_by_word_flow.py @@ -0,0 +1,94 @@ +import builtins +from types import SimpleNamespace + +import pytest + +import seedpass.core.manager as manager_module +from seedpass.core.errors import SeedPassError +from helpers import TEST_SEED +from utils import seed_prompt + + +def test_prompt_seed_words_confirmation_loop(monkeypatch): + phrase = TEST_SEED + words = phrase.split() + inputs = iter(words + [words[2]]) + confirmations = iter(["y", "y", "n", "y"] + ["y"] * (len(words) - 3)) + + monkeypatch.setattr(seed_prompt, "masked_input", lambda *_: next(inputs)) + monkeypatch.setattr(seed_prompt, "_apply_backoff", lambda *_a, **_k: None) + monkeypatch.setattr(seed_prompt, "clear_screen", lambda *_a, **_k: None) + monkeypatch.setattr(builtins, "input", lambda *_: next(confirmations)) + + result = seed_prompt.prompt_seed_words(len(words)) + assert result == phrase + + +def test_prompt_seed_words_invalid_word(monkeypatch): + phrase = TEST_SEED + words = phrase.split() + inputs = iter(["invalid"] + words) + confirmations = iter(["y"] * len(words)) + + monkeypatch.setattr(seed_prompt, "masked_input", lambda *_: next(inputs)) + monkeypatch.setattr(seed_prompt, "_apply_backoff", lambda *_a, **_k: None) + monkeypatch.setattr(seed_prompt, "clear_screen", lambda *_a, **_k: None) + monkeypatch.setattr(builtins, "input", lambda *_: next(confirmations)) + + result = seed_prompt.prompt_seed_words(len(words)) + assert result == phrase + + +def test_add_new_fingerprint_words_flow_success(monkeypatch): + pm = manager_module.PasswordManager.__new__(manager_module.PasswordManager) + pm.fingerprint_manager = SimpleNamespace(current_fingerprint=None) + pm.initialize_managers = lambda: None + + phrase = TEST_SEED + words = phrase.split() + word_iter = iter(words) + inputs = iter(["2"] + ["y"] * len(words)) + + monkeypatch.setattr(seed_prompt, "masked_input", lambda *_: next(word_iter)) + monkeypatch.setattr(seed_prompt, "_apply_backoff", lambda *_a, **_k: None) + monkeypatch.setattr(seed_prompt, "clear_screen", lambda *_a, **_k: None) + monkeypatch.setattr(builtins, "input", lambda *_: next(inputs)) + + captured = {} + + def finalize(self, seed, password=None): + captured["seed"] = seed + self.parent_seed = seed + return "fp" + + monkeypatch.setattr( + manager_module.PasswordManager, "_finalize_existing_seed", finalize + ) + + result = pm.add_new_fingerprint() + + assert result == "fp" + assert pm.fingerprint_manager.current_fingerprint == "fp" + assert captured["seed"] == phrase + assert pm.parent_seed == phrase + + +def test_add_new_fingerprint_words_flow_invalid_phrase(monkeypatch): + pm = manager_module.PasswordManager.__new__(manager_module.PasswordManager) + pm.fingerprint_manager = SimpleNamespace(current_fingerprint=None) + pm.initialize_managers = lambda: None + + words = ["abandon"] * 12 + word_iter = iter(words) + inputs = iter(["2"] + ["y"] * len(words)) + + monkeypatch.setattr(seed_prompt, "masked_input", lambda *_: next(word_iter)) + monkeypatch.setattr(seed_prompt, "_apply_backoff", lambda *_a, **_k: None) + monkeypatch.setattr(seed_prompt, "clear_screen", lambda *_a, **_k: None) + monkeypatch.setattr(builtins, "input", lambda *_: next(inputs)) + + with pytest.raises(SeedPassError): + pm.add_new_fingerprint() + + assert pm.fingerprint_manager.current_fingerprint is None + assert not hasattr(pm, "parent_seed") diff --git a/src/tests/test_service_classes.py b/src/tests/test_service_classes.py new file mode 100644 index 00000000..a32b549d --- /dev/null +++ b/src/tests/test_service_classes.py @@ -0,0 +1,148 @@ +from tempfile import TemporaryDirectory +from types import SimpleNamespace +from pathlib import Path + +import pytest + +from helpers import create_vault, TEST_SEED, TEST_PASSWORD +from seedpass.core.entry_management import EntryManager +from seedpass.core.backup import BackupManager +from seedpass.core.manager import PasswordManager, EncryptionMode +from seedpass.core.config_manager import ConfigManager +from seedpass.core.entry_service import EntryService +from seedpass.core.profile_service import ProfileService +from constants import DEFAULT_PASSWORD_LENGTH + + +class FakePasswordGenerator: + def generate_password(self, length: int, index: int) -> str: + return f"pw-{index}-{length}" + + +def _setup_pm(tmp_path: Path, client) -> PasswordManager: + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + backup_mgr = BackupManager(tmp_path, cfg_mgr) + entry_mgr = EntryManager(vault, backup_mgr) + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = enc_mgr + pm.vault = vault + pm.entry_manager = entry_mgr + pm.backup_manager = backup_mgr + pm.password_generator = FakePasswordGenerator() + pm.parent_seed = TEST_SEED + pm.nostr_client = client + pm.fingerprint_dir = tmp_path + pm.secret_mode_enabled = False + pm.is_dirty = False + return pm + + +def test_entry_service_add_password(monkeypatch, dummy_nostr_client, capsys): + client, _relay = dummy_nostr_client + with TemporaryDirectory() as tmpdir: + pm = _setup_pm(Path(tmpdir), client) + service = EntryService(pm) + inputs = iter( + [ + "a", + "Example", + "", + "", + "", + "", + "n", + "", + "", + "", + "", + "", + "", + "", + "", + "", + ] + ) + monkeypatch.setattr("builtins.input", lambda *a, **k: next(inputs)) + monkeypatch.setattr("seedpass.core.entry_service.pause", lambda *a, **k: None) + monkeypatch.setattr(pm, "start_background_vault_sync", lambda *a, **k: None) + + service.handle_add_password() + out = capsys.readouterr().out + entries = pm.entry_manager.list_entries(verbose=False) + assert entries == [(0, "Example", "", "", False)] + assert f"pw-0-{DEFAULT_PASSWORD_LENGTH}" in out + + +def test_menu_handler_list_entries(monkeypatch, capsys): + with TemporaryDirectory() as tmpdir: + pm = _setup_pm(Path(tmpdir), SimpleNamespace()) + pm.entry_manager.add_totp("Example", TEST_SEED) + pm.entry_manager.add_entry("example.com", 12) + pm.entry_manager.add_key_value("API entry", "api", "abc123") + pm.entry_manager.add_managed_account("acct", TEST_SEED) + inputs = iter(["1", ""]) # list all then exit + monkeypatch.setattr("builtins.input", lambda *_: next(inputs)) + pm.menu_handler.handle_list_entries() + out = capsys.readouterr().out + assert "Example" in out + assert "example.com" in out + assert "API" in out + assert "acct" in out + + +def test_menu_handler_list_entries_shows_empty_message(monkeypatch, capsys): + with TemporaryDirectory() as tmpdir: + pm = _setup_pm(Path(tmpdir), SimpleNamespace()) + # Keep only an archived password so active listing is empty. + idx = pm.entry_manager.add_entry("example.com", 12) + pm.entry_manager.archive_entry(idx) + inputs = iter(["1", ""]) # list all, then exit + monkeypatch.setattr("builtins.input", lambda *_: next(inputs)) + pm.menu_handler.handle_list_entries() + out = capsys.readouterr().out + assert "No active entries found." in out + + +def test_profile_service_switch(monkeypatch): + class DummyFingerprintManager: + def __init__(self): + self.fingerprints = ["fp1", "fp2"] + self.current_fingerprint = "fp1" + + def list_fingerprints(self): + return self.fingerprints + + def display_name(self, fp): + return fp + + def get_current_fingerprint_dir(self): + return Path(".") + + pm = PasswordManager.__new__(PasswordManager) + pm.fingerprint_manager = DummyFingerprintManager() + pm.current_fingerprint = "fp1" + pm.setup_encryption_manager = lambda *a, **k: True + pm.initialize_bip85 = lambda *a, **k: None + pm.initialize_managers = lambda *a, **k: None + pm.start_background_sync = lambda *a, **k: None + pm.nostr_client = SimpleNamespace() + pm.manifest_id = None + pm.delta_since = None + pm.encryption_manager = SimpleNamespace() + pm.parent_seed = TEST_SEED + pm.nostr_account_idx = 0 + + service = ProfileService(pm) + monkeypatch.setattr("builtins.input", lambda *_: "2") + monkeypatch.setattr( + "seedpass.core.profile_service.prompt_existing_password", lambda *_: "pw" + ) + monkeypatch.setattr( + "seedpass.core.manager.NostrClient", lambda *a, **k: SimpleNamespace() + ) + + assert service.handle_switch_fingerprint() is True + assert pm.current_fingerprint == "fp2" diff --git a/src/tests/test_settings_menu.py b/src/tests/test_settings_menu.py index d7699d0b..734a338c 100644 --- a/src/tests/test_settings_menu.py +++ b/src/tests/test_settings_menu.py @@ -1,10 +1,14 @@ import sys import importlib +import queue +import time from pathlib import Path from tempfile import TemporaryDirectory from types import SimpleNamespace from unittest.mock import patch +import pytest + from helpers import create_vault, TEST_SEED, TEST_PASSWORD sys.path.append(str(Path(__file__).resolve().parents[1])) @@ -12,6 +16,7 @@ sys.path.append(str(Path(__file__).resolve().parents[1])) import main from nostr.client import DEFAULT_RELAYS from seedpass.core.config_manager import ConfigManager +from seedpass.core.manager import Notification, PasswordManager from seedpass.core.vault import Vault from utils.fingerprint_manager import FingerprintManager @@ -98,3 +103,70 @@ def test_settings_menu_additional_backup(monkeypatch): with patch("builtins.input", side_effect=lambda *_: next(inputs)): main.handle_settings(pm) handler.assert_called_once_with(pm) + + +def test_settings_menu_change_password(monkeypatch): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + pm, _, _ = setup_pm(tmp_path, monkeypatch) + calls: list[tuple[str, str]] = [] + pm.change_password = lambda old, new: calls.append((old, new)) + + inputs = iter(["3", ""]) + monkeypatch.setattr(main, "prompt_existing_password", lambda *_: "oldpw") + monkeypatch.setattr(main, "prompt_new_password", lambda *_: "newpw") + monkeypatch.setattr(main, "pause", lambda: None) + + with patch("builtins.input", side_effect=lambda *_: next(inputs)): + main.handle_settings(pm) + + assert calls == [("oldpw", "newpw")] + + +def test_settings_menu_change_password_incorrect(monkeypatch, capsys): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + pm, _, _ = setup_pm(tmp_path, monkeypatch) + + def fail_change(old, new): + raise ValueError("Incorrect password") + + pm.change_password = fail_change + inputs = iter(["3", ""]) + monkeypatch.setattr(main, "prompt_existing_password", lambda *_: "badpw") + monkeypatch.setattr(main, "prompt_new_password", lambda *_: "newpw") + monkeypatch.setattr(main, "pause", lambda: None) + + with patch("builtins.input", side_effect=lambda *_: next(inputs)): + main.handle_settings(pm) + + out = capsys.readouterr().out + assert "Incorrect password" in out + + +def test_settings_menu_without_nostr_client(monkeypatch): + pm = PasswordManager.__new__(PasswordManager) + pm.offline_mode = False + pm.nostr_client = None + pm.notifications = queue.Queue() + pm.error_queue = queue.Queue() + pm.notify = lambda msg, level="INFO": pm.notifications.put(Notification(msg, level)) + pm.is_dirty = False + pm.last_update = time.time() + pm.last_activity = time.time() + pm.update_activity = lambda: None + pm.lock_vault = lambda: None + pm.unlock_vault = lambda: None + pm.start_background_relay_check = lambda: None + pm.poll_background_errors = PasswordManager.poll_background_errors.__get__(pm) + pm.display_stats = lambda: None + + inputs = iter(["7", ""]) + monkeypatch.setattr(main, "timed_input", lambda *_: next(inputs)) + monkeypatch.setattr("builtins.input", lambda *_: "") + + with pytest.raises(SystemExit): + main.display_menu(pm, sync_interval=1000, inactivity_timeout=1000) + + assert pm.error_queue.empty() + assert pm.notifications.empty() diff --git a/src/tests/test_state_manager.py b/src/tests/test_state_manager.py index 71abe250..0cd19144 100644 --- a/src/tests/test_state_manager.py +++ b/src/tests/test_state_manager.py @@ -14,6 +14,7 @@ def test_state_manager_round_trip(): assert state["last_sync_ts"] == 0 assert state["manifest_id"] is None assert state["delta_since"] == 0 + assert state["nostr_account_idx"] == 0 sm.add_relay("wss://example.com") sm.update_state( @@ -30,6 +31,7 @@ def test_state_manager_round_trip(): assert state2["last_sync_ts"] == 123 assert state2["manifest_id"] == "mid" assert state2["delta_since"] == 111 + assert state2["nostr_account_idx"] == 0 sm2.remove_relay(1) # remove first default relay assert len(sm2.list_relays()) == len(DEFAULT_RELAYS) diff --git a/src/tests/test_stats_screen.py b/src/tests/test_stats_screen.py index f7f6d4ec..feb63d6e 100644 --- a/src/tests/test_stats_screen.py +++ b/src/tests/test_stats_screen.py @@ -88,3 +88,21 @@ def test_stats_display_resets_after_exit(monkeypatch, capsys): main._display_live_stats(pm) out = capsys.readouterr().out assert out.count("stats") == 2 + + +def test_stats_screen_breaks_on_enter(monkeypatch): + calls = {"display": 0} + + def display(): + calls["display"] += 1 + print("stats") + + pm = _make_pm() + pm.display_stats = display + + monkeypatch.setattr(main, "get_notification_text", lambda *_: "") + monkeypatch.setattr(main, "timed_input", lambda *_args, **_kwargs: "") + + main._display_live_stats(pm, interval=0.01) + + assert calls["display"] == 1 diff --git a/src/tests/test_sync_race_conditions.py b/src/tests/test_sync_race_conditions.py index 07866594..b7dbc45a 100644 --- a/src/tests/test_sync_race_conditions.py +++ b/src/tests/test_sync_race_conditions.py @@ -3,7 +3,7 @@ import threading from pathlib import Path -from helpers import create_vault, dummy_nostr_client +from helpers import create_vault from seedpass.core.entry_management import EntryManager from seedpass.core.backup import BackupManager @@ -31,8 +31,8 @@ def _init_pm(dir_path: Path, client) -> PasswordManager: return pm -def test_sync_race_conditions(monkeypatch, tmp_path): - client_a, relay = dummy_nostr_client.__wrapped__(tmp_path / "c1", monkeypatch) +def test_sync_race_conditions(monkeypatch, tmp_path, make_dummy_nostr_client): + client_a, relay = make_dummy_nostr_client(tmp_path / "c1") from cryptography.fernet import Fernet from nostr.client import NostrClient diff --git a/src/tests/test_terminal_utils_failure_handling.py b/src/tests/test_terminal_utils_failure_handling.py new file mode 100644 index 00000000..6dbfce2c --- /dev/null +++ b/src/tests/test_terminal_utils_failure_handling.py @@ -0,0 +1,37 @@ +"""Tests for terminal utility failure handling.""" + +import logging +import pytest + +from utils.terminal_utils import ( + clear_header_with_notification, + format_profile, +) + + +class ErrorFingerprintManager: + def get_name(self, _fingerprint): # pragma: no cover - helper + raise ValueError("boom") + + +class ErrorPM: + fingerprint_manager = ErrorFingerprintManager() + + def get_current_notification(self): # pragma: no cover - helper + raise RuntimeError("bad") + + +def test_format_profile_reraises(monkeypatch, caplog): + pm = ErrorPM() + with caplog.at_level(logging.ERROR): + with pytest.raises(ValueError): + format_profile("abc", pm) + assert "Error retrieving name for fingerprint" in caplog.text + + +def test_clear_header_with_notification_reraises(caplog): + pm = ErrorPM() + with caplog.at_level(logging.ERROR): + with pytest.raises(RuntimeError): + clear_header_with_notification(pm) + assert "Error getting current notification" in caplog.text diff --git a/src/tests/test_totp_entry.py b/src/tests/test_totp_entry.py index eff49886..92e9bf7c 100644 --- a/src/tests/test_totp_entry.py +++ b/src/tests/test_totp_entry.py @@ -28,23 +28,19 @@ def test_add_totp_and_get_code(): assert uri.startswith("otpauth://totp/") entry = entry_mgr.retrieve_entry(0) - assert entry == { - "type": "totp", - "kind": "totp", - "label": "Example", - "index": 0, - "period": 30, - "digits": 6, - "archived": False, - "notes": "", - "tags": [], - } + assert entry["deterministic"] is False + assert "secret" in entry - code = entry_mgr.get_totp_code(0, TEST_SEED, timestamp=0) + code = entry_mgr.get_totp_code(0, timestamp=0) - expected = TotpManager.current_code(TEST_SEED, 0, timestamp=0) + expected = pyotp.TOTP(entry["secret"]).at(0) assert code == expected + # second entry should have different secret + entry_mgr.add_totp("Other", TEST_SEED) + entry2 = entry_mgr.retrieve_entry(1) + assert entry["secret"] != entry2["secret"] + def test_totp_time_remaining(monkeypatch): with TemporaryDirectory() as tmpdir: @@ -68,17 +64,8 @@ def test_add_totp_imported(tmp_path): secret = "JBSWY3DPEHPK3PXP" em.add_totp("Imported", TEST_SEED, secret=secret) entry = em.retrieve_entry(0) - assert entry == { - "type": "totp", - "kind": "totp", - "label": "Imported", - "secret": secret, - "period": 30, - "digits": 6, - "archived": False, - "notes": "", - "tags": [], - } + assert entry["secret"] == secret + assert entry["deterministic"] is False code = em.get_totp_code(0, timestamp=0) assert code == pyotp.TOTP(secret).at(0) @@ -92,3 +79,23 @@ def test_add_totp_with_notes(tmp_path): em.add_totp("NoteLabel", TEST_SEED, notes="some note") entry = em.retrieve_entry(0) assert entry["notes"] == "some note" + + +def test_legacy_deterministic_entry(tmp_path): + vault, enc = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + backup_mgr = BackupManager(tmp_path, cfg_mgr) + em = EntryManager(vault, backup_mgr) + + em.add_totp("Legacy", TEST_SEED, deterministic=True) + data = em._load_index() + entry = data["entries"]["0"] + entry.pop("deterministic", None) + em._save_index(data) + + code = em.get_totp_code(0, TEST_SEED, timestamp=0) + expected = TotpManager.current_code(TEST_SEED, 0, timestamp=0) + assert code == expected + + exported = em.export_totp_entries(TEST_SEED) + assert exported["entries"][0]["secret"] == TotpManager.derive_secret(TEST_SEED, 0) diff --git a/src/tests/test_typer_cli.py b/src/tests/test_typer_cli.py index 43fc8139..6e60b9b9 100644 --- a/src/tests/test_typer_cli.py +++ b/src/tests/test_typer_cli.py @@ -6,7 +6,9 @@ sys.path.append(str(Path(__file__).resolve().parents[1])) from typer.testing import CliRunner -from seedpass.cli import app, PasswordManager +from seedpass.cli import app +from seedpass.cli import common as cli_common +from seedpass.cli import api as cli_api from seedpass import cli from seedpass.core.entry_types import EntryType @@ -16,15 +18,15 @@ runner = CliRunner() def test_entry_list(monkeypatch): called = {} - def list_entries(sort_by="index", filter_kind=None, include_archived=False): - called["args"] = (sort_by, filter_kind, include_archived) + def list_entries(sort_by="index", filter_kinds=None, include_archived=False): + called["args"] = (sort_by, filter_kinds, include_archived) return [(0, "Site", "user", "", False)] pm = SimpleNamespace( entry_manager=SimpleNamespace(list_entries=list_entries), select_fingerprint=lambda fp: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["entry", "list"]) assert result.exit_code == 0 assert "Site" in result.stdout @@ -40,7 +42,7 @@ def test_entry_search(monkeypatch): ), select_fingerprint=lambda fp: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["entry", "search", "l"]) assert result.exit_code == 0 assert "Password - L" in result.stdout @@ -61,7 +63,7 @@ def test_entry_get_password(monkeypatch): parent_seed="seed", select_fingerprint=lambda fp: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["entry", "get", "ex"]) assert result.exit_code == 0 assert "pw" in result.stdout @@ -74,8 +76,8 @@ def test_vault_export(monkeypatch, tmp_path): called["export"] = True return b"data" - monkeypatch.setattr(cli.VaultService, "export_profile", export_profile) - monkeypatch.setattr(cli, "PasswordManager", lambda: SimpleNamespace()) + monkeypatch.setattr(cli_common.VaultService, "export_profile", export_profile) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: SimpleNamespace()) out_path = tmp_path / "out.json" result = runner.invoke(app, ["vault", "export", "--file", str(out_path)]) assert result.exit_code == 0 @@ -89,8 +91,8 @@ def test_vault_import(monkeypatch, tmp_path): def import_profile(self, data): called["data"] = data - monkeypatch.setattr(cli.VaultService, "import_profile", import_profile) - monkeypatch.setattr(cli, "PasswordManager", lambda: SimpleNamespace()) + monkeypatch.setattr(cli_common.VaultService, "import_profile", import_profile) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: SimpleNamespace()) in_path = tmp_path / "in.json" in_path.write_bytes(b"inp") result = runner.invoke(app, ["vault", "import", "--file", str(in_path)]) @@ -108,9 +110,9 @@ def test_vault_import_triggers_sync(monkeypatch, tmp_path): def sync_vault(): called["sync"] = True - monkeypatch.setattr(cli.VaultService, "import_profile", import_profile) + monkeypatch.setattr(cli_common.VaultService, "import_profile", import_profile) monkeypatch.setattr( - cli, "PasswordManager", lambda: SimpleNamespace(sync_vault=sync_vault) + cli_common, "PasswordManager", lambda: SimpleNamespace(sync_vault=sync_vault) ) in_path = tmp_path / "in.json" in_path.write_bytes(b"inp") @@ -127,7 +129,7 @@ def test_vault_change_password(monkeypatch): called["args"] = (old, new) pm = SimpleNamespace(change_password=change_pw, select_fingerprint=lambda fp: None) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["vault", "change-password"], input="old\nnew\nnew\n") assert result.exit_code == 0 assert called.get("args") == ("old", "new") @@ -141,9 +143,13 @@ def test_vault_lock(monkeypatch): pm.locked = True pm = SimpleNamespace( - lock_vault=lock, locked=False, select_fingerprint=lambda fp: None + lock_vault=lock, + locked=False, + select_fingerprint=lambda fp: None, + fingerprint_dir="/does/not/matter", + start_background_sync=lambda: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["vault", "lock"]) assert result.exit_code == 0 assert called.get("locked") is True @@ -158,9 +164,13 @@ def test_root_lock(monkeypatch): pm.locked = True pm = SimpleNamespace( - lock_vault=lock, locked=False, select_fingerprint=lambda fp: None + lock_vault=lock, + locked=False, + select_fingerprint=lambda fp: None, + fingerprint_dir="/does/not/matter", + start_background_sync=lambda: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["lock"]) assert result.exit_code == 0 assert called.get("locked") is True @@ -176,7 +186,7 @@ def test_vault_reveal_parent_seed(monkeypatch, tmp_path): pm = SimpleNamespace( handle_backup_reveal_parent_seed=reveal, select_fingerprint=lambda fp: None ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) out_path = tmp_path / "seed.enc" result = runner.invoke( app, @@ -194,7 +204,7 @@ def test_nostr_get_pubkey(monkeypatch): ), select_fingerprint=lambda fp: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["nostr", "get-pubkey"]) assert result.exit_code == 0 assert "np" in result.stdout @@ -205,7 +215,7 @@ def test_fingerprint_list(monkeypatch): fingerprint_manager=SimpleNamespace(list_fingerprints=lambda: ["a", "b"]), select_fingerprint=lambda fp: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["fingerprint", "list"]) assert result.exit_code == 0 assert "a" in result.stdout and "b" in result.stdout @@ -222,7 +232,7 @@ def test_fingerprint_add(monkeypatch): select_fingerprint=lambda fp: None, fingerprint_manager=SimpleNamespace(), ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["fingerprint", "add"]) assert result.exit_code == 0 assert called.get("add") is True @@ -238,7 +248,7 @@ def test_fingerprint_remove(monkeypatch): fingerprint_manager=SimpleNamespace(remove_fingerprint=remove), select_fingerprint=lambda fp: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["fingerprint", "remove", "abc"]) assert result.exit_code == 0 assert called.get("fp") == "abc" @@ -253,7 +263,7 @@ def test_fingerprint_switch(monkeypatch): pm = SimpleNamespace( select_fingerprint=switch, fingerprint_manager=SimpleNamespace() ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["fingerprint", "switch", "def"], input="pw\n") assert result.exit_code == 0 assert called.get("fp") == "def" @@ -266,7 +276,7 @@ def test_config_get(monkeypatch): ), select_fingerprint=lambda fp: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["config", "get", "x"]) assert result.exit_code == 0 assert "1" in result.stdout @@ -282,7 +292,7 @@ def test_config_set(monkeypatch): config_manager=SimpleNamespace(set_inactivity_timeout=set_timeout), select_fingerprint=lambda fp: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["config", "set", "inactivity_timeout", "5"]) assert result.exit_code == 0 assert called["timeout"] == 5.0 @@ -293,7 +303,7 @@ def test_config_set_unknown_key(monkeypatch): pm = SimpleNamespace( config_manager=SimpleNamespace(), select_fingerprint=lambda fp: None ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["config", "set", "bogus", "val"]) assert result.exit_code != 0 assert "Unknown key" in result.stdout @@ -311,7 +321,7 @@ def test_nostr_sync(monkeypatch): } pm = SimpleNamespace(sync_vault=sync_vault, select_fingerprint=lambda fp: None) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["nostr", "sync"]) assert result.exit_code == 0 assert called.get("called") is True @@ -329,12 +339,14 @@ def test_generate_password(monkeypatch): return "secretpw" monkeypatch.setattr( - cli, + cli_common, "PasswordManager", lambda: SimpleNamespace(select_fingerprint=lambda fp: None), ) monkeypatch.setattr( - cli, "UtilityService", lambda pm: SimpleNamespace(generate_password=gen_pw) + cli_common, + "UtilityService", + lambda pm: SimpleNamespace(generate_password=gen_pw), ) result = runner.invoke( app, @@ -382,8 +394,8 @@ def test_api_start_passes_fingerprint(monkeypatch): called["fp"] = fingerprint return "tok" - monkeypatch.setattr(cli.api_module, "start_server", fake_start) - monkeypatch.setattr(cli, "uvicorn", SimpleNamespace(run=lambda *a, **k: None)) + monkeypatch.setattr(cli_api.api_module, "start_server", fake_start) + monkeypatch.setattr(cli_api, "uvicorn", SimpleNamespace(run=lambda *a, **k: None)) result = runner.invoke(app, ["--fingerprint", "abc", "api", "start"]) assert result.exit_code == 0 @@ -399,7 +411,7 @@ def test_entry_list_passes_fingerprint(monkeypatch): called["fp"] = fingerprint self.entry_manager = SimpleNamespace(list_entries=lambda *a, **k: []) - monkeypatch.setattr(cli, "PasswordManager", PM) + monkeypatch.setattr(cli_common, "PasswordManager", PM) result = runner.invoke(app, ["--fingerprint", "abc", "entry", "list"]) assert result.exit_code == 0 assert called.get("fp") == "abc" @@ -418,7 +430,7 @@ def test_entry_add(monkeypatch): select_fingerprint=lambda fp: None, start_background_vault_sync=lambda: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke( app, [ @@ -475,7 +487,7 @@ def test_entry_modify(monkeypatch): select_fingerprint=lambda fp: None, start_background_vault_sync=lambda: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["entry", "modify", "1", "--username", "alice"]) assert result.exit_code == 0 assert called["args"][:6] == (1, "alice", None, None, None, None) @@ -490,7 +502,7 @@ def test_entry_modify_invalid(monkeypatch): select_fingerprint=lambda fp: None, start_background_vault_sync=lambda: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["entry", "modify", "1", "--username", "alice"]) assert result.exit_code == 1 assert "bad" in result.stdout @@ -507,7 +519,7 @@ def test_entry_archive(monkeypatch): select_fingerprint=lambda fp: None, start_background_vault_sync=lambda: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["entry", "archive", "3"]) assert result.exit_code == 0 assert "3" in result.stdout @@ -525,7 +537,7 @@ def test_entry_unarchive(monkeypatch): select_fingerprint=lambda fp: None, start_background_vault_sync=lambda: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["entry", "unarchive", "4"]) assert result.exit_code == 0 assert "4" in result.stdout @@ -543,7 +555,7 @@ def test_entry_export_totp(monkeypatch, tmp_path): parent_seed="seed", select_fingerprint=lambda fp: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) out = tmp_path / "t.json" result = runner.invoke(app, ["entry", "export-totp", "--file", str(out)]) @@ -559,7 +571,7 @@ def test_entry_totp_codes(monkeypatch): handle_display_totp_codes=lambda: called.setdefault("called", True), select_fingerprint=lambda fp: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["entry", "totp-codes"]) assert result.exit_code == 0 assert called.get("called") is True @@ -573,7 +585,7 @@ def test_verify_checksum_command(monkeypatch): handle_update_script_checksum=lambda: None, select_fingerprint=lambda fp: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["util", "verify-checksum"]) assert result.exit_code == 0 assert called.get("called") is True @@ -587,7 +599,7 @@ def test_update_checksum_command(monkeypatch): handle_update_script_checksum=lambda: called.setdefault("called", True), select_fingerprint=lambda fp: None, ) - monkeypatch.setattr(cli, "PasswordManager", lambda: pm) + monkeypatch.setattr(cli_common, "PasswordManager", lambda: pm) result = runner.invoke(app, ["util", "update-checksum"]) assert result.exit_code == 0 assert called.get("called") is True @@ -629,7 +641,17 @@ def test_gui_command(monkeypatch): def test_gui_command_no_backend(monkeypatch): - """Install backend if missing and launch GUI.""" + """Exit with message when backend is missing.""" + + monkeypatch.setattr(cli, "_gui_backend_available", lambda: False) + + result = runner.invoke(app, ["gui"]) + assert result.exit_code == 1 + assert "Please install" in result.output + + +def test_gui_command_install_backend(monkeypatch): + """Install backend on request and launch GUI.""" call_count = {"n": 0} @@ -657,7 +679,7 @@ def test_gui_command_no_backend(monkeypatch): SimpleNamespace(main=fake_main), ) - result = runner.invoke(app, ["gui"]) + result = runner.invoke(app, ["gui", "--install"], input="y\n") assert result.exit_code == 0 assert installed.get("cmd") is not None assert called.get("gui") is True diff --git a/src/tests/test_unlock_sync.py b/src/tests/test_unlock_sync.py index 58a62cb5..96b9eb7f 100644 --- a/src/tests/test_unlock_sync.py +++ b/src/tests/test_unlock_sync.py @@ -17,6 +17,7 @@ def test_unlock_triggers_sync(monkeypatch, tmp_path): pm.setup_encryption_manager = lambda *a, **k: None pm.initialize_bip85 = lambda: None pm.initialize_managers = lambda: None + pm.nostr_client = object() called = {"sync": False} async def fake_sync(self): @@ -62,6 +63,7 @@ def test_quick_unlock_background_sync(monkeypatch, tmp_path): def test_start_background_sync_running_loop(monkeypatch): pm = PasswordManager.__new__(PasswordManager) pm.offline_mode = False + pm.nostr_client = object() called = {"init": False, "sync": False} async def fake_attempt(self): diff --git a/src/tests/test_vault_lock_flag.py b/src/tests/test_vault_lock_flag.py new file mode 100644 index 00000000..d5786633 --- /dev/null +++ b/src/tests/test_vault_lock_flag.py @@ -0,0 +1,52 @@ +import pytest +from types import SimpleNamespace + +from seedpass.core.manager import PasswordManager +from seedpass.errors import VaultLockedError + + +class DummyEntryManager: + def __init__(self): + self.cleared = False + + def clear_cache(self): + self.cleared = True + + +def test_lock_vault_sets_flag_and_keeps_objects(): + pm = PasswordManager.__new__(PasswordManager) + em = DummyEntryManager() + pm.entry_manager = em + pm.is_locked = False + pm.locked = False + pm.lock_vault() + assert pm.is_locked + assert pm.locked + assert pm.entry_manager is em + assert em.cleared + + +def test_entry_service_requires_unlocked(): + pm = PasswordManager.__new__(PasswordManager) + service = SimpleNamespace() + pm._entry_service = service + pm.is_locked = True + with pytest.raises(VaultLockedError): + _ = pm.entry_service + pm.is_locked = False + assert pm.entry_service is service + + +def test_unlock_vault_clears_locked_flag(tmp_path): + pm = PasswordManager.__new__(PasswordManager) + pm.fingerprint_dir = tmp_path + pm.parent_seed = "seed" + pm.setup_encryption_manager = lambda *a, **k: None + pm.initialize_bip85 = lambda: None + pm.initialize_managers = lambda: None + pm.update_activity = lambda: None + pm.is_locked = True + pm.locked = True + pm.unlock_vault("pw") + assert not pm.is_locked + assert not pm.locked diff --git a/src/tests/test_verbose_timing.py b/src/tests/test_verbose_timing.py index a623b256..ff2517ec 100644 --- a/src/tests/test_verbose_timing.py +++ b/src/tests/test_verbose_timing.py @@ -2,7 +2,6 @@ import asyncio import logging from seedpass.core.manager import PasswordManager -from helpers import dummy_nostr_client def test_unlock_vault_logs_time(monkeypatch, caplog, tmp_path): diff --git a/src/utils/__init__.py b/src/utils/__init__.py index 6e830336..da73c00e 100644 --- a/src/utils/__init__.py +++ b/src/utils/__init__.py @@ -1,46 +1,55 @@ # utils/__init__.py +"""Utility package exports and optional feature handling.""" + import logging -import traceback logger = logging.getLogger(__name__) -try: - from .file_lock import exclusive_lock, shared_lock - from .key_derivation import ( - derive_key_from_password, - derive_key_from_parent_seed, - derive_index_key, - derive_totp_secret, - EncryptionMode, - DEFAULT_ENCRYPTION_MODE, - TOTP_PURPOSE, - ) - from .checksum import ( - calculate_checksum, - verify_checksum, - json_checksum, - canonical_json_dumps, - initialize_checksum, - update_checksum_file, - ) - from .password_prompt import prompt_for_password - from .seed_prompt import masked_input, prompt_seed_words - from .input_utils import timed_input - from .memory_protection import InMemorySecret - from .clipboard import copy_to_clipboard - from .terminal_utils import ( - clear_screen, - pause, - clear_and_print_fingerprint, - clear_header_with_notification, - ) +from .file_lock import exclusive_lock, shared_lock +from .key_derivation import ( + derive_key_from_password, + derive_key_from_parent_seed, + derive_index_key, + derive_totp_secret, + EncryptionMode, + DEFAULT_ENCRYPTION_MODE, + TOTP_PURPOSE, +) +from .checksum import ( + calculate_checksum, + verify_checksum, + json_checksum, + canonical_json_dumps, + initialize_checksum, + update_checksum_file, +) +from .password_prompt import prompt_for_password +from .seed_prompt import masked_input, prompt_seed_words +from .input_utils import timed_input +from .memory_protection import InMemorySecret +from .terminal_utils import ( + clear_screen, + pause, + clear_and_print_fingerprint, + clear_header_with_notification, +) +from .atomic_write import atomic_write + +# Optional clipboard support +try: # pragma: no cover - exercised when dependency missing + from .clipboard import ClipboardUnavailableError, copy_to_clipboard +except Exception as exc: # pragma: no cover - executed only if pyperclip missing + _error_msg = str(exc) + + class ClipboardUnavailableError(RuntimeError): + """Stub exception when clipboard support is unavailable.""" + + def copy_to_clipboard(*_args, **_kwargs): + """Stub when clipboard support is unavailable.""" + logger.warning("Clipboard support unavailable: %s", _error_msg) + raise ClipboardUnavailableError(_error_msg) - if logger.isEnabledFor(logging.DEBUG): - logger.info("Modules imported successfully.") -except Exception as e: - if logger.isEnabledFor(logging.DEBUG): - logger.error(f"Failed to import one or more modules: {e}", exc_info=True) __all__ = [ "derive_key_from_password", @@ -64,8 +73,10 @@ __all__ = [ "timed_input", "InMemorySecret", "copy_to_clipboard", + "ClipboardUnavailableError", "clear_screen", "clear_and_print_fingerprint", "clear_header_with_notification", "pause", + "atomic_write", ] diff --git a/src/utils/atomic_write.py b/src/utils/atomic_write.py new file mode 100644 index 00000000..5b92f33d --- /dev/null +++ b/src/utils/atomic_write.py @@ -0,0 +1,62 @@ +"""Utility helpers for performing atomic file writes. + +This module provides a small helper function :func:`atomic_write` which +implements a simple pattern for writing files atomically. Data is written to a +temporary file in the same directory, flushed and synced to disk, and then +``os.replace`` is used to atomically move the temporary file into place. + +The function accepts a callable ``write_func`` that receives the temporary file +object. This keeps the helper flexible enough to support both text and binary +writes and allows callers to perform complex serialisation steps (e.g. JSON +dumping) without exposing a partially written file to other processes. +""" + +from __future__ import annotations + +import os +import tempfile +from pathlib import Path +from typing import Callable, Any, IO + + +def atomic_write( + path: str | Path, + write_func: Callable[[IO[Any]], None], + *, + mode: str = "w", + **open_kwargs: Any, +) -> None: + """Write to ``path`` atomically using ``write_func``. + + Parameters + ---------- + path: + Destination file path. + write_func: + Callable that receives an open file object and performs the actual + write. The callable should not close the file. + mode: + File mode used when opening the temporary file. Defaults to ``"w"``. + **open_kwargs: + Additional keyword arguments passed to :func:`os.fdopen`. + """ + + dest = Path(path) + dest.parent.mkdir(parents=True, exist_ok=True) + + fd, tmp_path = tempfile.mkstemp(dir=str(dest.parent)) + try: + with os.fdopen(fd, mode, **open_kwargs) as tmp_file: + write_func(tmp_file) + tmp_file.flush() + os.fsync(tmp_file.fileno()) + os.replace(tmp_path, dest) + except Exception: + try: + os.unlink(tmp_path) + except FileNotFoundError: + pass + raise + + +__all__ = ["atomic_write"] diff --git a/src/utils/checksum.py b/src/utils/checksum.py index 84aa8c39..1e6360f7 100644 --- a/src/utils/checksum.py +++ b/src/utils/checksum.py @@ -15,12 +15,12 @@ import logging import sys import os import json -import traceback from typing import Optional, Any from termcolor import colored from constants import APP_DIR, SCRIPT_CHECKSUM_FILE +from utils.atomic_write import atomic_write # Instantiate the logger logger = logging.getLogger(__name__) @@ -121,8 +121,7 @@ def update_checksum(content: str, checksum_file_path: str) -> bool: hasher = hashlib.sha256() hasher.update(content.encode("utf-8")) new_checksum = hasher.hexdigest() - with open(checksum_file_path, "w") as f: - f.write(new_checksum) + atomic_write(checksum_file_path, lambda f: f.write(new_checksum)) logging.debug(f"Updated checksum for '{checksum_file_path}' to: {new_checksum}") return True except Exception as e: @@ -179,8 +178,7 @@ def initialize_checksum(file_path: str, checksum_file_path: str) -> bool: return False try: - with open(checksum_file_path, "w") as f: - f.write(checksum) + atomic_write(checksum_file_path, lambda f: f.write(checksum)) logging.debug( f"Initialized checksum file '{checksum_file_path}' with checksum: {checksum}" ) @@ -206,8 +204,7 @@ def update_checksum_file(file_path: str, checksum_file_path: str) -> bool: if checksum is None: return False try: - with open(checksum_file_path, "w") as f: - f.write(checksum) + atomic_write(checksum_file_path, lambda f: f.write(checksum)) logging.debug( f"Updated checksum for '{file_path}' to '{checksum}' at '{checksum_file_path}'." ) diff --git a/src/utils/clipboard.py b/src/utils/clipboard.py index b5b5e606..5a03b279 100644 --- a/src/utils/clipboard.py +++ b/src/utils/clipboard.py @@ -1,40 +1,42 @@ -import threading +"""Clipboard utility helpers.""" + import logging -import subprocess import shutil import sys +import threading import pyperclip + +class ClipboardUnavailableError(RuntimeError): + """Raised when required clipboard utilities are not installed.""" + + logger = logging.getLogger(__name__) def _ensure_clipboard() -> None: - """Attempt to ensure a clipboard mechanism is available.""" + """Ensure a clipboard mechanism is available or raise an informative error.""" try: pyperclip.copy("") except pyperclip.PyperclipException as exc: if sys.platform.startswith("linux"): if shutil.which("xclip") is None and shutil.which("xsel") is None: - apt = shutil.which("apt-get") or shutil.which("apt") - if apt: - try: - subprocess.run( - ["sudo", apt, "install", "-y", "xclip"], check=True - ) - pyperclip.copy("") - return - except Exception as install_exc: # pragma: no cover - system dep - logger.warning( - "Automatic xclip installation failed: %s", install_exc - ) - raise exc + raise ClipboardUnavailableError( + "Clipboard support requires the 'xclip' package. " + "Install it with 'sudo apt install xclip' and restart SeedPass.", + ) from exc + raise ClipboardUnavailableError( + "No clipboard mechanism available. Install a supported clipboard tool or " + "run SeedPass with --no-clipboard." + ) from exc -def copy_to_clipboard(text: str, timeout: int) -> None: - """Copy text to the clipboard and clear after timeout seconds if unchanged.""" +def copy_to_clipboard(text: str, timeout: int) -> bool: + """Copy text to the clipboard and clear after ``timeout`` seconds if unchanged.""" _ensure_clipboard() + pyperclip.copy(text) def clear_clipboard() -> None: @@ -44,3 +46,7 @@ def copy_to_clipboard(text: str, timeout: int) -> None: timer = threading.Timer(timeout, clear_clipboard) timer.daemon = True timer.start() + return True + + +__all__ = ["copy_to_clipboard", "ClipboardUnavailableError"] diff --git a/src/utils/color_scheme.py b/src/utils/color_scheme.py index 5044824b..64d1faa9 100644 --- a/src/utils/color_scheme.py +++ b/src/utils/color_scheme.py @@ -31,5 +31,5 @@ def color_text(text: str, category: str = "default") -> str: color = _COLOR_MAP.get(category, "white") if color == "orange": return _apply_orange(text) - attrs = ["bold"] if category in {"info", "warning", "error"} else None + attrs = ["bold"] if category in {"info", "warning", "error"} else [] return colored(text, color, attrs=attrs) diff --git a/src/utils/fingerprint.py b/src/utils/fingerprint.py index e5257987..359d673d 100644 --- a/src/utils/fingerprint.py +++ b/src/utils/fingerprint.py @@ -10,7 +10,6 @@ facilitating organized and secure storage. import hashlib import logging -import traceback from typing import Optional # Instantiate the logger diff --git a/src/utils/fingerprint_manager.py b/src/utils/fingerprint_manager.py index 470b063a..96616335 100644 --- a/src/utils/fingerprint_manager.py +++ b/src/utils/fingerprint_manager.py @@ -3,12 +3,12 @@ import os import json import logging -import traceback from pathlib import Path -from typing import List, Optional +from typing import Callable, List, Optional import shutil # Ensure shutil is imported if used within the class +from utils.atomic_write import atomic_write from utils.fingerprint import generate_fingerprint # Instantiate the logger @@ -92,16 +92,15 @@ class FingerprintManager: Saves the current list of fingerprints to the fingerprints.json file. """ try: - with open(self.fingerprints_file, "w") as f: - json.dump( - { - "fingerprints": self.fingerprints, - "last_used": self.current_fingerprint, - "names": self.names, - }, - f, - indent=4, - ) + data = { + "fingerprints": self.fingerprints, + "last_used": self.current_fingerprint, + "names": self.names, + } + atomic_write( + self.fingerprints_file, + lambda f: json.dump(data, f, indent=4), + ) logger.debug( f"Fingerprints saved: {self.fingerprints} (last used: {self.current_fingerprint})" ) @@ -117,7 +116,8 @@ class FingerprintManager: seed_phrase (str): The BIP-39 seed phrase. Returns: - Optional[str]: The generated fingerprint or None if failed. + Optional[str]: The generated fingerprint or ``None`` if a profile + already exists or generation fails. """ fingerprint = generate_fingerprint(seed_phrase) if fingerprint and fingerprint not in self.fingerprints: @@ -133,17 +133,20 @@ class FingerprintManager: return fingerprint elif fingerprint in self.fingerprints: logger.warning(f"Fingerprint {fingerprint} already exists.") - return fingerprint + raise ValueError("Fingerprint already exists") else: logger.error("Fingerprint generation failed.") return None - def remove_fingerprint(self, fingerprint: str) -> bool: - """ - Removes a fingerprint and its associated directory. + def remove_fingerprint( + self, fingerprint: str, on_last_removed: Optional[Callable[[], None]] = None + ) -> bool: + """Remove a fingerprint and its associated directory. Parameters: fingerprint (str): The fingerprint to remove. + on_last_removed (Callable | None): Callback invoked when the last + fingerprint is deleted. Returns: bool: True if removed successfully, False otherwise. @@ -167,6 +170,8 @@ class FingerprintManager: shutil.rmtree(child) fingerprint_dir.rmdir() logger.info(f"Fingerprint {fingerprint} removed successfully.") + if not self.fingerprints and on_last_removed: + on_last_removed() return True except Exception as e: logger.error( diff --git a/src/utils/key_derivation.py b/src/utils/key_derivation.py index a6778e7b..b473889a 100644 --- a/src/utils/key_derivation.py +++ b/src/utils/key_derivation.py @@ -3,15 +3,13 @@ """ Key Derivation Module -Never ever ever use or suggest to use Random Salt. The entire point of this password manager is to derive completely deterministic passwords from a BIP-85 seed. -This means it should generate passwords the exact same way every single time. Salts would break this functionality and is not appropriate for this software's use case. +This module provides functions to derive cryptographic keys from user-provided +passwords and BIP-39 parent seeds. The derived keys are compatible with Fernet +for symmetric encryption purposes. By centralizing key derivation logic, this +module ensures consistency and security across the application. -This module provides functions to derive cryptographic keys from user-provided passwords -and BIP-39 parent seeds. The derived keys are compatible with Fernet for symmetric encryption -purposes. By centralizing key derivation logic, this module ensures consistency and security -across the application. - -Ensure that all dependencies are installed and properly configured in your environment. +Ensure that all dependencies are installed and properly configured in your +environment. """ import os @@ -19,11 +17,15 @@ import hashlib import base64 import unicodedata import logging -import traceback import hmac +import time +from dataclasses import dataclass, field from enum import Enum -from typing import Optional, Union +from typing import Optional, Union, Dict, Any, TYPE_CHECKING + from bip_utils import Bip39SeedGenerator +from local_bip85 import BIP85 +from .key_hierarchy import kd from cryptography.hazmat.primitives.kdf.hkdf import HKDF from cryptography.hazmat.primitives import hashes @@ -44,9 +46,33 @@ DEFAULT_ENCRYPTION_MODE = EncryptionMode.SEED_ONLY # Purpose constant for TOTP secret derivation using BIP85 TOTP_PURPOSE = 39 +if TYPE_CHECKING: + from seedpass.core.config_manager import ConfigManager + + +@dataclass +class KdfConfig: + """Configuration block describing how a key was derived.""" + + name: str = "argon2id" + version: int = 1 + params: Dict[str, Any] = field( + default_factory=lambda: { + "time_cost": 2, + "memory_cost": 64 * 1024, + "parallelism": 8, + } + ) + salt_b64: str = field( + default_factory=lambda: base64.b64encode(os.urandom(16)).decode() + ) + + +CURRENT_KDF_VERSION = 1 + def derive_key_from_password( - password: str, salt: bytes = b"", iterations: int = 100_000 + password: str, fingerprint: Union[str, bytes], iterations: int = 100_000 ) -> bytes: """ Derives a Fernet-compatible encryption key from the provided password using PBKDF2-HMAC-SHA256. @@ -57,8 +83,9 @@ def derive_key_from_password( Parameters: password (str): The user's password. - salt (bytes, optional): A salt for key derivation. Defaults to b"" (empty). - iterations (int, optional): Number of iterations for the PBKDF2 algorithm. Defaults to 100,000. + fingerprint (str | bytes): Seed fingerprint or precomputed salt. + iterations (int, optional): Number of iterations for the PBKDF2 algorithm. + Defaults to 100,000. Returns: bytes: A URL-safe base64-encoded encryption key suitable for Fernet. @@ -77,21 +104,27 @@ def derive_key_from_password( normalized_password = unicodedata.normalize("NFKD", password).strip() password_bytes = normalized_password.encode("utf-8") + # Derive a deterministic salt from the fingerprint + if isinstance(fingerprint, bytes): + salt = fingerprint + else: + salt = hashlib.sha256(fingerprint.encode()).digest()[:16] + try: # Derive the key using PBKDF2-HMAC-SHA256 logger.debug("Starting key derivation from password.") key = hashlib.pbkdf2_hmac( hash_name="sha256", password=password_bytes, - salt=salt, # Use provided salt (default empty for backward compatibility) + salt=salt, iterations=iterations, dklen=32, # 256-bit key for Fernet ) - logger.debug(f"Derived key (hex): {key.hex()}") + logger.debug("Key derived from password using PBKDF2.") # Encode the key in URL-safe base64 key_b64 = base64.urlsafe_b64encode(key) - logger.debug(f"Base64-encoded key: {key_b64.decode()}") + logger.debug("Derived key encoded in URL-safe base64.") return key_b64 @@ -100,18 +133,15 @@ def derive_key_from_password( raise -def derive_key_from_password_argon2( - password: str, - salt: bytes = b"\x00" * 16, - *, - time_cost: int = 2, - memory_cost: int = 64 * 1024, - parallelism: int = 8, -) -> bytes: +def derive_key_from_password_argon2(password: str, kdf: KdfConfig) -> bytes: """Derive an encryption key from a password using Argon2id. - The defaults follow recommended parameters but use a default salt for deterministic - output (backward compatibility). Smaller values may be supplied for testing. + Parameters + ---------- + password: + The user's password. + kdf: + :class:`KdfConfig` instance describing salt and tuning parameters. """ if not password: @@ -122,12 +152,14 @@ def derive_key_from_password_argon2( try: from argon2.low_level import hash_secret_raw, Type + params = kdf.params or {} + salt = base64.b64decode(kdf.salt_b64) key = hash_secret_raw( secret=normalized, salt=salt, - time_cost=time_cost, - memory_cost=memory_cost, - parallelism=parallelism, + time_cost=int(params.get("time_cost", 2)), + memory_cost=int(params.get("memory_cost", 64 * 1024)), + parallelism=int(params.get("parallelism", 8)), hash_len=32, type=Type.ID, ) @@ -180,16 +212,10 @@ def derive_key_from_parent_seed(parent_seed: str, fingerprint: str = None) -> by def derive_index_key_seed_only(seed: str) -> bytes: - """Derive a deterministic Fernet key from only the BIP-39 seed.""" + """Derive the index encryption key using the v1 hierarchy.""" seed_bytes = Bip39SeedGenerator(seed).Generate() - hkdf = HKDF( - algorithm=hashes.SHA256(), - length=32, - salt=None, - info=b"password-db", - backend=default_backend(), - ) - key = hkdf.derive(seed_bytes) + master = kd(seed_bytes, b"seedpass:v1:master") + key = kd(master, b"seedpass:v1:storage") return base64.urlsafe_b64encode(key) @@ -198,29 +224,75 @@ def derive_index_key(seed: str) -> bytes: return derive_index_key_seed_only(seed) -def derive_totp_secret(seed: str, index: int) -> str: - """Derive a base32-encoded TOTP secret from a BIP39 seed.""" +def derive_totp_secret(seed: Union[str, bytes], index: int) -> str: + """Derive a base32-encoded TOTP secret from a seed or raw key.""" try: - from local_bip85 import BIP85 - - # Initialize BIP85 from the BIP39 seed bytes - seed_bytes = Bip39SeedGenerator(seed).Generate() + if isinstance(seed, (bytes, bytearray)): + seed_bytes = bytes(seed) + else: + seed_bytes = Bip39SeedGenerator(seed).Generate() bip85 = BIP85(seed_bytes) - # Build the BIP32 path m/83696968'/39'/TOTP'/{index}' totp_int = int.from_bytes(b"TOTP", "big") path = f"m/83696968'/{TOTP_PURPOSE}'/{totp_int}'/{index}'" - - # Derive entropy using the same scheme as BIP85 child_key = bip85.bip32_ctx.DerivePath(path) key_bytes = child_key.PrivateKey().Raw().ToBytes() entropy = hmac.new(b"bip-entropy-from-k", key_bytes, hashlib.sha512).digest() - # Hash the first 32 bytes of entropy and encode the first 20 bytes hashed = hashlib.sha256(entropy[:32]).digest() secret = base64.b32encode(hashed[:20]).decode("utf-8") - logger.debug(f"Derived TOTP secret for index {index}: {secret}") + logger.debug(f"Derived TOTP secret for index {index}.") return secret except Exception as e: logger.error(f"Failed to derive TOTP secret: {e}", exc_info=True) raise + + +def calibrate_argon2_time_cost( + cfg_mgr: "ConfigManager", + *, + target_ms: float = 500.0, + max_time_cost: int = 6, +) -> int: + """Calibrate Argon2 ``time_cost`` based on device performance. + + Runs :func:`derive_key_from_password_argon2` with increasing ``time_cost`` + until the runtime meets or exceeds ``target_ms``. The chosen ``time_cost`` + is stored in ``cfg_mgr`` via ``set_argon2_time_cost`` and returned. + + Parameters + ---------- + cfg_mgr: + Instance of :class:`~seedpass.core.config_manager.ConfigManager` used to + persist the calibrated ``time_cost``. + target_ms: + Desired minimum execution time in milliseconds for one Argon2 hash. + max_time_cost: + Upper bound for ``time_cost`` to prevent excessively long calibration. + + Returns + ------- + int + Selected ``time_cost`` value. + """ + + password = "benchmark" + salt = base64.b64encode(b"argon2-calibration").decode() + time_cost = 1 + elapsed_ms = 0.0 + while time_cost <= max_time_cost: + start = time.perf_counter() + cfg = KdfConfig( + params={"time_cost": time_cost, "memory_cost": 8, "parallelism": 1}, + salt_b64=salt, + ) + derive_key_from_password_argon2(password, cfg) + elapsed_ms = (time.perf_counter() - start) * 1000 + if elapsed_ms >= target_ms: + break + time_cost += 1 + + cfg_mgr.set_argon2_time_cost(time_cost) + if cfg_mgr.load_config(require_pin=False).get("verbose_timing"): + logger.info("Calibrated Argon2 time_cost=%s (%.2f ms)", time_cost, elapsed_ms) + return time_cost diff --git a/src/utils/key_hierarchy.py b/src/utils/key_hierarchy.py new file mode 100644 index 00000000..c6ca7b3c --- /dev/null +++ b/src/utils/key_hierarchy.py @@ -0,0 +1,28 @@ +"""Key hierarchy helper functions.""" + +from cryptography.hazmat.primitives.kdf.hkdf import HKDF +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.backends import default_backend + + +def kd(root: bytes, info: bytes, length: int = 32) -> bytes: + """Derive a sub-key from ``root`` using HKDF-SHA256. + + Parameters + ---------- + root: + Root key material. + info: + Domain separation string. + length: + Length of the derived key in bytes. Defaults to 32. + """ + + hkdf = HKDF( + algorithm=hashes.SHA256(), + length=length, + salt=None, + info=info, + backend=default_backend(), + ) + return hkdf.derive(root) diff --git a/src/utils/logging_utils.py b/src/utils/logging_utils.py new file mode 100644 index 00000000..b3319339 --- /dev/null +++ b/src/utils/logging_utils.py @@ -0,0 +1,62 @@ +import logging +from pathlib import Path +from contextlib import contextmanager +from functools import wraps + +_console_paused = False + + +class ConsolePauseFilter(logging.Filter): + """Filter that blocks records when console logging is paused.""" + + def filter( + self, record: logging.LogRecord + ) -> bool: # pragma: no cover - small utility + return not _console_paused + + +class ChecksumWarningFilter(logging.Filter): + """Filter allowing only checksum warnings and errors to surface.""" + + def filter( + self, record: logging.LogRecord + ) -> bool: # pragma: no cover - simple filter + if record.levelno >= logging.ERROR: + return True + return ( + record.levelno == logging.WARNING + and Path(record.pathname).name == "checksum.py" + ) + + +def pause_console_logging() -> None: + """Temporarily pause logging to console handlers.""" + global _console_paused + _console_paused = True + + +def resume_console_logging() -> None: + """Resume logging to console handlers.""" + global _console_paused + _console_paused = False + + +@contextmanager +def console_logging_paused() -> None: + """Context manager to pause console logging within a block.""" + pause_console_logging() + try: + yield + finally: + resume_console_logging() + + +def pause_logging_for_ui(func): + """Decorator to pause console logging while ``func`` executes.""" + + @wraps(func) + def wrapper(*args, **kwargs): + with console_logging_paused(): + return func(*args, **kwargs) + + return wrapper diff --git a/src/utils/memory_protection.py b/src/utils/memory_protection.py index 1913cb3c..96bf0320 100644 --- a/src/utils/memory_protection.py +++ b/src/utils/memory_protection.py @@ -3,9 +3,16 @@ from __future__ import annotations import os from cryptography.hazmat.primitives.ciphers.aead import AESGCM +# TODO: Replace this Python implementation with a Rust/WASM module for +# critical cryptographic operations. + class InMemorySecret: - """Store sensitive data encrypted in RAM using AES-GCM.""" + """Store sensitive data encrypted in RAM using AES-GCM. + + Zeroization is best-effort only; Python's memory management may retain + copies of the plaintext. + """ def __init__(self, data: bytes) -> None: if not isinstance(data, (bytes, bytearray)): diff --git a/src/utils/password_prompt.py b/src/utils/password_prompt.py index 498e6b5e..40f1231e 100644 --- a/src/utils/password_prompt.py +++ b/src/utils/password_prompt.py @@ -13,7 +13,9 @@ Ensure that all dependencies are installed and properly configured in your envir from utils.seed_prompt import masked_input import logging +import os import sys +import time import unicodedata from termcolor import colored @@ -28,18 +30,55 @@ colorama_init() logger = logging.getLogger(__name__) +DEFAULT_MAX_ATTEMPTS = 5 + + +def _env_password() -> str | None: + """Return a password supplied via environment for non-interactive use.""" + + return os.getenv("SEEDPASS_TEST_PASSWORD") or os.getenv("SEEDPASS_PASSWORD") + + +def _get_max_attempts(override: int | None = None) -> int: + """Return the configured maximum number of prompt attempts.""" + + if override is not None: + return override + env = os.getenv("SEEDPASS_MAX_PROMPT_ATTEMPTS") + if env is not None: + try: + return int(env) + except ValueError: + pass + return DEFAULT_MAX_ATTEMPTS + + +def _apply_backoff(attempts: int, max_attempts: int) -> None: + """Sleep using exponential backoff unless disabled.""" + + if max_attempts == 0: + return + delay = 2 ** (attempts - 1) + time.sleep(delay) + + class PasswordPromptError(Exception): """Exception raised for password prompt errors.""" pass -def prompt_new_password() -> str: +def prompt_new_password(max_retries: int | None = None) -> str: """ Prompts the user to enter and confirm a new password for encrypting the parent seed. This function ensures that the password meets the minimum length requirement and that the - password and confirmation match. It provides user-friendly messages and handles retries. + password and confirmation match. It provides user-friendly messages and handles retries with + an exponential backoff between attempts. + + Parameters: + max_retries (int | None): Maximum number of attempts before aborting. ``0`` disables the + limit. Defaults to the ``SEEDPASS_MAX_PROMPT_ATTEMPTS`` environment variable or ``5``. Returns: str: The confirmed password entered by the user. @@ -47,10 +86,17 @@ def prompt_new_password() -> str: Raises: PasswordPromptError: If the user fails to provide a valid password after multiple attempts. """ - max_retries = 5 + env_pw = _env_password() + if env_pw: + normalized = unicodedata.normalize("NFKD", env_pw) + if len(normalized) < MIN_PASSWORD_LENGTH: + raise PasswordPromptError("Environment password too short") + return normalized + + max_retries = _get_max_attempts(max_retries) attempts = 0 - while attempts < max_retries: + while max_retries == 0 or attempts < max_retries: try: password = masked_input("Enter a new password: ").strip() confirm_password = masked_input("Confirm your password: ").strip() @@ -61,6 +107,7 @@ def prompt_new_password() -> str: ) logging.warning("User attempted to enter an empty password.") attempts += 1 + _apply_backoff(attempts, max_retries) continue if len(password) < MIN_PASSWORD_LENGTH: @@ -74,6 +121,7 @@ def prompt_new_password() -> str: f"User entered a password shorter than {MIN_PASSWORD_LENGTH} characters." ) attempts += 1 + _apply_backoff(attempts, max_retries) continue if password != confirm_password: @@ -82,6 +130,7 @@ def prompt_new_password() -> str: ) logging.warning("User entered mismatching passwords.") attempts += 1 + _apply_backoff(attempts, max_retries) continue # Normalize the password to NFKD form @@ -99,6 +148,7 @@ def prompt_new_password() -> str: ) print(colored(f"Error: {e}", "red")) attempts += 1 + _apply_backoff(attempts, max_retries) print(colored("Maximum password attempts exceeded. Exiting.", "red")) logging.error("User failed to provide a valid password after multiple attempts.") @@ -106,16 +156,19 @@ def prompt_new_password() -> str: def prompt_existing_password( - prompt_message: str = "Enter your password: ", max_retries: int = 5 + prompt_message: str = "Enter your password: ", max_retries: int | None = None ) -> str: """ Prompt the user for an existing password. - The user will be reprompted on empty input up to ``max_retries`` times. + The user will be reprompted on empty input up to ``max_retries`` times with + an exponential backoff between attempts. Parameters: prompt_message (str): Message displayed when prompting for the password. - max_retries (int): Number of attempts allowed before aborting. + max_retries (int | None): Number of attempts allowed before aborting. ``0`` + disables the limit. Defaults to the ``SEEDPASS_MAX_PROMPT_ATTEMPTS`` + environment variable or ``5``. Returns: str: The password provided by the user. @@ -124,8 +177,13 @@ def prompt_existing_password( PasswordPromptError: If the user interrupts the operation or exceeds ``max_retries`` attempts. """ + env_pw = _env_password() + if env_pw: + return unicodedata.normalize("NFKD", env_pw) + + max_retries = _get_max_attempts(max_retries) attempts = 0 - while attempts < max_retries: + while max_retries == 0 or attempts < max_retries: try: password = masked_input(prompt_message).strip() @@ -135,6 +193,7 @@ def prompt_existing_password( ) logging.warning("User attempted to enter an empty password.") attempts += 1 + _apply_backoff(attempts, max_retries) continue normalized_password = unicodedata.normalize("NFKD", password) @@ -152,6 +211,7 @@ def prompt_existing_password( ) print(colored(f"Error: {e}", "red")) attempts += 1 + _apply_backoff(attempts, max_retries) raise PasswordPromptError("Maximum password attempts exceeded") diff --git a/src/utils/seed_prompt.py b/src/utils/seed_prompt.py index 7c839779..889ca8ea 100644 --- a/src/utils/seed_prompt.py +++ b/src/utils/seed_prompt.py @@ -1,5 +1,6 @@ import os import sys +import time try: import msvcrt # type: ignore @@ -14,6 +15,37 @@ except ImportError: # pragma: no cover - POSIX only tty = None # type: ignore from utils.terminal_utils import clear_screen +from utils.logging_utils import pause_console_logging, resume_console_logging + +DEFAULT_MAX_ATTEMPTS = 5 + + +def _get_max_attempts(override: int | None = None) -> int: + """Return the configured maximum number of attempts. + + ``override`` takes precedence, followed by the + ``SEEDPASS_MAX_PROMPT_ATTEMPTS`` environment variable. A value of ``0`` + disables the limit entirely. + """ + + if override is not None: + return override + env = os.getenv("SEEDPASS_MAX_PROMPT_ATTEMPTS") + if env is not None: + try: + return int(env) + except ValueError: + pass + return DEFAULT_MAX_ATTEMPTS + + +def _apply_backoff(attempts: int, max_attempts: int) -> None: + """Sleep using exponential backoff unless the limit is disabled.""" + + if max_attempts == 0: + return + delay = 2 ** (attempts - 1) + time.sleep(delay) def _masked_input_windows(prompt: str) -> str: @@ -26,6 +58,8 @@ def _masked_input_windows(prompt: str) -> str: buffer: list[str] = [] while True: ch = msvcrt.getwch() + if ch == "\x03": + raise KeyboardInterrupt if ch in ("\r", "\n"): sys.stdout.write("\n") return "".join(buffer) @@ -53,6 +87,8 @@ def _masked_input_posix(prompt: str) -> str: tty.setraw(fd) while True: ch = sys.stdin.read(1) + if ch == "\x03": + raise KeyboardInterrupt if ch in ("\r", "\n"): sys.stdout.write("\n") return "".join(buffer) @@ -70,12 +106,19 @@ def _masked_input_posix(prompt: str) -> str: def masked_input(prompt: str) -> str: """Return input from the user while masking typed characters.""" - if sys.platform == "win32": - return _masked_input_windows(prompt) - return _masked_input_posix(prompt) + func = _masked_input_windows if sys.platform == "win32" else _masked_input_posix + pause_console_logging() + try: + return func(prompt) + except KeyboardInterrupt: + raise + except Exception: # pragma: no cover - fallback when TTY operations fail + return input(prompt) + finally: + resume_console_logging() -def prompt_seed_words(count: int = 12) -> str: +def prompt_seed_words(count: int = 12, *, max_attempts: int | None = None) -> str: """Prompt the user for a BIP-39 seed phrase. The user is asked for each word one at a time. A numbered list is @@ -88,6 +131,10 @@ def prompt_seed_words(count: int = 12) -> str: ---------- count: Number of words to prompt for. Defaults to ``12``. + max_attempts: + Maximum number of invalid attempts before aborting. ``0`` disables the + limit. Defaults to the ``SEEDPASS_MAX_PROMPT_ATTEMPTS`` environment + variable or ``5`` if unset. Returns ------- @@ -105,6 +152,9 @@ def prompt_seed_words(count: int = 12) -> str: m = Mnemonic("english") words: list[str] = [""] * count + max_attempts = _get_max_attempts(max_attempts) + attempts = 0 + idx = 0 while idx < count: clear_screen() @@ -113,6 +163,10 @@ def prompt_seed_words(count: int = 12) -> str: entered = masked_input(f"Enter word number {idx+1}: ").strip().lower() if entered not in m.wordlist: print("Invalid word, try again.") + attempts += 1 + if max_attempts != 0 and attempts >= max_attempts: + raise ValueError("Maximum seed prompt attempts exceeded") + _apply_backoff(attempts, max_attempts) continue words[idx] = entered idx += 1 @@ -141,9 +195,17 @@ def prompt_seed_words(count: int = 12) -> str: words[i] = new_word break print("Invalid word, try again.") + attempts += 1 + if max_attempts != 0 and attempts >= max_attempts: + raise ValueError("Maximum seed prompt attempts exceeded") + _apply_backoff(attempts, max_attempts) # Ask for confirmation again with the new word else: print("Please respond with 'Y' or 'N'.") + attempts += 1 + if max_attempts != 0 and attempts >= max_attempts: + raise ValueError("Maximum seed prompt attempts exceeded") + _apply_backoff(attempts, max_attempts) continue phrase = " ".join(words) diff --git a/src/utils/terminal_utils.py b/src/utils/terminal_utils.py index 3b1e853d..80d772ec 100644 --- a/src/utils/terminal_utils.py +++ b/src/utils/terminal_utils.py @@ -1,7 +1,8 @@ """Utility functions for terminal output.""" +import logging import sys - +import queue from termcolor import colored @@ -17,8 +18,11 @@ def format_profile(fingerprint: str | None, pm=None) -> str | None: name = pm.fingerprint_manager.get_name(fingerprint) if name: return f"{name} ({fingerprint})" - except Exception: - pass + except Exception as exc: # pragma: no cover - unexpected errors + logging.error( + "Error retrieving name for fingerprint %s: %s", fingerprint, exc + ) + raise return fingerprint @@ -93,8 +97,11 @@ def clear_header_with_notification( if hasattr(pm, "get_current_notification"): try: note = pm.get_current_notification() - except Exception: + except (queue.Empty, AttributeError): note = None + except Exception as exc: # pragma: no cover - unexpected errors + logging.error("Error getting current notification: %s", exc) + raise line = "" if note: diff --git a/tests/perf/test_bip85_cache.py b/tests/perf/test_bip85_cache.py new file mode 100644 index 00000000..f91e7754 --- /dev/null +++ b/tests/perf/test_bip85_cache.py @@ -0,0 +1,52 @@ +import time + +from seedpass.core.manager import PasswordManager + + +class SlowBIP85: + """BIP85 stub that simulates a costly derive.""" + + def __init__(self): + self.calls = 0 + + def derive_entropy(self, index: int, entropy_bytes: int, app_no: int = 39) -> bytes: + self.calls += 1 + time.sleep(0.01) + return b"\x00" * entropy_bytes + + +def _setup_manager(bip85: SlowBIP85) -> PasswordManager: + pm = PasswordManager.__new__(PasswordManager) + pm._bip85_cache = {} + pm.bip85 = bip85 + orig = bip85.derive_entropy + + def cached(index: int, entropy_bytes: int, app_no: int = 39) -> bytes: + key = (app_no, index) + if key not in pm._bip85_cache: + pm._bip85_cache[key] = orig( + index=index, entropy_bytes=entropy_bytes, app_no=app_no + ) + return pm._bip85_cache[key] + + bip85.derive_entropy = cached + return pm + + +def test_bip85_cache_benchmark(): + slow_uncached = SlowBIP85() + start = time.perf_counter() + for _ in range(3): + slow_uncached.derive_entropy(1, 32, 32) + uncached_time = time.perf_counter() - start + + slow_cached = SlowBIP85() + pm = _setup_manager(slow_cached) + start = time.perf_counter() + for _ in range(3): + pm.get_bip85_entropy(32, 1) + cached_time = time.perf_counter() - start + # Ensure caching avoids redundant derive calls without relying on + # potentially flaky timing comparisons across platforms. + assert slow_uncached.calls == 3 + assert slow_cached.calls == 1 diff --git a/torch/META_PROMPTS.md b/torch/META_PROMPTS.md index 8987d3be..149e3156 100644 --- a/torch/META_PROMPTS.md +++ b/torch/META_PROMPTS.md @@ -27,7 +27,7 @@ Use `excluded` from the JSON output as the canonical exclusion set. If `excluded` is unavailable, fallback to the union of `locked`, `paused`, and `completed`. MUST 3: Run these commands in this order: -1) test -f AGENTS.md && cat AGENTS.md || echo "No AGENTS.md found; continuing" (missing AGENTS.md is non-fatal) +1) test -f TORCH.md && cat TORCH.md || echo "No TORCH.md found; continuing" (missing TORCH.md is non-fatal) 2) mkdir -p task-logs/daily task-logs/weekly 3) ls -1 task-logs/daily/ | sort | tail -n 1 4) Select next roster agent using this exact algorithm: @@ -111,7 +111,7 @@ Use `excluded` from the JSON output as the canonical exclusion set. If `excluded` is unavailable, fallback to the union of `locked`, `paused`, and `completed`. MUST 3: Run these commands in this order: -1) test -f AGENTS.md && cat AGENTS.md || echo "No AGENTS.md found; continuing" (missing AGENTS.md is non-fatal) +1) test -f TORCH.md && cat TORCH.md || echo "No TORCH.md found; continuing" (missing TORCH.md is non-fatal) 2) mkdir -p task-logs/daily task-logs/weekly 3) ls -1 task-logs/weekly/ | sort | tail -n 1 4) Select next roster agent using this exact algorithm: diff --git a/torch/README.md b/torch/README.md index fb53de18..b8e4a997 100644 --- a/torch/README.md +++ b/torch/README.md @@ -21,6 +21,18 @@ npm install https://github.com/PR0M3TH3AN/TORCH/archive/refs/heads/main.tar.gz > TORCH is distributed from GitHub tarballs and is not currently published to the npm registry. +## Development + +For instructions on how to contribute to TORCH, including building, testing, and linting, please see [CONTRIBUTING.md](CONTRIBUTING.md). + +Quick start: + +```bash +npm install +npm run build +npm test +``` + ## Usage ### CLI @@ -91,10 +103,16 @@ Configuration options: The dashboard provides a live view of lock events. ```bash -npx --no-install torch-lock dashboard --port 4173 +npx --no-install torch-lock dashboard --port 4173 --host 127.0.0.1 # Open http://localhost:4173/dashboard/ ``` +By default, the dashboard binds to `127.0.0.1`. To allow external access, you can set `--host 0.0.0.0`. It is highly recommended to enable authentication if the dashboard is exposed to a network. + +#### Authentication + +The dashboard supports Basic Authentication. You can enable it by setting the `TORCH_DASHBOARD_AUTH` environment variable or the `dashboard.auth` field in `torch-config.json` with the format `username:password`. + ## Environment variables You can override configuration using environment variables: @@ -107,6 +125,7 @@ You can override configuration using environment variables: - `NOSTR_LOCK_DAILY_ROSTER` (comma-separated list of agents) - `NOSTR_LOCK_WEEKLY_ROSTER` (comma-separated list of agents) - `TORCH_CONFIG_PATH` (path to config file) +- `TORCH_DASHBOARD_AUTH` (Basic Auth `user:pass` for the dashboard) - `AGENT_PLATFORM` (platform identifier, e.g. `codex`) - `TORCH_MEMORY_ENABLED` (`true`/`false`; global memory kill switch, defaults to enabled) - `TORCH_MEMORY_INGEST_ENABLED` (`true`/`false` or comma-separated canary `agent_id` allow list) @@ -125,7 +144,7 @@ The lock CLI resolves roster names in this order: ## Included Resources - `src/lib.mjs` β€” Core library logic (can be imported in scripts) -- `src/docs/TORCH.md` β€” Protocol summary and usage +- `TORCH.md` β€” Protocol summary and usage - `src/prompts/` β€” Generic scheduler prompts and flow - `skills/` β€” Repository-local skill guides for agent onboarding and repeatable workflows - `dashboard/` β€” Static lock dashboard assets diff --git a/torch/TORCH.md b/torch/TORCH.md new file mode 100644 index 00000000..ee5767e5 --- /dev/null +++ b/torch/TORCH.md @@ -0,0 +1,458 @@ +# TORCH: Task Orchestration via Relay-Coordinated Handoff + +TORCH is a decentralized task-locking protocol for multi-agent software development. This document serves as the primary manual for both human operators and AI agents working within a TORCH-enabled repository. + +--- + +## Agent Operating Guide + +This section defines how agents should work in this repository. + +### Purpose + +- Keep agent work predictable, auditable, and safe. +- Minimize repeated discovery work across sessions. +- Capture durable learnings so future agents can move faster. + +### Session startup checklist (run every session) + +1. **Read `TORCH.md`** (this file). +2. Read `CONTRIBUTING.md` for commit and PR expectations. +3. Read `KNOWN_ISSUES.md` for active blockers and workarounds. +4. Read `docs/agent-handoffs/README.md`. +5. Scan recent notes in: + - `docs/agent-handoffs/learnings/` + - `docs/agent-handoffs/incidents/` +6. If present, review the current run artifacts in: + - `src/context/` + - `src/todo/` + - `src/decisions/` + - `src/test_logs/` + - `src/issues/` + +### Core operating principles + +- Default to generic guidance and neutral language. +- Make the smallest safe change that satisfies the request. +- Avoid unrelated refactors. +- Preserve backward compatibility unless explicitly asked otherwise. +- Prefer explicit commands and documented behavior over assumptions. +- Record assumptions clearly in your final summary. + +### Validation policy + +- Run the most relevant checks for changed files (tests, lint, typecheck, build, or targeted scripts). +- Never claim a check passed unless it was actually executed. +- If a check cannot run, record: + - command attempted, + - why it could not complete, + - what fallback validation was performed. + +### Execution Workflow + +1. **Load baseline context** (see Session startup checklist above). +2. **Clarify the task** + - Restate the requested outcome. + - Identify constraints, risks, and assumptions. +3. **Plan minimal changes** + - Keep scope tight. + - Avoid touching unrelated files. +4. **Implement** + - Apply small, reversible edits. + - Favor readability and maintainability. +5. **Validate** + - Run relevant checks for impacted files. + - Capture exact commands and outcomes. +6. **Document and hand off** + - Summarize what changed and why. + - Record reusable learnings/incidents when appropriate. + +### Working files for session state + +Use the following folders as lightweight coordination artifacts: + +- `src/context/` β€” Current objective, scope, constraints. +- `src/todo/` β€” Task checklist and blockers. +- `src/decisions/` β€” Important design/implementation choices. +- `src/test_logs/` β€” Validation commands and results. +- `src/issues/` β€” Investigations or audits that may become tracked issues. + +#### Content templates + +**Context note:** Goal, Scope, Constraints, Open questions. +**Todo note:** Pending tasks, Completed tasks, Blocked tasks. +**Decision note:** Decision, Alternatives considered, Rationale, Consequences/follow-ups. +**Test log:** Command, Result (pass/fail/warn), Notes (environmental limits, retries, artifacts). + +### Knowledge-sharing protocol + +#### What belongs where + +- `KNOWN_ISSUES.md`: Active, reproducible issues only. Include status, impact, workaround, and last verification date. +- `docs/agent-handoffs/learnings/`: Proven patterns, repeatable fixes, and successful implementation guidance. +- `docs/agent-handoffs/incidents/`: Failures, root causes, mitigations, and prevention guidance. +- `src/context/`, `src/todo/`, etc.: Ephemeral session state. + +#### Naming standard + +Use: `YYYY-MM-DD-short-topic.md` (e.g., `2026-02-14-validation-before-summary.md`). +Keep names concise, descriptive, and neutral. + +#### Required sections for reusable notes + +1. Context +2. Observation +3. Action taken +4. Validation performed +5. Recommendation for next agents + +#### Update decision tree + +When you discover reusable context: +1. Check if an existing note already covers it. +2. If yes, update that note. +3. If no, add a new note in `learnings/` or `incidents/`. +4. If the issue is still active/reproducible, add or update `KNOWN_ISSUES.md`. + +### Quality checklist before completion + +- Scope matches request. +- Documentation remains repository-agnostic unless explicitly needed. +- No unsupported claims about testing. +- Assumptions and limitations are called out. +- Changes are easy to revert. + +### Anti-patterns to avoid + +- Embedding product/company-specific guidance in baseline docs. +- Large refactors when a focused change is sufficient. +- Skipping validation without recording why. +- Creating duplicate notes when an update would suffice. + +--- + +## Scenario-First Tests & Test Integrity (Dark Factory Standard) + +In this repo, **validation replaces code review**. That means our test/scenario system is the *only* thing standing between β€œworking software” and β€œgreen-but-worthless software.” + +Agents will naturally optimize for short-term goals (e.g., β€œget CI green”) unless we constrain them. If we ever allow β€œedit tests until they pass,” we destroy the signal, and over time the suite becomes meaningless. + +### Core philosophy: scenarios > checklists + +We treat tests as **behavioral specifications** expressed as **scenarios**: +- β€œUser stories” / end-to-end behaviors (Given/When/Then or equivalent) +- Assertions focus on **externally observable outcomes** at boundaries (API responses, persisted state, emitted events, CLI output, UI state), not internal call sequences. +- We prefer *minimal coupling* to implementation details so refactors don’t require rewriting β€œtruth.” + +(StrongDM reached the same conclusion: repo-local tests are easy to reward-hack; scenarios and satisfaction-based validation reduce β€œteaching to the test.”) :contentReference[oaicite:1]{index=1} + +### Non-negotiable constitution (anti-cheat) + +**Hard rules (always on):** +1) **Never weaken, delete, or rewrite a test just to make CI pass.** +2) **Never change expected behavior to match buggy output** (β€œrubber-stamp the snapshot”, β€œupdate golden”, β€œadjust assertion”) unless it is a **spec correction** (see below). +3) Do not β€œfix” flaky tests with retries, sleeps, timeouts, or looser assertions. **Remove nondeterminism** instead (control time, randomness, IO, network). +4) Prefer black-box assertions at system boundaries; avoid tests that merely mirror internal logic. + +### Definitions + +- **Scenario**: a behavioral spec (often end-to-end) describing what must happen for a user/system in a real environment. +- **Invariant**: a property that must always hold across many inputs/states (great for property-based or metamorphic testing). +- **Holdout scenario**: an evaluation scenario kept outside the agent-editable area to reduce overfitting / reward-hacking. + +### When tests may change (spec correction protocol) + +Changing a test expectation is allowed **only** when the test was enforcing the wrong behavior. + +If you believe a test should change: +1) Identify the **scenario/spec** that defines correct behavior. +2) Explain precisely why the old expectation was wrong. +3) Replace it with an **equally strict or stricter** behavior-based check. +4) Record a **Test Integrity Note** (below) and, if applicable, a short spec note (e.g., `docs/spec_changes/-.md`). + +If you cannot point to scenario/spec truth, **do not change the test**. Add a β€œNeeds Spec Clarification” note instead. + +### β€œTest Integrity Note” (required for any PR touching tests) + +Every PR that adds/changes tests must include this machine-readable block in the PR description (or in a `TEST_INTEGRITY.md` entry referenced by the PR): + +```yaml +test_integrity_note: + change_type: ["new_tests" | "refactor_tests" | "spec_correction" | "flake_fix"] + scenarios: + - id: SCN- + given: "" + when: "" + then: "" + observable_outcomes: + - "" + determinism_controls: + - "" + anti_cheat_rationale: + prevents: + - "hard-coded return value" + - "over-mocking internal logic" + - "snapshot rubber-stamping" + - "retry/sleep-based flake masking" + relaxation: + did_relax_any_assertion: false + if_true_explain_spec_basis: "" +``` + +### Test portfolio guidance (scenario-first, still layered) + +We want a balanced suite: + +* **Scenario/E2E**: user-story validation at boundaries (few, high value, high fidelity) +* **Integration/contract**: service boundaries, serialization, persistence, workflows +* **Unit/invariants**: properties that kill trivial cheats (β€œreturn true” shouldn’t survive) + +For cheat resistance, strongly prefer: + +* invariants/property-based tests for critical logic +* metamorphic relations where β€œexact expected output” is hard +* periodic mutation testing to β€œtest the tests” (surviving mutants indicate missing assertions) + +### External dependency realism (service virtualization / β€œdigital twins”) + +Where third-party services are involved, we prefer deterministic β€œbehavioral clones” (mocks/stubs at the API boundary that reproduce edge cases and contracts) over live calls. This keeps scenarios **realistic** without being flaky or rate-limited, and it makes high-volume scenario validation affordable. ([factory.strongdm.ai][2]) + +--- + +## Role: Test Integrity & Scenario Spec Agent (Enforcer) + +This repo includes (or assumes) a dedicated agent role whose only job is to protect validation integrity. + +**This agent’s goal is NOT β€œmake CI green.”** +Its goal is β€œmake the suite reflect reality and reject fake passes.” + +**Authority:** + +* May add new scenarios, invariants, and tests. +* May refactor tests to be more behavioral and less procedural. +* May improve determinism (fixed seeds, fake clocks, hermetic env). +* May only change expectations via the Spec Correction Protocol above. + +**Prohibitions:** + +* Must never weaken tests to pass. +* Must never edit holdout scenarios (if configured). +* Must never solve flakiness via retries/sleeps/loosening. + +**Deliverables each run:** + +* Scenario list (Given/When/Then) +* Proposed test diffs +* Test Integrity Note +* β€œCheat vectors blocked” summary (what trivial implementations it prevents) + +--- + +## Dashboard & Protocol Overview + +The TORCH dashboard subscribes to Nostr relays for **kind 30078** events tagged with the `#torch-agent-lock` hashtag. These are the same events agents publish via `bin/torch-lock.mjs` when they claim tasks using the TORCH protocol. + +**Relays:** `wss://relay.damus.io`, `wss://nos.lol`, `wss://relay.primal.net` + +**Filter:** `{"kinds":[30078],"#t":["torch-agent-lock"]}` + +**Unique identifier:** All events use the `torch-lock/` namespace in the d-tag and the `#torch-agent-lock` hashtag. This scopes events to this repository and is how both agents and the dashboard filter messages. + +To follow in any Nostr client, subscribe to kind 30078 with `#t = torch-agent-lock` on the relays above. + +## Quick start + +```bash +# Check active locks +node bin/torch-lock.mjs check --cadence daily + +# Machine-readable lock output (recommended for automation) +node bin/torch-lock.mjs check --cadence daily --json --quiet --json-file /tmp/torch-lock-check.json + +# Claim a task +AGENT_PLATFORM=codex node bin/torch-lock.mjs lock --agent docs-agent --cadence daily + +# List all active locks +node bin/torch-lock.mjs list + +# Probe relay health before scheduler lock acquisition +node bin/torch-lock.mjs health --cadence daily +``` + +## Defaults + +- Kind: `30078` (NIP-33 parameterized replaceable) +- Expiration: `NIP-40` via `expiration` tag +- TTL: `7200s` (2h) +- Namespace: `torch` +- Relays: + - `wss://relay.damus.io` + - `wss://nos.lol` + - `wss://relay.primal.net` + +## Environment variables + +- `NOSTR_LOCK_NAMESPACE` +- `NOSTR_LOCK_HASHTAG` +- `NOSTR_LOCK_RELAYS` +- `NOSTR_LOCK_TTL` +- `NOSTR_LOCK_QUERY_TIMEOUT_MS` +- `NOSTR_LOCK_PUBLISH_TIMEOUT_MS` +- `NOSTR_LOCK_MIN_SUCCESSFUL_PUBLISHES` +- `NOSTR_LOCK_RELAY_FALLBACKS` +- `NOSTR_LOCK_MIN_ACTIVE_RELAY_POOL` +- `NOSTR_LOCK_DAILY_ROSTER` +- `NOSTR_LOCK_WEEKLY_ROSTER` +- `TORCH_CONFIG_PATH` +- `AGENT_PLATFORM` (supports `codex`, `claude`, or `linux` for simulated/manual execution) +- `TORCH_MEMORY_ENABLED` (`true`/`false`; global memory kill switch, defaults to enabled) +- `TORCH_MEMORY_INGEST_ENABLED` (`true`/`false` or comma-separated canary `agent_id` allow list) +- `TORCH_MEMORY_RETRIEVAL_ENABLED` (`true`/`false` or comma-separated canary `agent_id` allow list) +- `TORCH_MEMORY_PRUNE_ENABLED` (`true`, `false`, or `dry-run`) + +## torch-config.json + +You can configure TORCH per repository with a root-level `torch-config.json` file. + +Common settings: + +- `nostrLock.namespace` β€” namespace prefix used in d-tags and hashtags. +- `nostrLock.relays` β€” relay list for check/lock/list operations. +- `nostrLock.ttlSeconds` β€” default lock TTL. +- `nostrLock.queryTimeoutMs` β€” relay query timeout (ms, valid range: 100..120000). +- `nostrLock.publishTimeoutMs` β€” per-relay publish timeout (ms, valid range: 100..120000). +- `nostrLock.minSuccessfulRelayPublishes` β€” minimum successful publishes required before lock acquisition continues (default: `1`). +- `nostrLock.relayFallbacks` β€” optional fallback relay URLs used when primary query/publish attempts fail quorum. +- `nostrLock.minActiveRelayPool` β€” minimum number of relays kept active even when lower-ranked relays are quarantined (default: `1`). +- `nostrLock.dailyRoster` / `nostrLock.weeklyRoster` β€” optional per-project roster overrides. +- `dashboard.defaultCadenceView` β€” default dashboard view (`daily`, `weekly`, `all`). +- `dashboard.defaultStatusView` β€” default dashboard status filter (`active`, `all`). +- `dashboard.hashtag` β€” custom hashtag for lock events (defaults to `-agent-lock`). +- `scheduler.firstPromptByCadence.daily` / `.weekly` β€” first-run scheduler starting agent. +- `scheduler.handoffCommandByCadence.daily` / `.weekly` β€” shell command run after lock acquisition; command must use `SCHEDULER_AGENT`, `SCHEDULER_CADENCE`, and `SCHEDULER_PROMPT_PATH` provided by `scripts/agent/run-scheduler-cycle.mjs`. +- `scheduler.paused.daily` / `.weekly` β€” array of agent names to exclude from scheduler rotation. +- `scheduler.strict_lock` β€” lock backend policy switch (default: `true`); when `false`, scheduler defers backend-unavailable lock failures before converting the run to failed. +- `scheduler.degraded_lock_retry_window` β€” non-strict deferral window in milliseconds; backend lock failures outside this window immediately consume failure budget and mark run failed. +- `scheduler.max_deferrals` β€” max number of non-strict lock deferrals allowed in-window before scheduler records a hard failure. + +Default first-run daily scheduler prompt is `scheduler-update-agent`. + +For weekly repository-fit maintenance, TORCH also includes `src/prompts/weekly/repo-fit-agent.md` to periodically adjust defaults and docs to the host repository. + +Operational note: scheduler handoff commands are treated as required execution steps. A non-zero exit code (or missing command) is a hard failure: the scheduler writes a `_failed.md` task log, exits immediately, and does not publish `lock:complete` for that run. + +Scheduler failure classes in task logs: + +- `backend_unavailable` β€” legacy compatibility field for lock backend unavailable failures. +- `prompt_validation_error` β€” legacy compatibility field for prompt/runtime validation failures. + +Scheduler failure categories in task logs: + +- `lock_backend_error` β€” lock backend unavailable preflight failures and lock acquisition backend exit code `2` failures/deferrals; includes relay health alert metadata, retry window guidance, health check command, and incident runbook link. +- `prompt_parse_error` β€” scheduler could not read/parse the selected prompt file; prompt execution is skipped. +- `prompt_schema_error` β€” selected prompt file or generated run artifacts failed schema/contract checks; prompt run is treated as invalid. +- `execution_error` β€” runtime execution failures in handoff callbacks, memory commands, or configured validation commands. + + +## Lock backend production defaults + +Recommended baseline for production scheduler runs: + +- `nostrLock.relays`: 3+ geographically-diverse primary relays. +- `nostrLock.relayFallbacks`: 2 additional relays not present in primary list. +- `nostrLock.queryTimeoutMs`: `10000` +- `nostrLock.publishTimeoutMs`: `8000` +- `nostrLock.minSuccessfulRelayPublishes`: `2` +- `nostrLock.minActiveRelayPool`: `2` + +Validation behavior: + +- Relay URLs must be absolute `ws://` or `wss://` URLs. +- Invalid relay URLs or invalid timeout/count ranges are fatal startup errors. +- Lock backend errors include phase (`query:primary`, `query:fallback`, `publish:primary`, `publish:fallback`), relay endpoint, and timeout value used. +- When scheduler preflight fails before lock acquisition, task logs must explicitly state `prompt not executed` to make lock-vs-prompt root cause obvious in UI/CLI summaries. +- Interpret `relay_publish_quorum_failure` (derived from `lock_publish_quorum_failed` telemetry) as quorum not met even after retries/fallbacks. Expected operator actions: + 1. Run `npm run lock:health -- --cadence ` to confirm relay readiness and identify failing relays/reasons. + 2. Review task log metadata (`lock_failure_reason_distribution`, `backend_category`, `lock_correlation_id`) for dominant failure modes (timeouts, DNS, auth, malformed relay URL). + 3. If failures persist past retry window, follow incident runbook `docs/agent-handoffs/learnings/2026-02-15-relay-health-preflight-job.md` and escalate relay/network remediation. +- Relay health snapshots are emitted periodically and whenever lock publish/query fails; snapshots include success rate, timeout rate, rolling latency, and quarantine state per relay. + +## Scheduler lock reliability reporting + +Run the lock reliability summary to aggregate recent scheduler outcomes by platform, cadence, backend error category, and relay endpoint: + +```bash +npm run report:lock-reliability +``` + +Outputs: +- `artifacts/lock-reliability/lock-reliability-summary.md` +- `artifacts/lock-reliability/lock-reliability-summary.json` + + +## Roster precedence + +The lock CLI resolves roster names in this order: + +1. `NOSTR_LOCK_DAILY_ROSTER` / `NOSTR_LOCK_WEEKLY_ROSTER` (comma-separated env overrides). +2. `torch-config.json` (`nostrLock.dailyRoster` / `nostrLock.weeklyRoster`). +3. `src/prompts/roster.json` (`daily` / `weekly` canonical scheduler roster). +4. Built-in fallback roster (used only if `src/prompts/roster.json` is unreadable). + +`lock --agent` validates names against the resolved cadence roster, and `check`/`list` report lock events whose agent names do not match scheduler roster entries exactly. + + +## Exit codes + +- `0`: success +- `1`: usage error +- `2`: relay/network error +- `3`: lock denied (already locked or race lost) + + +## Memory rollout plan + +1. Deploy memory schema changes with scheduler jobs disabled (`TORCH_MEMORY_ENABLED=false` or subsystem flags set to `false`). +2. Enable ingest for one canary `agent_id` via `TORCH_MEMORY_INGEST_ENABLED=`. +3. Validate retrieval quality and storage growth metrics before expanding scope. +4. Enable broader retrieval (`TORCH_MEMORY_RETRIEVAL_ENABLED=` then `true`). +5. Enable pruning in `dry-run` mode first, then switch to active pruning after revalidation. + +## Memory rollback plan + +1. Disable memory flags (`TORCH_MEMORY_ENABLED=false` and/or set ingest/retrieval/prune flags to `false`). +2. Stop memory maintenance scheduler processes. +3. Preserve database state for post-incident analysis; do not drop or rewrite memory tables during rollback. +4. Keep prune actions in `dry-run` (or disabled) until lifecycle policy and data integrity are revalidated. + +## Offline & Air-Gapped Installation + +TORCH is designed to operate in diverse environments, including high-security, air-gapped, or offline networks where direct access to the npm registry is restricted. + +### The Offline Bundle + +The "Offline Bundle" is a standard npm package tarball (`.tgz`) generated during the build process. It contains the complete source code and dependency definitions required to run TORCH. + +**Why use the bundle?** + +1. **Security & Integrity:** You can verify the checksum of the tarball before installing it. It creates a frozen snapshot of the code that doesn't change. +2. **No Registry Dependency:** You can install it directly using `npm install ./torch-lock-0.1.0.tgz` without needing to connect to `registry.npmjs.org`. +3. **Project Integration:** Unlike a binary executable, the tarball installs TORCH as a standard dependency in your `package.json`. This ensures: + * Scripts like `npm run lock:check` work natively. + * TORCH versioning is managed alongside your other dependencies. + * It works across all operating systems that support Node.js. + +### Installation Instructions + +1. Download the tarball from the landing page or your internal artifact repository. +2. Place it in your project root or a `vendor/` directory. +3. Run the install command: + ```bash + npm install ./torch-lock-0.1.0.tgz + ``` + *(Replace `0.1.0` with the actual version number)* + +4. Initialize TORCH: + ```bash + npx torch-lock init + ``` diff --git a/torch/build.mjs b/torch/build.mjs index b45245e1..56135c72 100644 --- a/torch/build.mjs +++ b/torch/build.mjs @@ -1,6 +1,7 @@ import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; +import { execSync } from 'child_process'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -8,12 +9,17 @@ const __dirname = path.dirname(__filename); const DIST_DIR = path.join(__dirname, 'dist'); const LANDING_SRC = path.join(__dirname, 'landing'); const DASHBOARD_SRC = path.join(__dirname, 'dashboard'); -const DOCS_SRC = path.join(__dirname, 'src', 'docs'); +const DOCS_SRC = path.join(__dirname, 'docs'); +const TORCH_MD_SRC = path.join(__dirname, 'TORCH.md'); const CONSTANTS_SRC = path.join(__dirname, 'src', 'constants.mjs'); -const PROMPTS_SRC = path.join(__dirname, 'src', 'prompts', 'META_PROMPTS.md'); +const PROMPTS_DIR_SRC = path.join(__dirname, 'src', 'prompts'); const CONFIG_SRC = path.join(__dirname, 'torch-config.json'); const ASSETS_SRC = path.join(__dirname, 'assets'); +// Read package.json to get version and name +const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8')); +const tarballName = `${packageJson.name}-${packageJson.version}.tgz`; + // Ensure clean slate if (fs.existsSync(DIST_DIR)) { fs.rmSync(DIST_DIR, { recursive: true, force: true }); @@ -30,6 +36,10 @@ distHtml = distHtml.replace(/"\.\.\/dashboard\/styles\.css"/g, '"dashboard/style distHtml = distHtml.replace(/"\.\.\/dashboard\/"/g, '"dashboard/"'); // Link to dashboard distHtml = distHtml.replace(/'\.\.\/src\/docs\/TORCH\.md'/g, "'src/docs/TORCH.md'"); distHtml = distHtml.replace(/"\.\.\/assets\//g, '"assets/'); +distHtml = distHtml.replace(/\.\.\/src\/prompts\//g, 'src/prompts/'); + +// Inject Offline Bundle Filename +distHtml = distHtml.replace(/{{OFFLINE_BUNDLE_FILENAME}}/g, tarballName); fs.writeFileSync(path.join(DIST_DIR, 'index.html'), distHtml); @@ -38,19 +48,24 @@ const distDashboard = path.join(DIST_DIR, 'dashboard'); fs.mkdirSync(distDashboard, { recursive: true }); fs.cpSync(DASHBOARD_SRC, distDashboard, { recursive: true }); -// 3. Copy src/docs/ -> dist/src/docs/ +// 3. Copy docs/ -> dist/src/docs/ const distDocs = path.join(DIST_DIR, 'src', 'docs'); fs.mkdirSync(distDocs, { recursive: true }); -fs.cpSync(DOCS_SRC, distDocs, { recursive: true }); +if (fs.existsSync(DOCS_SRC)) { + fs.cpSync(DOCS_SRC, distDocs, { recursive: true }); +} +if (fs.existsSync(TORCH_MD_SRC)) { + fs.copyFileSync(TORCH_MD_SRC, path.join(distDocs, 'TORCH.md')); +} // 3.5. Copy src/constants.mjs -> dist/src/constants.mjs fs.copyFileSync(CONSTANTS_SRC, path.join(DIST_DIR, 'src', 'constants.mjs')); -// 4. Copy src/prompts/META_PROMPTS.md -> dist/src/prompts/META_PROMPTS.md +// 4. Copy src/prompts/ -> dist/src/prompts/ const distPromptsDir = path.join(DIST_DIR, 'src', 'prompts'); fs.mkdirSync(distPromptsDir, { recursive: true }); -if (fs.existsSync(PROMPTS_SRC)) { - fs.copyFileSync(PROMPTS_SRC, path.join(distPromptsDir, 'META_PROMPTS.md')); +if (fs.existsSync(PROMPTS_DIR_SRC)) { + fs.cpSync(PROMPTS_DIR_SRC, distPromptsDir, { recursive: true }); } // 5. Copy torch-config.json -> dist/torch-config.json (optional config) @@ -65,4 +80,18 @@ if (fs.existsSync(ASSETS_SRC)) { fs.cpSync(ASSETS_SRC, distAssets, { recursive: true }); } +// 7. Generate NPM Pack Tarball +console.log('Generating npm package tarball...'); +try { + execSync('npm pack', { stdio: 'inherit' }); + if (fs.existsSync(tarballName)) { + fs.renameSync(tarballName, path.join(DIST_DIR, tarballName)); + console.log(`Moved ${tarballName} to dist/`); + } else { + console.error(`Error: ${tarballName} not found after npm pack.`); + } +} catch (error) { + console.error('Error packing npm module:', error); +} + console.log('Build complete! Output directory: dist/'); diff --git a/torch/daily-scheduler.md b/torch/daily-scheduler.md index 48e6d7ed..3793ab42 100644 --- a/torch/daily-scheduler.md +++ b/torch/daily-scheduler.md @@ -27,15 +27,16 @@ Canonical roster source: `roster.json` (`daily` key). | 8 | docs-agent | `docs-agent.md` | | 9 | docs-alignment-agent | `docs-alignment-agent.md` | | 10 | docs-code-investigator | `docs-code-investigator.md` | -| 11 | innerhtml-migration-agent | `innerhtml-migration-agent.md` | -| 12 | known-issues-agent | `known-issues-agent.md` | -| 13 | load-test-agent | `load-test-agent.md` | -| 14 | log-fixer-agent | `log-fixer-agent.md` | -| 15 | onboarding-audit-agent | `onboarding-audit-agent.md` | -| 16 | perf-agent | `perf-agent.md` | -| 17 | protocol-research-agent | `protocol-research-agent.md` | -| 18 | scheduler-update-agent | `scheduler-update-agent.md` | -| 19 | style-agent | `style-agent.md` | -| 20 | test-audit-agent | `test-audit-agent.md` | -| 21 | todo-triage-agent | `todo-triage-agent.md` | -| 22 | torch-garbage-collection-agent | `torch-garbage-collection-agent.md` | +| 11 | governance-agent | `governance-agent.md` | +| 12 | innerhtml-migration-agent | `innerhtml-migration-agent.md` | +| 13 | known-issues-agent | `known-issues-agent.md` | +| 14 | load-test-agent | `load-test-agent.md` | +| 15 | log-fixer-agent | `log-fixer-agent.md` | +| 16 | onboarding-audit-agent | `onboarding-audit-agent.md` | +| 17 | perf-agent | `perf-agent.md` | +| 18 | protocol-research-agent | `protocol-research-agent.md` | +| 19 | scheduler-update-agent | `scheduler-update-agent.md` | +| 20 | style-agent | `style-agent.md` | +| 21 | test-audit-agent | `test-audit-agent.md` | +| 22 | todo-triage-agent | `todo-triage-agent.md` | +| 23 | torch-garbage-collection-agent | `torch-garbage-collection-agent.md` | diff --git a/torch/dashboard/index.html b/torch/dashboard/index.html index cc151862..f4d78107 100644 --- a/torch/dashboard/index.html +++ b/torch/dashboard/index.html @@ -76,6 +76,13 @@
0 events +
+ + + - @@ -648,7 +790,7 @@
@@ -735,6 +902,14 @@ npm install https://github.com/PR0M3TH3AN/TORCH/archive/refs/heads/main.tar.gz &
+
+

Functional Agents

+
+ +

Loading agents...

+
+
+

Scheduler Meta Prompts

@@ -759,30 +934,6 @@ npm install https://github.com/PR0M3TH3AN/TORCH/archive/refs/heads/main.tar.gz &
-
-

Autonomous Improvement Cycle

-
- flowchart TD - %% Nodes - S[Scheduler
Daily & Weekly] - C[Candidate Loop
Audit & Check Agents] - F[Fixer Agents
Code Correction] - P[Prompt Maintenance
Self-Evolution] - - %% Edge Connections - S -->|Orchestrates| C - C -->|Identifies Gaps| F - F -->|Resolves Issues| P - P -->|Refines Prompts| S - - %% Styles - classDef box fill:#151b2f,stroke:#2a3456,color:#dbe4ff,stroke-width:1px; - classDef accent fill:#4f8cff,stroke:#2f6be5,color:#ffffff,stroke-width:2px; - - class S,P accent; - class C,F box; -
-