Project Architecture
This page outlines the internal software design and architecture of the SKM codebase. It is primarily intended for developers wishing to audit the security of the tool, understand its execution flow, or contribute to the Open Source project.
The Core Principle: Zero Data Loss
SKM is designed around one absolute rule: Never destroy a user's original SSH keys.
When a user initializes SKM (skm init), the tool does not delete the contents of ~/.ssh. Instead, it executes a carefully choreographed migration:
- It creates an isolated directory at
~/.skm/default/. - It physically moves the
id_rsa/id_ed25519files from~/.ssh/to the new vault. - It immediately generates symbolic links back in
~/.ssh/pointing to the vault.
Because the active ~/.ssh directory relies entirely on symlinks, SKM can swap identities in milliseconds simply by breaking and recreating those symlinks. The underlying private keys remain untouched in their respective ~/.skm/<alias> folders.
Codebase Organization
SKM is written entirely in Go (Golang) and utilizes urfave/cli.v1 to handle command-line routing and flag parsing.
cmd/skm/ (The Entrypoint)
This package handles the user-facing CLI layer.
main.go: The root execution point. It defines global flags, parses crucial environment variables (likeSKM_STORE_PATH), and mounts the CLI application.commands.go: Defines the command schema (aliases, usage descriptions, and flags). It maps CLI commands directly to functions in theinternal/actionspackage.Makefile: Contains compilation scripts, handling cross-platform builds and binary packaging for releases.
internal/actions/ (Business Logic)
This directory holds the logic for every executable command.
actions.go: Contains the criticalInitializesequence, ensuring safe data migration.use.go: Implements the symlink swapping logic. Notably, it leverages themanifoldco/promptuilibrary to render the interactive, scrollable alias selection menu if no arguments are provided.- Command-specific files (
create.go,delete.go,rename.go, etc.) execute the business logic, heavily relying on theutilspackage to interact with the filesystem and OS binaries.
internal/models/ (Data Structures & Extensibility)
Environment: A struct encapsulating dynamic operational paths (StorePath,SSHPath,ResticPath). By passing this struct through the application rather than hardcoding paths, the entire codebase becomes highly testable. Unit tests can construct anEnvironmentpointing to temporary/tmpdirectories, ensuring tests never overwrite a developer's real keys.KeyType®istry.go: SKM uses a registry pattern to define supported SSH key algorithms. TheSupportedKeyTypesmap currently handlesrsaanded25519.- Extensibility: If a contributor wants to add support for ECDSA keys, they simply need to append a new
KeyTypedefinition intoregistry.gowith the appropriateKeyBaseName(e.g.,id_ecdsa). The rest of the application will dynamically adapt.
internal/utils/ (System Interaction)
Execute: A robust wrapper around Go'sos/exec.Command. SKM does not reinvent cryptography; it delegates generation and caching to the OS's native OpenSSH binaries (ssh-keygen,ssh-add).CreateLink/ClearKey: The core symlink engine.CreateLinkhandles relative pathing calculations to ensure symlinks remain valid even if the parent directories are moved.RunHook: Inspects the alias directory for an executable file namedhookand runs it as a child process during a key swap.
pkg/lib/ (External Integrations)
restic.go: Encapsulates all Restic logic. It handles the JSON configuration parsing (restic.json), repository initialization (restic init), and the execution of backup/restore subprocesses while passing the required password file flags securely.