$ shellfirm

Interactive Wrapper

Protect live database and REPL sessions with shellfirm wrap

shellfirm's shell hooks intercept commands before execution, but they cannot protect you inside interactive sessions like psql, mysql, redis-cli, or mongosh. The shellfirm wrap command solves this by creating a PTY (pseudo-terminal) proxy that intercepts statements before they reach the underlying program.

How it works

shellfirm wrap launches the target program inside a PTY proxy. As you type, shellfirm buffers input and watches for statement delimiters (; for SQL tools, newlines for line-oriented tools). When a complete statement is detected, it runs through the full check pipeline before being forwarded to the program.

Basic usage

# Wrap a PostgreSQL session
shellfirm wrap psql -h localhost -U postgres

# Wrap a Redis CLI session
shellfirm wrap redis-cli

# Wrap a MySQL session
shellfirm wrap mysql -u root -p

# Wrap a MongoDB shell
shellfirm wrap mongosh mongodb://localhost/mydb

The wrapped program behaves exactly like the original -- same prompt, same tab completion, same scrollback. The only difference is that dangerous statements are intercepted before execution.

Statement delimiters

shellfirm needs to know where one statement ends and another begins. The delimiter determines this boundary:

DelimiterUsed forExample tools
;SQL-based toolspsql, mysql, sqlite3
\n (newline)Line-oriented toolsredis-cli, mongosh

Automatic detection

shellfirm has built-in defaults for common tools. When you run shellfirm wrap psql, it automatically uses ; as the delimiter.

Override the delimiter

Use the --delimiter flag to override:

# Force semicolon delimiter
shellfirm wrap --delimiter ';' sqlite3 mydb.sqlite

# Force newline delimiter
shellfirm wrap --delimiter '\n' custom-repl

What gets intercepted

Inside a wrapped session, shellfirm checks statements against the same pattern database used for shell commands. The most relevant patterns for interactive sessions are:

SQL (psql, mysql):

  • DROP DATABASE / DROP TABLE (Critical)
  • TRUNCATE TABLE (Critical)
  • DELETE FROM without WHERE (Critical)
  • UPDATE without WHERE (High)

Redis:

  • FLUSHALL (Critical)
  • FLUSHDB (High)
  • SHUTDOWN (Critical)

MongoDB:

  • db.dropDatabase() (Critical)
  • db.collection.drop() (Critical)

Example: protected psql session

$ shellfirm wrap psql -h localhost -U postgres
psql (15.4)
Type "help" for help.

postgres=# DROP TABLE users;

============ RISKY COMMAND DETECTED ============
Severity: CRITICAL
Description: Dropping a table will permanently delete all its data.
Alternative: Use SELECT before DROP to verify the table
  (Lets you confirm you are targeting the right table before dropping it.)

? Solve the challenge:: 4 + 7 = ? Esc to cancel ›

Configuration

Per-tool settings

Configure delimiter and check groups per tool in ~/.config/shellfirm/settings.yaml:

wrappers:
  tools:
    psql:
      delimiter: ";"
      check_groups:
        - database
        - psql
    redis-cli:
      delimiter: "\n"
      check_groups:
        - redis
    mongosh:
      delimiter: "\n"
      check_groups:
        - mongodb
    mysql:
      delimiter: ";"
      check_groups:
        - database
        - mysql

When check_groups is specified, only patterns from those groups are active during the wrapped session. This reduces noise by filtering out irrelevant patterns (e.g., no filesystem checks inside a psql session).

When check_groups is empty (the default), all active checks from your global settings are used.

Limitations

  • shellfirm wrap requires a PTY-capable terminal
  • Multi-line statements are accumulated until the delimiter is seen
  • Tab completion and other terminal features pass through transparently
  • The wrapped program's exit code is forwarded as shellfirm's exit code