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:
| Delimiter | Used for | Example tools |
|---|---|---|
; | SQL-based tools | psql, mysql, sqlite3 |
\n (newline) | Line-oriented tools | redis-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 FROMwithoutWHERE(Critical)UPDATEwithoutWHERE(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 wraprequires 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