Desktop Material

TUI security and failure modes

Historical prototype record: This page preserves the July 27, 2026 TUI experiment. It is not current supported-product guidance or a Windows-release blocker.

Process execution

Git, GitHub CLI, editor, and terminal launches use argument arrays with shell=False. NUL/control validation, explicit repository working directories, stdin policy, captured output, and timeouts are owned at adapter boundaries. User text is never concatenated into a shell command.

Git timeouts terminate the process group and collect final output under a short bound. GitHub calls disable prompts, pagers, color, and update notices. Timeout or cancellation does not imply the remote operation had no effect; refresh local and remote state before retrying a mutation.

Credentials and remote data

The app does not claim that a user is authorized merely because gh has a credential. GitHub still enforces repository access and scopes.

Filesystem and persistence

Resolved XDG roots keep app state outside working copies. Directories and files request private Unix permissions. TOML writes are locked and atomic. SQLite uses WAL, busy timeout, foreign keys, and migrations. Local history is isolated and never auto-pushed.

Symlink, filesystem-permission, read-only mount, disk-full, and concurrent-writer errors surface without replacing the last valid config. App-owned state can contain private paths and notification content; protect backups accordingly.

Regex denial of service

Only google-re2 evaluates user patterns. Pattern/input/memory/match/capture bounds apply before or during iteration. The app never falls back to Python re or a shell tool for a rejected pattern. See Search and RE2.

Destructive operations

Decision dialogs are reserved for actions that need a choice. They name the repository object and allow cancellation. A confirmation is not a stale-state proof: Git and GitHub can still reject a changed branch, head SHA, lock, scope, or repository.

The preview does not auto-remove index locks, reset repositories, force-push, or delete project directories. Clone/new destinations are reviewed inputs.

Failure table

Failure User-visible behavior Safe recovery
invalid/non-repository path open is refused choose the intended Git working copy
Git missing or timed out pane/action error notification install Git or inspect the active process, then refresh
repository lock/in-progress operation Git error remains visible finish/abort the owning Git workflow deliberately
gh missing/signed out/scope short GitHub pane reports prerequisite use trusted gh auth flow outside the TUI
provider rate limit/server error bounded failure, no infinite retry wait or inspect provider status, then refresh
invalid/oversized regex validation/limit message correct it or switch explicitly to Literal
malformed config defaults for the run; bad file preserved move aside, compare, and repair the TOML
SQLite unavailable notice history degrades repair XDG permissions/storage; primary Git action must not be undone implicitly
editor/terminal unavailable non-blocking notice select an installed executable
narrow/limited terminal compact layout and scrolling enlarge it or use keyboard navigation

Reporting

Include the version, OS/distribution, terminal and multiplexer, Python version, Git version, gh version without authentication data, exact action, sanitized error, and whether a remote mutation may have begun. Never attach config, credential stores, environment dumps, or screenshots containing tokens/private repository data without redaction at the source.