Tool packs¶
A tool pack describes one CLI tool in one JSON file. One generic shim reads the pack, so a new tool needs no new code.
CmdWarden has three built-in packs: npm, aws, and kubectl. The tools gh, git, az, and docker keep their own code, because they have strong mode and credential helpers.
Use a pack¶
cw harden npm # find npm.cmd on PATH, pin it, install npm.exe (the pack shim)
cw harden --list # pack tools show next to the built-in tools
cw unharden npm # remove the pin and the shim
cw harden --list has a source column: built-in, pack, or user pack. A user pack that does not load shows a pack not loaded line with the reason.
Write your own pack¶
Put a JSON file in %LOCALAPPDATA%\CmdWarden\packs\. The file name does not matter; the tool field names the tool. A user pack with the same tool as a built-in pack replaces it.
{
"tool": "terraform",
"displayName": "Terraform",
"binaries": ["terraform.exe"],
"secretEnv": ["TF_TOKEN_app_terraform_io"],
"flagsWithValue": ["-chdir", "-var-file"],
"default": "unknown",
"rules": [
// First match wins. Put the narrow rules first.
{ "match": "output -json|-raw", "class": "secret-reveal" },
{ "match": "destroy", "class": "write", "risk": "high" },
{ "match": "apply -auto-approve", "class": "write", "risk": "high" },
{ "match": "apply|import|taint|untaint|state", "class": "write" },
{ "match": "plan|validate|fmt|show|output|providers|version|graph", "class": "read" }
],
"secretFiles": [
{ "path": "~/AppData/Roaming/terraform.d/credentials.tfrc.json", "pattern": "\"token\"\\s*:", "title": "Plain Terraform Cloud token" }
],
"samples": [
{ "argv": "plan", "class": "read" },
{ "argv": "destroy -target=aws_s3_bucket.logs", "class": "write" },
{ "argv": "output -raw db_password", "class": "secret-reveal" }
]
}
Then run cw harden terraform. The pack file may have // comments.
Fields¶
| Field | What it does |
|---|---|
tool |
The command name: lower case letters, digits, ., -, _. The shim is <tool>.exe. It cannot be gh, git, az, or docker. |
displayName |
The name in the Vault app and in messages. |
logo |
Optional { "path": "<SVG path data in a 24x24 box>", "color": "#RRGGBB" } for the Vault app and the Approval Gate. |
binaries |
File names of the real tool, in order, for example ["npm.cmd", "npm.exe"]. Each ends in .exe, .cmd, or .bat. |
secretEnv |
Vault names. On an allowed run, each name that is in the vault goes into the child env as a variable of the same name. Save a value with cw save <NAME>. |
flagsWithValue |
Flags that take the next word as their value, so that word is not a command word. --flag=value needs no entry. |
default |
The class of a command that no rule matches. The default is unknown. |
rules |
The class rules. The first rule that matches wins. |
secretFiles |
Config files that cw scan reads for a plain secret. |
samples |
Sample commands and their class. |
Rules¶
A rule has match, class, and two optional fields.
matchis words and flags split by spaces.- A word matches the command words in order, from the first one.
*and?are wildcards.a|bis either word. - A flag (a token that starts with
-) must be somewhere in the command, alone or asflag=value.-a|-bis either flag. - Words after
--belong to the child command and do not count.
- A word matches the command words in order, from the first one.
classisread,write,secret-reveal, orunknown. Policy decides from the class, as for the built-in tools.secrets(defaulttrue):falsegives the run no secret. Use it for commands that start other code, for examplenpm runornpm installwithout--ignore-scripts.risk(defaultnormal):highalways shows the popup below the Full level, and no remembered answer covers it.lowlets an enrolled launcher run the write whencw policy low-risk allowis on.
A command that ends in --help or -h, a command of only --version, -v, or -V, and a command whose first word is help are help. Help is read and gets no secret.
Secret files¶
path starts with ~ for the user profile, or is relative to the working folder. pattern is a regular expression for one line. A matching line is a high finding. The finding names the file and the line number, never the value. remediation is optional.
cw scan also reports a pack secret that is set in the environment, and a tool on PATH that has no pin.
Samples are the pack tests¶
A pack does not load when a sample gets a different class. So each cw harden and each Session Agent call checks the samples of the pack. The test suite checks the samples of every built-in pack. Add a sample for each rule you write.
Limits¶
- Compat mode only. The tool's own config and credential store stay in place. An absolute path to the real tool skips the shim.
- A
.cmdor.battool runs throughcmd.exe. The shim puts each argument in quotes. It stops the run when an argument has a", a line break, or a%NAME%pair, becausecmd.exewould read it as code. - The risk line on the popup is plain for pack tools:
Runs <command>. You cannot undo this.for a high-risk rule.