mirror of
https://github.com/koalaman/shellcheck.git
synced 2025-08-08 12:37:14 +08:00
SC2114 about rm -rf /usr is no longer silenced by --
This commit is contained in:
@@ -86,6 +86,7 @@ commandChecks = [
|
||||
,checkDeprecatedEgrep
|
||||
,checkDeprecatedFgrep
|
||||
,checkWhileGetoptsCase
|
||||
,checkCatastrophicRm
|
||||
]
|
||||
|
||||
buildCommandMap :: [CommandCheck] -> Map.Map CommandName (Token -> Analysis)
|
||||
@@ -756,6 +757,65 @@ checkWhileGetoptsCase = CommandCheck (Exactly "getopts") f
|
||||
T_Redirecting _ _ x@(T_CaseExpression {}) -> return x
|
||||
_ -> Nothing
|
||||
|
||||
prop_checkCatastrophicRm1 = verify checkCatastrophicRm "rm -r $1/$2"
|
||||
prop_checkCatastrophicRm2 = verify checkCatastrophicRm "rm -r /home/$foo"
|
||||
prop_checkCatastrophicRm3 = verifyNot checkCatastrophicRm "rm -r /home/${USER:?}/*"
|
||||
prop_checkCatastrophicRm4 = verify checkCatastrophicRm "rm -fr /home/$(whoami)/*"
|
||||
prop_checkCatastrophicRm5 = verifyNot checkCatastrophicRm "rm -r /home/${USER:-thing}/*"
|
||||
prop_checkCatastrophicRm6 = verify checkCatastrophicRm "rm --recursive /etc/*$config*"
|
||||
prop_checkCatastrophicRm8 = verify checkCatastrophicRm "rm -rf /home"
|
||||
prop_checkCatastrophicRm10= verifyNot checkCatastrophicRm "rm -r \"${DIR}\"/{.gitignore,.gitattributes,ci}"
|
||||
prop_checkCatastrophicRm11= verify checkCatastrophicRm "rm -r /{bin,sbin}/$exec"
|
||||
prop_checkCatastrophicRm12= verify checkCatastrophicRm "rm -r /{{usr,},{bin,sbin}}/$exec"
|
||||
prop_checkCatastrophicRm13= verifyNot checkCatastrophicRm "rm -r /{{a,b},{c,d}}/$exec"
|
||||
prop_checkCatastrophicRmA = verify checkCatastrophicRm "rm -rf /usr /lib/nvidia-current/xorg/xorg"
|
||||
prop_checkCatastrophicRmB = verify checkCatastrophicRm "rm -rf \"$STEAMROOT/\"*"
|
||||
checkCatastrophicRm = CommandCheck (Basename "rm") $ \t ->
|
||||
when (isRecursive t) $
|
||||
mapM_ (mapM_ checkWord . braceExpand) $ arguments t
|
||||
where
|
||||
isRecursive = any (`elem` ["r", "R", "recursive"]) . map snd . getAllFlags
|
||||
|
||||
checkWord token =
|
||||
case getLiteralString token of
|
||||
Just str ->
|
||||
when (fixPath str `elem` importantPaths) $
|
||||
warn (getId token) 2114 "Warning: deletes a system directory."
|
||||
Nothing ->
|
||||
checkWord' token
|
||||
|
||||
checkWord' token = fromMaybe (return ()) $ do
|
||||
filename <- getPotentialPath token
|
||||
let path = fixPath filename
|
||||
return . when (path `elem` importantPaths) $
|
||||
warn (getId token) 2115 $ "Use \"${var:?}\" to ensure this never expands to " ++ path ++ " ."
|
||||
|
||||
fixPath filename =
|
||||
let normalized = skipRepeating '/' . skipRepeating '*' $ filename in
|
||||
if normalized == "/" then normalized else stripTrailing '/' normalized
|
||||
|
||||
getPotentialPath = getLiteralStringExt f
|
||||
where
|
||||
f (T_Glob _ str) = return str
|
||||
f (T_DollarBraced _ word) =
|
||||
let var = onlyLiteralString word in
|
||||
-- This shouldn't handle non-colon cases.
|
||||
if any (`isInfixOf` var) [":?", ":-", ":="]
|
||||
then Nothing
|
||||
else return ""
|
||||
f _ = return ""
|
||||
|
||||
stripTrailing c = reverse . dropWhile (== c) . reverse
|
||||
skipRepeating c (a:b:rest) | a == b && b == c = skipRepeating c (b:rest)
|
||||
skipRepeating c (a:r) = a:skipRepeating c r
|
||||
skipRepeating _ [] = []
|
||||
|
||||
paths = [
|
||||
"", "/bin", "/etc", "/home", "/mnt", "/usr", "/usr/share", "/usr/local",
|
||||
"/var", "/lib", "/dev", "/media", "/boot", "/lib64", "/usr/bin"
|
||||
]
|
||||
importantPaths = filter (not . null) $
|
||||
["", "/", "/*", "/*/*"] >>= (\x -> map (++x) paths)
|
||||
|
||||
return []
|
||||
runTests = $( [| $(forAllProperties) (quickCheckWithResult (stdArgs { maxSuccess = 1 }) ) |])
|
||||
|
Reference in New Issue
Block a user