Skip to content

Commit 847addf

Browse files
james-fossajcc333csasarak
authored
[ANE-2123] A fix around listing excluded dirs (#1493)
* [ANE-2123] Get Walk.Discovery.walkWithFilters to avoid listDir calls on excluded dirs * [ANE-2123] Add a spec for walkWithFilters' to check that it does not touch excluded dirs * Update src/Discovery/Walk.hs Co-authored-by: Christopher Sasarak <[email protected]> * [ANE-2123] Address PR comments * [ANE-2123] Fix formatting * [ANE-2123] Update changelog to match our standard format and reflect our readers' expectations --------- Co-authored-by: James Clemer <[email protected]> Co-authored-by: Christopher Sasarak <[email protected]>
1 parent 9a86016 commit 847addf

File tree

11 files changed

+181
-34
lines changed

11 files changed

+181
-34
lines changed

Changelog.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# FOSSA CLI Changelog
22

3+
## 3.9.43
4+
- Discovery: Fix a bug where directories in paths.exclude may still be accessed during discovery which causes an error when users don't have permission to read those directories.
5+
36
## 3.9.42
47
- Licensing: Adds support for the Text-Tabs+Wrap License
58

src/App/Fossa/Analyze.hs

+5-1
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,11 @@ analyze cfg = Diag.context "fossa-analyze" $ do
413413
reachabilityUnitsResult <-
414414
case orgInfo of
415415
(Just (Organization{orgSupportsReachability = False})) -> pure []
416-
_ -> Diag.context "reachability analysis" . runReader (Config.reachabilityConfig cfg) $ analyzeForReachability projectScans
416+
_ ->
417+
Diag.context "reachability analysis"
418+
. runReader (Config.reachabilityConfig cfg)
419+
. runReader filters
420+
$ analyzeForReachability projectScans
417421
let reachabilityUnits = onlyFoundUnits reachabilityUnitsResult
418422

419423
let analysisResult = AnalysisScanResult projectScans vsiResults binarySearchResults manualSrcUnits dynamicLinkedResults maybeLernieResults reachabilityUnitsResult

src/App/Fossa/Reachability/Maven.hs

+4
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import App.Fossa.Reachability.Jar (callGraphFromJars, isValidJar)
77
import App.Fossa.Reachability.Types (CallGraphAnalysis (..))
88
import Control.Carrier.Lift (Lift)
99
import Control.Effect.Diagnostics (Diagnostics, context, fromEither, recover)
10+
import Control.Effect.Reader (Reader)
1011
import Control.Monad (filterM, join)
1112
import Data.Map qualified as Map
1213
import Data.Maybe (catMaybes, fromMaybe)
1314
import Data.String.Conversion (ToText (toText))
1415
import Data.Text (Text, replace)
16+
import Discovery.Filters (AllFilters)
1517
import Effect.Exec (Exec)
1618
import Effect.Logger (Logger, logDebug, pretty)
1719
import Effect.ReadFS (Has, ReadFS, resolveDir', resolveFile)
@@ -32,6 +34,7 @@ mavenJarCallGraph ::
3234
, Has Diagnostics sig m
3335
, Has Exec sig m
3436
, Has (Lift IO) sig m
37+
, Has (Reader AllFilters) sig m
3538
) =>
3639
Path Abs Dir ->
3740
m CallGraphAnalysis
@@ -44,6 +47,7 @@ getJarsByBuild ::
4447
( Has Logger sig m
4548
, Has ReadFS sig m
4649
, Has Diagnostics sig m
50+
, Has (Reader AllFilters) sig m
4751
) =>
4852
Path Abs Dir ->
4953
m [Path Abs File]

src/App/Fossa/Reachability/Upload.hs

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import Data.List (nub)
3737
import Data.Map qualified as Map
3838
import Data.Maybe (mapMaybe)
3939
import Diag.Result (Result (..))
40+
import Discovery.Filters (AllFilters)
4041
import Effect.Exec (Exec)
4142
import Effect.Logger (Logger, logDebug, logInfo, pretty)
4243
import Effect.ReadFS (ReadFS)
@@ -57,6 +58,7 @@ analyzeForReachability ::
5758
, Has (Lift IO) sig m
5859
, Has Debug sig m
5960
, Has (Reader ReachabilityConfig) sig m
61+
, Has (Reader AllFilters) sig m
6062
) =>
6163
[DiscoveredProjectScan] ->
6264
m [SourceUnitReachabilityAttempt]
@@ -107,6 +109,7 @@ callGraphOf ::
107109
, Has (Lift IO) sig m
108110
, Has Debug sig m
109111
, Has (Reader ReachabilityConfig) sig m
112+
, Has (Reader AllFilters) sig m
110113
) =>
111114
DiscoveredProjectScan ->
112115
m SourceUnitReachabilityAttempt

src/Discovery/Walk.hs

+31-5
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ module Discovery.Walk (
1414
) where
1515

1616
import Control.Carrier.Writer.Church
17-
import Control.Effect.Diagnostics
17+
import Control.Effect.Diagnostics (Diagnostics, context, fatal)
1818
import Control.Effect.Reader (Reader, ask)
1919
import Control.Monad.Trans
2020
import Control.Monad.Trans.Maybe
21+
import Data.Bifunctor (second)
2122
import Data.Foldable (find)
2223
import Data.Functor (void)
2324
import Data.Glob qualified as Glob
@@ -73,17 +74,41 @@ pathFilterIntercept ::
7374
AllFilters ->
7475
Path Abs Dir ->
7576
Path Abs Dir ->
77+
[Path Abs Dir] ->
7678
m (o, WalkStep) ->
7779
m (o, WalkStep)
78-
pathFilterIntercept filters base path act = do
80+
pathFilterIntercept filters base dir subdirs act = do
7981
-- We know that the two have the same base, but if that invariant is broken,
8082
-- we just allow the path during discovery. It's better than crashing.
81-
case stripProperPrefix base path of
83+
case stripProperPrefix base dir of
8284
Nothing -> act
8385
Just relative ->
8486
if pathAllowed filters relative
85-
then act
87+
then (fmap . second) skipDisallowed act
8688
else pure (mempty, WalkSkipAll)
89+
where
90+
disallowedSubdirs :: [Text]
91+
disallowedSubdirs = do
92+
subdir <- subdirs
93+
stripped <- stripProperPrefix base subdir
94+
let isAllowed = pathAllowed filters stripped
95+
if isAllowed
96+
then mempty
97+
else pure $ (toText . toFilePath . dirname) subdir
98+
99+
-- skipDisallowed needs to look at either:
100+
-- * WalkStep.WalkContinue
101+
-- * WalkStep.WalkSkipSome [Text]
102+
-- and add on any missing disallowed subdirs
103+
skipDisallowed :: WalkStep -> WalkStep
104+
skipDisallowed action =
105+
if null disallowedSubdirs
106+
then
107+
action
108+
else case action of
109+
WalkContinue -> WalkSkipSome disallowedSubdirs
110+
WalkSkipSome dirs -> WalkSkipSome $ disallowedSubdirs ++ dirs
111+
_ -> action
87112

88113
-- | Like @walk@, but collects the output of @f@ in a monoid.
89114
walk' ::
@@ -117,7 +142,7 @@ walkWithFilters' ::
117142
m o
118143
walkWithFilters' f root = do
119144
filters <- ask
120-
let f' dir subdirs files = pathFilterIntercept filters root dir $ f dir subdirs files
145+
let f' dir subdirs files = pathFilterIntercept filters root dir subdirs $ f dir subdirs files
121146
walk' f' root
122147

123148
-- | Search upwards in the directory tree for the existence of the supplied file.
@@ -169,6 +194,7 @@ walkDir ::
169194
walkDir handler topdir =
170195
context "Walking the filetree" $
171196
void $
197+
-- makeAbsolute topdir >>= walkAvoidLoop Set.empty
172198
-- makeAbsolute topdir >>= walkAvoidLoop Set.empty
173199
walkAvoidLoop Set.empty topdir
174200
where

src/Strategy/Maven/Pom/Closure.hs

+10-7
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,24 @@ import Path.IO qualified as PIO
2727
import Strategy.Maven.Pom.PomFile
2828
import Strategy.Maven.Pom.Resolver
2929

30+
import Control.Effect.Reader (Reader)
3031
import Data.Text (Text)
32+
import Discovery.Filters (AllFilters)
3133

32-
findProjects :: (Has ReadFS sig m, Has Diagnostics sig m) => Path Abs Dir -> m [MavenProjectClosure]
34+
findProjects :: (Has ReadFS sig m, Has Diagnostics sig m, Has (Reader AllFilters) sig m) => Path Abs Dir -> m [MavenProjectClosure]
3335
findProjects basedir = do
3436
pomFiles <- context "Finding pom files" $ findPomFiles basedir
3537
globalClosure <- context "Building global closure" $ buildGlobalClosure pomFiles
3638
context "Building project closures" $ pure (buildProjectClosures basedir globalClosure)
3739

38-
findPomFiles :: (Has ReadFS sig m, Has Diagnostics sig m) => Path Abs Dir -> m [Path Abs File]
39-
findPomFiles dir = execState @[Path Abs File] [] $
40-
flip walk dir $ \_ _ files -> do
41-
let poms = filter (\file -> "pom.xml" `isSuffixOf` fileName file || ".pom" `isSuffixOf` fileName file) files
42-
traverse_ (modify . (:)) poms
40+
findPomFiles :: (Has ReadFS sig m, Has Diagnostics sig m, Has (Reader AllFilters) sig m) => Path Abs Dir -> m [Path Abs File]
41+
findPomFiles dir =
42+
execState @[Path Abs File] [] $
43+
flip walkWithFilters' dir $ \_ _ files -> do
44+
let poms = filter (\file -> "pom.xml" `isSuffixOf` fileName file || ".pom" `isSuffixOf` fileName file) files
45+
traverse_ (modify . (:)) poms
4346

44-
pure (WalkSkipSome ["target"])
47+
pure ((), WalkSkipSome ["target"])
4548

4649
buildProjectClosures :: Path Abs Dir -> GlobalClosure -> [MavenProjectClosure]
4750
buildProjectClosures basedir global = closures

src/Strategy/Node.hs

+3-3
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import Discovery.Filters (AllFilters, withMultiToolFilter)
4949
import Discovery.Walk (
5050
WalkStep (WalkSkipSome),
5151
findFileNamed,
52-
walk',
52+
walkWithFilters',
5353
)
5454
import Effect.Logger (
5555
Logger,
@@ -129,8 +129,8 @@ discover dir = withMultiToolFilter [YarnProjectType, NpmProjectType, PnpmProject
129129
graphs <- context "Splitting global graph into chunks" $ fromMaybe CyclicPackageJson $ splitGraph globalGraph
130130
context "Converting graphs to analysis targets" $ traverse (mkProject <=< identifyProjectType) graphs
131131

132-
collectManifests :: (Has ReadFS sig m, Has Diagnostics sig m) => Path Abs Dir -> m [Manifest]
133-
collectManifests = walk' $ \_ _ files ->
132+
collectManifests :: (Has ReadFS sig m, Has Diagnostics sig m, Has (Reader AllFilters) sig m) => Path Abs Dir -> m [Manifest]
133+
collectManifests = walkWithFilters' $ \_ _ files ->
134134
case findFileNamed "package.json" files of
135135
Nothing -> pure ([], skipJsFolders)
136136
Just jsonFile -> pure ([Manifest jsonFile], skipJsFolders)

src/Strategy/SwiftPM.hs

+34-10
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import Discovery.Simple (simpleDiscover)
1818
import Discovery.Walk (
1919
WalkStep (WalkContinue, WalkSkipSome),
2020
findFileNamed,
21-
walk',
21+
walkWithFilters',
2222
)
2323
import Effect.Logger (Logger, Pretty (pretty), logDebug)
2424
import Effect.ReadFS (ReadFS)
@@ -54,15 +54,27 @@ instance ToJSON SwiftProject
5454
discover :: (Has ReadFS sig m, Has Diagnostics sig m, Has Logger sig m, Has (Reader AllFilters) sig m) => Path Abs Dir -> m [DiscoveredProject SwiftProject]
5555
discover = simpleDiscover findProjects mkProject SwiftProjectType
5656

57-
findProjects :: (Has ReadFS sig m, Has Diagnostics sig m, Has Logger sig m) => Path Abs Dir -> m [SwiftProject]
57+
findProjects ::
58+
( Has ReadFS sig m
59+
, Has Diagnostics sig m
60+
, Has Logger sig m
61+
, Has (Reader AllFilters) sig m
62+
) =>
63+
Path Abs Dir ->
64+
m [SwiftProject]
5865
findProjects dir = do
5966
swiftPackageProjects <- context "Finding swift package projects" $ findSwiftPackageProjects dir
6067
xCodeProjects <- context "Finding xcode projects using swift package manager" $ findXcodeProjects dir
6168
pure (swiftPackageProjects <> xCodeProjects)
6269

63-
-- TODO: determine if walkWithFilters' is safe here
64-
findSwiftPackageProjects :: (Has ReadFS sig m, Has Diagnostics sig m) => Path Abs Dir -> m [SwiftProject]
65-
findSwiftPackageProjects = walk' $ \dir _ files -> do
70+
findSwiftPackageProjects ::
71+
( Has ReadFS sig m
72+
, Has Diagnostics sig m
73+
, Has (Reader AllFilters) sig m
74+
) =>
75+
Path Abs Dir ->
76+
m [SwiftProject]
77+
findSwiftPackageProjects = walkWithFilters' $ \dir _ files -> do
6678
let packageManifestFile = findFileNamed "Package.swift" files
6779
let packageResolvedFile = findFileNamed "Package.resolved" files
6880
case (packageManifestFile, packageResolvedFile) of
@@ -72,9 +84,15 @@ findSwiftPackageProjects = walk' $ \dir _ files -> do
7284
-- Package.resolved without Package.swift or Xcode project file is not a valid swift project.
7385
(Nothing, _) -> pure ([], WalkContinue)
7486

75-
-- TODO: determine if walkWithFilters' is safe here
76-
findXcodeProjects :: (Has ReadFS sig m, Has Diagnostics sig m, Has Logger sig m) => Path Abs Dir -> m [SwiftProject]
77-
findXcodeProjects = walk' $ \dir _ files -> do
87+
findXcodeProjects ::
88+
( Has ReadFS sig m
89+
, Has Diagnostics sig m
90+
, Has Logger sig m
91+
, Has (Reader AllFilters) sig m
92+
) =>
93+
Path Abs Dir ->
94+
m [SwiftProject]
95+
findXcodeProjects = walkWithFilters' $ \dir _ files -> do
7896
let xcodeProjectFile = findFileNamed "project.pbxproj" files
7997
case xcodeProjectFile of
8098
Nothing -> pure ([], WalkContinue)
@@ -89,8 +107,14 @@ findXcodeProjects = walk' $ \dir _ files -> do
89107
-- XCode projects using swift package manager retain Package.resolved,
90108
-- not in the same directory as project file, but rather in workspace's xcshareddata/swiftpm directory.
91109
-- Reference: https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app.
92-
findFirstResolvedFileRecursively :: (Has ReadFS sig m, Has Diagnostics sig m) => Path Abs Dir -> m (Maybe (Path Abs File))
93-
findFirstResolvedFileRecursively baseDir = listToMaybe <$> walk' findFile baseDir
110+
findFirstResolvedFileRecursively ::
111+
( Has ReadFS sig m
112+
, Has Diagnostics sig m
113+
, Has (Reader AllFilters) sig m
114+
) =>
115+
Path Abs Dir ->
116+
m (Maybe (Path Abs File))
117+
findFirstResolvedFileRecursively baseDir = listToMaybe <$> walkWithFilters' findFile baseDir
94118
where
95119
isParentDirSwiftPm :: Path Abs Dir -> Bool
96120
isParentDirSwiftPm d = (dirname d) == [reldir|swiftpm|]

test/Discovery/FiltersSpec.hs

+1-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import Discovery.Filters (
2424
withToolFilter,
2525
)
2626
import Path (Dir, Path, Rel, mkRelDir)
27+
import Test.Fixtures (excludePath)
2728
import Test.Hspec (
2829
Expectation,
2930
Spec,
@@ -284,9 +285,6 @@ testHarness include exclude = traverse_ testSingle
284285
where
285286
testSingle ((buildtool, dir), targets, expected) = applyFilters (AllFilters include exclude) buildtool dir targets `shouldBe` expected
286287

287-
excludePath :: Path Rel Dir -> AllFilters
288-
excludePath path = AllFilters mempty $ comboExclude mempty [path]
289-
290288
excludeTool :: DiscoveredProjectType -> AllFilters
291289
excludeTool tool = AllFilters mempty $ comboExclude [TypeTarget $ toText tool] mempty
292290

0 commit comments

Comments
 (0)