mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-07 14:58:56 +00:00
Add dependency scanning and optional dependency checks
This commit is contained in:
6
.github/workflows/python-ci.yml
vendored
6
.github/workflows/python-ci.yml
vendored
@@ -83,10 +83,8 @@ jobs:
|
||||
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 install pip-audit
|
||||
pip-audit -r requirements.lock --ignore-vuln GHSA-wj6h-64fc-37mp
|
||||
- name: Run dependency scan
|
||||
run: scripts/dependency_scan.sh --ignore-vuln GHSA-wj6h-64fc-37mp
|
||||
- name: Determine stress args
|
||||
shell: bash
|
||||
run: |
|
||||
|
9
scripts/dependency_scan.sh
Executable file
9
scripts/dependency_scan.sh
Executable file
@@ -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 "$@"
|
21
src/main.py
21
src/main.py
@@ -18,6 +18,7 @@ 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 nostr.client import NostrClient
|
||||
@@ -38,6 +39,25 @@ 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.warning(
|
||||
"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."""
|
||||
@@ -1205,6 +1225,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")
|
||||
|
@@ -22,19 +22,21 @@ pgpy==0.6.0
|
||||
pyotp>=2.8.0
|
||||
|
||||
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>=0.0.20
|
||||
PyJWT
|
||||
orjson
|
||||
argon2-cffi
|
||||
toga-core>=0.5.2
|
||||
pillow
|
||||
toga-dummy>=0.5.2 # for headless GUI tests
|
||||
slowapi
|
||||
|
||||
# Optional dependencies - install as needed for additional features
|
||||
pyperclip # Clipboard support for secret mode
|
||||
qrcode>=8.2 # Generate QR codes for TOTP setup
|
||||
fastapi>=0.116.1 # API server
|
||||
uvicorn>=0.35.0 # API server
|
||||
starlette>=0.47.2 # API server
|
||||
httpx>=0.28.1 # API server
|
||||
requests>=2.32 # API server
|
||||
python-multipart>=0.0.20 # API server file uploads
|
||||
PyJWT # JWT authentication for API server
|
||||
orjson # Fast JSON serialization for API server
|
||||
argon2-cffi # Password hashing for API server
|
||||
toga-core>=0.5.2 # Desktop GUI
|
||||
pillow # Image support for GUI
|
||||
toga-dummy>=0.5.2 # Headless GUI tests
|
||||
slowapi # Rate limiting for API server
|
||||
|
@@ -1,47 +1,51 @@
|
||||
# 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 .atomic_write import atomic_write
|
||||
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 copy_to_clipboard
|
||||
except Exception as exc: # pragma: no cover - executed only if pyperclip missing
|
||||
|
||||
def copy_to_clipboard(*_args, **_kwargs):
|
||||
"""Stub when clipboard support is unavailable."""
|
||||
logger.warning("Clipboard support unavailable: %s", exc)
|
||||
return False
|
||||
|
||||
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",
|
||||
|
Reference in New Issue
Block a user