Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2025 LeoTN
Copyright (c) 2025-2026 LeoTN

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
3 changes: 1 addition & 2 deletions assets/CheckDependencies.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -117,5 +117,4 @@ else {
Write-Host "`n[INFO] No transitive dependencies detected." -ForegroundColor Green
}

Write-Host "`n[INFO] Done." -ForegroundColor Cyan
pause
Write-Host "`n[INFO] Done." -ForegroundColor Cyan
4 changes: 3 additions & 1 deletion assets/CheckDependencies_Launcher.bat
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ echo Terminal ready...

set psScriptPath="%CD%\CheckDependencies.ps1"

powershell.exe -executionPolicy bypass -file %psScriptPath%
powershell.exe -executionPolicy bypass -file %psScriptPath%

pause
Binary file modified assets/readme.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion assets/readme.tape
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Output readme.gif

Require sct.exe
Require sct

Set Shell powershell
Set Width 1500
Expand Down
44 changes: 26 additions & 18 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,45 @@
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.poetry]
[project]
name = "step-cli-tools"
version = "0.0.0"
description = "Prebuilt tools for the smallstep step-cli"
license = "MIT"
license-files = ["LICENSE"]
readme = "README.md"
authors = ["LeoTN <LeoTN.GitHub@gmx.net>"]
license = "LICENSE"
repository = "https://github.com/LeoTN/step-cli-tools"
keywords = ["step", "cli", "step-cli", "step-ca", "certificate", "root-ca", "automation"]
authors = [
{ name = "LeoTN", email = "LeoTN.GitHub@gmx.net" }
]
keywords = ["step-ca", "step-cli", "ca", "cli", "certificate", "certificate-authority"]
classifiers = [
"Topic :: Utilities",
"Environment :: Console",
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent"
]

[project.urls]
homepage = "https://github.com/LeoTN/step-cli-tools#readme"
repository = "https://github.com/LeoTN/step-cli-tools"
"Bug Tracker" = "https://github.com/LeoTN/step-cli-tools/issues"

[project.scripts]
step-cli-tools = "step_cli_tools.main:main"
sct = "step_cli_tools.main:main"

[tool.poetry]
packages = [
{ include = "step_cli_tools" }
]

[tool.poetry.dependencies]
python = ">=3.10,<4.0"
cryptography = ">=46.0.2"
rich = ">=14.2.0"
questionary = "^2.1.1"
ruamel-yaml = "^0.18.16"
cryptography = "^46.0.3"
packaging = "^25.0"
questionary = "^2.1.1"
rich = "^14.2.0"
ruamel-yaml = "^0.19.1"

[tool.poetry.scripts]
step-cli-tools = "step_cli_tools.main:main"
sct = "step_cli_tools.main:main"

[dependency-groups]
dev = [
"deptry (>=0.23.1,<0.24.0)"
]
[tool.poetry.group.dev.dependencies]
deptry = ">=0.24.0,<0.25.0"
90 changes: 84 additions & 6 deletions step_cli_tools/common.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
# --- Standard library imports ---
import logging
from logging.handlers import RotatingFileHandler
import os
import platform

# --- Third-party imports ---
import questionary
from rich.console import Console
from rich.logging import RichHandler
from rich.theme import Theme

__all__ = [
"console",
"qy",
"DEFAULT_QY_STYLE",
"SCRIPT_HOME_DIR",
"SCRIPT_LOGGING_DIR",
"STEP_BIN",
"logger",
]

console = Console()

custom_logging_theme = Theme(
{
"logging.level.info": "none",
"logging.level.warning": "#F9ED69",
"logging.level.error": "#B83B5E",
"logging.level.critical": "bold reverse #B83B5E",
}
)
console = Console(theme=custom_logging_theme)
qy = questionary
# Default style to use for questionary
DEFAULT_QY_STYLE = qy.Style(
Expand All @@ -25,18 +40,18 @@
("answer", "fg:#F08A5D"),
]
)

# --- Directories and files ---
SCRIPT_HOME_DIR = os.path.expanduser("~/.step-cli-tools")
SCRIPT_LOGGING_DIR = os.path.normpath(os.path.join(SCRIPT_HOME_DIR, "logs"))


def get_step_binary_path() -> str:
def _get_step_binary_path() -> str:
"""
Get the absolute path to the step-cli binary based on the operating system.

Returns:
str: Absolute path to the step binary.

Raises:
OSError: If the operating system is not supported.
"""

bin_dir = os.path.join(SCRIPT_HOME_DIR, "bin")
Expand All @@ -51,4 +66,67 @@ def get_step_binary_path() -> str:
return os.path.normpath(binary)


STEP_BIN = get_step_binary_path()
STEP_BIN = _get_step_binary_path()

# --- Logging ---


def _setup_logger(
name: str,
log_file: str = "step-cli-tools.log",
level=logging.DEBUG,
console: Console = console,
max_bytes: int = 5_000_000,
backup_count: int = 5,
) -> logging.Logger:
"""
Sets up a reusable logger with Rich console output.

Args:
name: Name of the logger.
log_file: Path to the log file.
level: Logging level.
console: Console instance used for output.
max_bytes: Maximum size of log file in bytes.
backup_count: Number of log files to keep.

Returns:
A logger instance.
"""

# Ensure log directory exists
if os.path.dirname(log_file):
os.makedirs(os.path.dirname(log_file), exist_ok=True)

logger = logging.getLogger(name)
logger.setLevel(level)
# Avoid duplicate logs if root logger is configured
logger.propagate = False

if not logger.handlers:
# Rotating file handler (plain text)
file_handler = RotatingFileHandler(
log_file, maxBytes=max_bytes, backupCount=backup_count, encoding="utf-8"
)
file_handler.setFormatter(
logging.Formatter(
"%(asctime)s %(levelname)-8s [%(funcName)-30s] %(message)s"
)
)
file_handler.setLevel(level)
logger.addHandler(file_handler)

# Rich console handler (colorful)
console_handler = RichHandler(
console=console, rich_tracebacks=True, show_time=False, show_path=False
)
console_handler.setLevel(level)
logger.addHandler(console_handler)

return logger


logger = _setup_logger(
name="main",
log_file=os.path.join(SCRIPT_LOGGING_DIR, "step-cli-tools.log"),
)
Loading