shellfirm 0.3.9

`shellfirm` will intercept any risky patterns (default or defined by you) and prompt you a small challenge for double verification, kinda like a captcha for your terminal.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
---
# -- git:bisect --
- test: "git bisect start"
  description: "match bisect start"
  expect_ids: ["git:bisect"]
- test: "git bisect good"
  description: "match bisect good"
  expect_ids: ["git:bisect"]
- test: "git bisect bad"
  description: "match bisect bad"
  expect_ids: ["git:bisect"]
- test: "git bisect reset"
  description: "match bisect reset"
  expect_ids: ["git:bisect"]

# -- git:cherry_pick --
- test: "git cherry-pick abc123"
  description: "match cherry-pick command"
  expect_ids: ["git:cherry_pick"]
- test: "git cherry-pick --no-commit"
  description: "match cherry-pick without commit"
  expect_ids: ["git:cherry_pick"]

# -- git:clean_force --
- test: "git clean -fd"
  description: "match force clean command"
  expect_ids: ["git:clean_force"]
- test: "git clean -fdx"
  description: "match force clean command with x option"
  expect_ids: ["git:clean_force"]

# -- git:delete_all --
- test: "git  rm *"
  description: "match command"
  expect_ids: ["git:delete_all"]
- test: "git rm ."
  description: "match command"
  expect_ids: ["git:delete_all"]
- test: "git rm README.md"
  description: "negative: removing a specific file should not match"
  expect_ids: []
- test: "gitt rm"
  description: "invalid command"
  expect_ids: []

# -- git:delete_ref --
- test: "git update-ref -d refs/heads/feature"
  description: "match delete reference"
  expect_ids: ["git:delete_ref"]
- test: "git update-ref -d HEAD"
  description: "match delete HEAD reference"
  expect_ids: ["git:delete_ref"]

# -- git:filter_branch --
- test: "git filter-branch --env-filter"
  description: "match filter-branch command"
  expect_ids: ["git:filter_branch"]
- test: "git filter-branch --force"
  description: "match filter-branch with force"
  expect_ids: ["git:filter_branch"]

# -- git:force_checkout --
- test: "git checkout -f main"
  description: "match force checkout"
  expect_ids: ["git:force_checkout"]
- test: "git checkout -f"
  description: "match force checkout current branch"
  expect_ids: ["git:force_checkout"]

# -- git:force_delete_branch --
- test: "git branch -D feature"
  description: "match force delete branch"
  expect_ids: ["git:force_delete_branch"]
- test: "git branch -D"
  description: "match force delete current branch"
  expect_ids: ["git:force_delete_branch"]

# -- git:force_push --
- test: "git push -f"
  description: "match force push command"
  expect_ids: ["git:force_push"]
- test: "git push --force"
  description: "match force push with long option"
  expect_ids: ["git:force_push"]
- test: "git push origin --force"
  description: "match force push with remote before flag"
  expect_ids: ["git:force_push"]
- test: "git push origin main --force"
  description: "match force push with remote and branch before flag"
  expect_ids: ["git:force_push"]
- test: "git push origin -f"
  description: "match force push with remote before short flag"
  expect_ids: ["git:force_push"]
- test: "git push --force-with-lease"
  description: "force push with lease is the safe alternative and should not match"
  expect_ids: []

# -- git:gc_prune --
- test: "git gc --prune=now"
  description: "match garbage collection with prune"
  expect_ids: ["git:gc_prune"]
- test: "git   gc   --prune=now"
  description: "match garbage collection with prune and extra spaces"
  expect_ids: ["git:gc_prune"]
- test: "git gc --aggressive"
  description: "match aggressive garbage collection"
  expect_ids: []
- test: "git gc --prune"
  description: "should not match without =now"
  expect_ids: []

# -- git:interactive_rebase --
- test: "git rebase -i HEAD~3"
  description: "match interactive rebase"
  expect_ids: ["git-strict:rebase", "git:interactive_rebase"]
- test: "git rebase -i"
  description: "match interactive rebase without range"
  expect_ids: ["git-strict:rebase", "git:interactive_rebase"]

# -- git:merge_no_ff --
- test: "git merge --no-ff feature"
  description: "match non-fast-forward merge"
  expect_ids: ["git:merge_no_ff"]
- test: "git merge --abort"
  description: "match merge abort"
  expect_ids: ["git:merge_no_ff"]
- test: "git merge --no-ff"
  description: "match non-fast-forward merge without branch"
  expect_ids: ["git:merge_no_ff"]

# -- git:reset --
- test: "git reset"
  description: "match command"
  expect_ids: ["git:reset"]
- test: "git    reset"
  description: "match command"
  expect_ids: ["git:reset"]
- test: "gitt reset"
  description: "invalid command"
  expect_ids: []

# -- git:worktree_management --
- test: "git worktree add ../other"
  description: "match add worktree"
  expect_ids: ["git:worktree_management"]
- test: "git worktree remove ../other"
  description: "match remove worktree"
  expect_ids: ["git:worktree_management"]
- test: "git worktree add -f ../other"
  description: "match force add worktree"
  expect_ids: ["git:worktree_management"]
- test: "git worktree remove -f ../other"
  description: "match force remove worktree"
  expect_ids: ["git:worktree_management"]

# -- git-strict:add_all --
- test: "git add ."
  description: "match add all files"
  expect_ids: ["git-strict:add_all"]
- test: "git add -A"
  description: "match add all files with -A"
  expect_ids: ["git-strict:add_all"]
- test: "git add --all"
  description: "match add all files with --all"
  expect_ids: ["git-strict:add_all"]
- test: "git add README.md"
  description: "negative: adding a specific file should not match"
  expect_ids: []
- test: "git status"
  description: "negative: status command should not match add pattern"
  expect_ids: []

# -- git-strict:commit_all --
- test: "git commit --all"
  description: "match commit all changes"
  expect_ids: ["git-strict:commit_all"]
- test: "git commit -a"
  description: "match commit all with short option"
  expect_ids: ["git-strict:commit_all"]
- test: "git commit -am 'message'"
  description: "match commit all with message"
  expect_ids: ["git-strict:commit_all"]
- test: "git commit -m 'test'"
  description: "negative: commit with only -m (no -a) should not match"
  expect_ids: []
- test: "git commit --amend"
  description: "negative: amend should not match commit-all check"
  expect_ids: []
- test: "git commit --author='someone'"
  description: "negative: author flag should not match commit-all check"
  expect_ids: []

# -- git-strict:create_tag --
- test: "git tag -a v1.0.0"
  description: "match create annotated tag"
  expect_ids: ["git-strict:create_tag"]
- test: "git tag -a"
  description: "match create annotated tag without name"
  expect_ids: ["git-strict:create_tag"]
- test: "git tag v1.0.0"
  description: "negative: lightweight tag without -a should not match"
  expect_ids: []

# -- git-strict:rebase --
- test: "git rebase main"
  description: "match basic rebase"
  expect_ids: ["git-strict:rebase"]
- test: "git rebase"
  description: "match rebase without branch"
  expect_ids: ["git-strict:rebase"]
- test: "git pull --rebase main"
  description: "negative: pull with --rebase flag is not a rebase command"
  expect_ids: []

# -- git-strict:stash_pop_drop --
- test: "git stash pop"
  description: "match stash pop"
  expect_ids: ["git-strict:stash_pop_drop"]
- test: "git stash drop"
  description: "match stash drop"
  expect_ids: ["git-strict:stash_pop_drop"]
- test: "git stash list"
  description: "negative: listing stash entries should not match"
  expect_ids: []

# -- git-strict:submodule_update --
- test: "git submodule update"
  description: "match submodule update"
  expect_ids: ["git-strict:submodule_update"]
- test: "git submodule deinit"
  description: "match submodule deinit"
  expect_ids: ["git-strict:submodule_update"]
- test: "git submodule update --init"
  description: "match submodule update with init"
  expect_ids: ["git-strict:submodule_update"]
- test: "git submodule status"
  description: "negative: checking submodule status should not match"
  expect_ids: []

# -- git:clean_force — flag reordering --
- test: "git clean -df"
  description: "flag reorder -df now matched after regex fix"
  expect_ids: ["git:clean_force"]

- test: "git clean -fxd"
  description: "flag reorder -fxd now matched after regex fix"
  expect_ids: ["git:clean_force"]

- test: "git clean -xfd"
  description: "flag reorder -xfd now matched after regex fix"
  expect_ids: ["git:clean_force"]

- test: "git clean -dfx"
  description: "flag reorder -dfx now matched after regex fix"
  expect_ids: ["git:clean_force"]

- test: "git clean -xdf"
  description: "flag reorder -xdf now matched after regex fix"
  expect_ids: ["git:clean_force"]

- test: "git clean -dxf"
  description: "flag reorder -dxf now matched after regex fix"
  expect_ids: ["git:clean_force"]

- test: "git clean -f -d"
  description: "separate -f -d flags now matched after regex fix"
  expect_ids: ["git:clean_force"]

- test: "git clean -d -f"
  description: "separate -d -f flags now matched after regex fix"
  expect_ids: ["git:clean_force"]

- test: "git clean -f -d -x"
  description: "three separate flags now matched after regex fix"
  expect_ids: ["git:clean_force"]

- test: "git clean -fdX"
  description: "-fdX starts with -fd, matches"
  expect_ids: ["git:clean_force"]

- test: "git   clean   -fd"
  description: "extra spaces, still matches"
  expect_ids: ["git:clean_force"]

- test: "git clean -fdn"
  description: "-fdn starts with -fd, '-n' substring not present (n preceded by d not -)"
  expect_ids: ["git:clean_force"]

# -- git:force_delete_branch — long-form flags --
- test: "git branch --delete --force feature"
  description: "long-form --delete --force now matched after regex fix"
  expect_ids: ["git:force_delete_branch"]

- test: "git branch -d --force feature"
  description: "-d with --force now matched after regex fix"
  expect_ids: ["git:force_delete_branch"]

- test: "git branch -D feature/my-branch"
  description: "branch with slash in name"
  expect_ids: ["git:force_delete_branch"]

# -- git:force_checkout — long-form flag --
- test: "git checkout --force main"
  description: "long-form --force now matched after regex fix"
  expect_ids: ["git:force_checkout"]

- test: "git checkout -f -- ."
  description: "force checkout with -- separator"
  expect_ids: ["git:force_checkout"]

# -- git:checkout_discard_all --
- test: "git checkout -- ."
  description: "match checkout discard all changes"
  expect_ids: ["git:checkout_discard_all"]
- test: "git checkout -- ./"
  description: "match checkout discard all with trailing slash"
  expect_ids: ["git:checkout_discard_all"]
- test: "git checkout -- *"
  description: "match checkout discard with glob"
  expect_ids: ["git:checkout_discard_all"]
- test: "git  checkout  --  ."
  description: "match checkout discard all with extra spaces"
  expect_ids: ["git:checkout_discard_all"]
- test: "git checkout -- file.txt"
  description: "negative: checkout specific file should not match"
  expect_ids: []
- test: "git checkout -- src/main.rs"
  description: "negative: checkout specific file path should not match"
  expect_ids: []
- test: "git checkout -- .gitignore"
  description: "negative: checkout dotfile should not match"
  expect_ids: []
- test: "git checkout -- .env"
  description: "negative: checkout .env file should not match"
  expect_ids: []

# -- git:restore_discard_all --
- test: "git restore ."
  description: "match restore discard all changes"
  expect_ids: ["git:restore_discard_all"]
- test: "git restore ./"
  description: "match restore discard all with trailing slash"
  expect_ids: ["git:restore_discard_all"]
- test: "git restore *"
  description: "match restore discard with glob"
  expect_ids: ["git:restore_discard_all"]
- test: "git restore --staged ."
  description: "match restore staged discard all"
  expect_ids: ["git:restore_discard_all"]
- test: "git restore --staged ./"
  description: "match restore staged with trailing slash"
  expect_ids: ["git:restore_discard_all"]
- test: "git restore --source=HEAD ."
  description: "match restore with source flag"
  expect_ids: ["git:restore_discard_all"]
- test: "git restore --staged --worktree ."
  description: "match restore with multiple flags"
  expect_ids: ["git:restore_discard_all"]
- test: "git  restore  ."
  description: "match restore discard all with extra spaces"
  expect_ids: ["git:restore_discard_all"]
- test: "git restore file.txt"
  description: "negative: restore specific file should not match"
  expect_ids: []
- test: "git restore --staged file.txt"
  description: "negative: restore staged specific file should not match"
  expect_ids: []
- test: "git restore src/main.rs"
  description: "negative: restore specific file path should not match"
  expect_ids: []
- test: "git restore .gitignore"
  description: "negative: restore dotfile should not match"
  expect_ids: []
- test: "git restore .env"
  description: "negative: restore .env file should not match"
  expect_ids: []

# -- git:reset — more variants --
- test: "git reset --hard"
  description: "hard reset, most dangerous variant"
  expect_ids: ["git:reset"]

- test: "git reset --hard HEAD~3"
  description: "hard reset to specific commit"
  expect_ids: ["git:reset"]

- test: "git reset --soft HEAD~1"
  description: "soft reset filtered out by NotContains"
  expect_ids: []

- test: "git reset --hard origin/main"
  description: "hard reset to remote"
  expect_ids: ["git:reset"]

# -- git:push_mirror --
- test: "git push --mirror origin"
  description: "match push --mirror with remote"
  expect_ids: ["git:push_mirror"]
- test: "git push origin --mirror"
  description: "match push with remote before --mirror"
  expect_ids: ["git:push_mirror"]
- test: "git push --mirror"
  description: "match push --mirror without remote"
  expect_ids: ["git:push_mirror"]
- test: "git push origin main"
  description: "negative: regular push should not match mirror"
  expect_ids: []

# -- git:push_delete_branch --
- test: "git push origin --delete feature-branch"
  description: "match push --delete branch"
  expect_ids: ["git:push_delete_branch"]
- test: "git push origin --delete main"
  description: "match push --delete main branch"
  expect_ids: ["git:push_delete_branch"]
- test: "git push origin :feature-branch"
  description: "match push colon syntax to delete remote branch"
  expect_ids: ["git:push_delete_branch"]
- test: "git push origin main"
  description: "negative: regular push should not match delete"
  expect_ids: []

# -- git:reflog_expire --
- test: "git reflog expire --expire=now --all"
  description: "match reflog expire now with --all"
  expect_ids: ["git:reflog_expire"]
- test: "git reflog expire --expire=now"
  description: "match reflog expire now without --all"
  expect_ids: ["git:reflog_expire"]
- test: "git reflog show"
  description: "negative: reflog show should not match"
  expect_ids: []
- test: "git reflog expire --expire=90.days"
  description: "negative: normal expire should not match"
  expect_ids: []

# -- git:stash_clear --
- test: "git stash clear"
  description: "match stash clear"
  expect_ids: ["git:stash_clear"]
- test: "git  stash  clear"
  description: "match stash clear with extra spaces"
  expect_ids: ["git:stash_clear"]
- test: "git stash list"
  description: "negative: stash list should not match"
  expect_ids: []
- test: "git stash pop"
  description: "negative: stash pop should not match stash_clear"
  expect_ids: ["git-strict:stash_pop_drop"]
- test: "git stash drop"
  description: "negative: stash drop should not match stash_clear"
  expect_ids: ["git-strict:stash_pop_drop"]

# ====== EDGE CASE / STRESS TESTS ======

# -- git:force_push edge cases --
- test: "git push origin feature --force-if-includes"
  description: "force-if-includes is safe alternative and should not match"
  expect_ids: []
- test: "git  push  origin  -f"
  description: "EDGE: force push with extra spaces"
  expect_ids: ["git:force_push"]
- test: "git push -f origin main"
  description: "EDGE: -f immediately after push before remote"
  expect_ids: ["git:force_push"]

# -- git:gc_prune edge cases --
- test: "git gc --aggressive --prune=now"
  description: "match gc with intervening flags before --prune=now"
  expect_ids: ["git:gc_prune"]

# -- git:reflog_expire edge cases --
- test: "git reflog expire --all --expire=now"
  description: "match reflog expire with intervening flags before --expire=now"
  expect_ids: ["git:reflog_expire"]

# -- git:delete_all edge cases --
- test: "git rm -f *"
  description: "match rm with flag before wildcard"
  expect_ids: ["git:delete_all", "fs:recursively_delete"]
- test: "git rm -r ."
  description: "match rm with flag before dot"
  expect_ids: ["git:delete_all", "fs:recursively_delete"]
- test: "git  rm  ."
  description: "match rm dot with extra spaces"
  expect_ids: ["git:delete_all"]
- test: "git rm .."
  description: "negative: parent dir .. should not match delete all"
  expect_ids: []

# -- git:clean_force edge cases --
- test: "git clean --force -d"
  description: "match clean with --force long-form"
  expect_ids: ["git:clean_force"]
- test: "git clean -f -x -d"
  description: "EDGE: three separate flags with -x between"
  expect_ids: ["git:clean_force"]

# -- git:force_checkout edge cases --
- test: "git checkout main -f"
  description: "match force checkout with -f after branch name"
  expect_ids: ["git:force_checkout"]
- test: "git  checkout  --force"
  description: "match force checkout with extra spaces"
  expect_ids: ["git:force_checkout"]

# -- git:interactive_rebase edge cases --
- test: "git rebase --interactive HEAD~3"
  description: "match interactive rebase with --interactive long-form"
  expect_ids: ["git-strict:rebase", "git:interactive_rebase"]

# -- git:delete_ref edge cases --
- test: "git update-ref --delete refs/heads/main"
  description: "match delete ref with --delete long-form"
  expect_ids: ["git:delete_ref"]
- test: "git  update-ref  -d  refs/stash"
  description: "EDGE: extra spaces in delete ref"
  expect_ids: ["git:delete_ref"]

# -- git-strict:create_tag edge cases --
- test: "git tag --annotate v1.0"
  description: "match annotated tag with --annotate long-form"
  expect_ids: ["git-strict:create_tag"]

# -- git:push_delete_branch edge cases --
- test: "git push --delete origin feature"
  description: "match push delete with --delete before remote"
  expect_ids: ["git:push_delete_branch"]
- test: "git  push  origin  --delete  feature"
  description: "match push delete with extra spaces"
  expect_ids: ["git:push_delete_branch"]
- test: "git push origin :refs/heads/feature"
  description: "EDGE: full refspec delete"
  expect_ids: ["git:push_delete_branch"]

# -- git-strict:add_all edge cases --
- test: "git add -p ."
  description: "EDGE: -p before dot - should not match add_all"
  expect_ids: []
- test: "git add --all --verbose"
  description: "EDGE: --all with trailing flag"
  expect_ids: ["git-strict:add_all"]

# -- git:stash_clear edge cases --
- test: "git stash clearing"
  description: "EDGE: word starting with clear should not match"
  expect_ids: []