GitHub
10/26/2026, 1:48 PMosctrl-cli has two connection modes: --db (local database) and the API. --api defaults to true, so a command run with --db has both modes on. Some commands only work in one mode and assumed the other was off, which gave nil-pointer panics:
• 17 database-only commands (settings, permissions, packs, scheduled queries, osquery options) panicked in the default API mode, because the database managers were never created. For example osctrl-cli settings show or env add-osquery-option.
• 7 alert commands only work through the API. They already returned an error with --db, but only after the database had been initialised.
• 5 env commands (add, update, delete, new-flags, add-posture-queries) printed "API not supported yet" and exited from inside the command.
• --api=false made every command succeed silently without doing anything.
This follows the user edit crash fixed in #1117.
Change
• cliWrapperDB and cliWrapperAPI are new wrappers for single-mode commands, alongside the existing cliWrapper. They share one core, and a pure checkMode(mode, dbFlag, apiFlag) decides first, before any database or API setup and before any prompt. A wrong-mode run prints a clear message and exits 1:
• this command works with the local database only: run it with --db (and -D <db config file>)
• this command works through the API only: run it without --db
• this command works through the API only: enable --api
• no connection mode selected: use --db (with -D <db config file>) or --api
• With --db, apiFlag is now set to false before the command runs, so an if apiFlag branch can never run with a nil API client.
• The 17 database-only commands and the 5 "not supported yet" environment commands are registered with cliWrapperDB, and the dead "not supported" branches are removed. The 7 alert commands are registered with cliWrapperAPI, and their requireAPI() helper is removed.
• TestCommandsRegisteredForTheirMode is a static test that fails when:
• a command that only uses database managers is registered with the plain wrapper
• a command that only uses the API client is registered with the plain wrapper
• a command registered DB-only or API-only uses the other mode's client or managers
• a bare if apiFlag { appears
It only looks at names inside a function's own body, so a helper that uses a manager is not detected. The test's comment says so.
• --db and --api help text now says what they imply. MCP.md shows --db -D <config> on user permissions, which is database-only and used to do nothing silently without it.
Behavior notes
• Commands that used to panic or do nothing in the wrong mode now exit 1 with a message. No script, Makefile, docker or provision call in the repo relied on that: every scripted osctrl-cli call passes --db.
• --api=false without --db now exits 1 instead of exiting 0 silently.
Validation
• go test ./cmd/cli/..., go vet ./cmd/cli/..., gofmt -l cmd/cli and `golangci-lint run ./cmd/cli/...`: clean.
• Reproduced the panics in API mode (settings show, env add-osquery-option, env add-scheduled-query) before the change.
• Ran the built CLI against a throwaway SQLite database:
• a DB-only command in API mode prints the DB-only message and exits 1
• alert rules list with --db prints "run it without --db" and exits 1
• --api=false on an API-only command prints "enable --api" and exits 1
• --api=false node list prints "no connection mode selected"
• a command that works in both modes still works with --db
• New tests cover:
• every mode and flag combination in checkMode
• the real wrapper rejecting the wrong mode without a panic, and never calling the action
• --db winning over the default API flag
• the registration guard
jmpsec/osctrlGitHub
10/26/2026, 2:26 PM