@@ -53,4 +53,106 @@ describe('evaluateShellCommandReadOnly', () => {
5353 const result = isShellCommandReadOnly ( 'FOO=bar ls' ) ;
5454 expect ( result ) . toBe ( true ) ;
5555 } ) ;
56+
57+ describe ( 'awk command security' , ( ) => {
58+ it ( 'allows safe awk commands' , ( ) => {
59+ expect ( isShellCommandReadOnly ( "awk '{print $1}' file.txt" ) ) . toBe ( true ) ;
60+ expect ( isShellCommandReadOnly ( 'awk \'BEGIN {print "hello"}\'' ) ) . toBe (
61+ true ,
62+ ) ;
63+ expect ( isShellCommandReadOnly ( "awk '/pattern/ {print}' file.txt" ) ) . toBe (
64+ true ,
65+ ) ;
66+ } ) ;
67+
68+ it ( 'rejects awk with system() calls' , ( ) => {
69+ expect ( isShellCommandReadOnly ( 'awk \'BEGIN {system("rm -rf /")}\'' ) ) . toBe (
70+ false ,
71+ ) ;
72+ expect (
73+ isShellCommandReadOnly ( 'awk \'{system("touch file")}\' input.txt' ) ,
74+ ) . toBe ( false ) ;
75+ expect ( isShellCommandReadOnly ( 'awk \'BEGIN { system ( "ls" ) }\'' ) ) . toBe (
76+ false ,
77+ ) ;
78+ } ) ;
79+
80+ it ( 'rejects awk with file output redirection' , ( ) => {
81+ expect (
82+ isShellCommandReadOnly ( 'awk \'{print > "output.txt"}\' input.txt' ) ,
83+ ) . toBe ( false ) ;
84+ expect (
85+ isShellCommandReadOnly ( 'awk \'{printf "%s\\n", $0 > "file.txt"}\'' ) ,
86+ ) . toBe ( false ) ;
87+ expect (
88+ isShellCommandReadOnly ( 'awk \'{print >> "append.txt"}\' input.txt' ) ,
89+ ) . toBe ( false ) ;
90+ expect (
91+ isShellCommandReadOnly ( 'awk \'{printf "%s" >> "file.txt"}\'' ) ,
92+ ) . toBe ( false ) ;
93+ } ) ;
94+
95+ it ( 'rejects awk with command pipes' , ( ) => {
96+ expect ( isShellCommandReadOnly ( 'awk \'{print | "sort"}\' input.txt' ) ) . toBe (
97+ false ,
98+ ) ;
99+ expect (
100+ isShellCommandReadOnly ( 'awk \'{printf "%s\\n", $0 | "wc -l"}\'' ) ,
101+ ) . toBe ( false ) ;
102+ } ) ;
103+
104+ it ( 'rejects awk with getline from commands' , ( ) => {
105+ expect ( isShellCommandReadOnly ( 'awk \'BEGIN {getline < "date"}\'' ) ) . toBe (
106+ false ,
107+ ) ;
108+ expect ( isShellCommandReadOnly ( 'awk \'BEGIN {"date" | getline}\'' ) ) . toBe (
109+ false ,
110+ ) ;
111+ } ) ;
112+
113+ it ( 'rejects awk with close() calls' , ( ) => {
114+ expect ( isShellCommandReadOnly ( 'awk \'BEGIN {close("file")}\'' ) ) . toBe (
115+ false ,
116+ ) ;
117+ expect ( isShellCommandReadOnly ( "awk '{close(cmd)}' input.txt" ) ) . toBe (
118+ false ,
119+ ) ;
120+ } ) ;
121+ } ) ;
122+
123+ describe ( 'sed command security' , ( ) => {
124+ it ( 'allows safe sed commands' , ( ) => {
125+ expect ( isShellCommandReadOnly ( "sed 's/foo/bar/' file.txt" ) ) . toBe ( true ) ;
126+ expect ( isShellCommandReadOnly ( "sed -n '1,5p' file.txt" ) ) . toBe ( true ) ;
127+ expect ( isShellCommandReadOnly ( "sed '/pattern/d' file.txt" ) ) . toBe ( true ) ;
128+ } ) ;
129+
130+ it ( 'rejects sed with execute command' , ( ) => {
131+ expect ( isShellCommandReadOnly ( "sed 's/foo/bar/e' file.txt" ) ) . toBe ( false ) ;
132+ expect ( isShellCommandReadOnly ( "sed 'e date' file.txt" ) ) . toBe ( false ) ;
133+ } ) ;
134+
135+ it ( 'rejects sed with write command' , ( ) => {
136+ expect (
137+ isShellCommandReadOnly ( "sed 's/foo/bar/w output.txt' file.txt" ) ,
138+ ) . toBe ( false ) ;
139+ expect ( isShellCommandReadOnly ( "sed 'w backup.txt' file.txt" ) ) . toBe ( false ) ;
140+ } ) ;
141+
142+ it ( 'rejects sed with read command' , ( ) => {
143+ expect (
144+ isShellCommandReadOnly ( "sed 's/foo/bar/r input.txt' file.txt" ) ,
145+ ) . toBe ( false ) ;
146+ expect ( isShellCommandReadOnly ( "sed 'r header.txt' file.txt" ) ) . toBe ( false ) ;
147+ } ) ;
148+
149+ it ( 'still rejects sed in-place editing' , ( ) => {
150+ expect ( isShellCommandReadOnly ( "sed -i 's/foo/bar/' file.txt" ) ) . toBe (
151+ false ,
152+ ) ;
153+ expect (
154+ isShellCommandReadOnly ( "sed --in-place 's/foo/bar/' file.txt" ) ,
155+ ) . toBe ( false ) ;
156+ } ) ;
157+ } ) ;
56158} ) ;
0 commit comments