|
1 | 1 | #!/usr/bin/env cabal
|
2 | 2 | {- cabal:
|
3 |
| -build-depends: base, csv |
| 3 | +build-depends: base, xml |
4 | 4 | -}
|
5 |
| --- | Use this script to update the CWE.Raw module: |
6 |
| --- Go to https://cwe.mitre.org/data/downloads.html |
7 |
| --- Download and extract the 'Software Development' and 'CWE Simplified Mapping' CSV.zip files |
8 |
| --- Run the following command: ./RenderCsvData.hs | fourmolu --stdin-input-file ./src/CWE/Raw.hs > src/CWE/Raw.hs |
| 5 | +{-# LANGUAGE NamedFieldPuns #-} |
| 6 | +-- | Use this script to update the Security.CWE.Data module: |
| 7 | +-- Download and extract https://cwe.mitre.org/data/xml/cwec_latest.xml.zip |
| 8 | +-- Run the following command: cat cwec_v4.12.xml | ./RenderCsvData.hs | fourmolu --stdin-input-file ./src/Security/CWE/Data.hs > src/Security/CWE/Data.hs |
9 | 9 | module Main where
|
10 | 10 |
|
11 | 11 | import Data.List
|
12 | 12 | import Data.Maybe
|
13 |
| -import Text.CSV |
14 | 13 | import Text.Read
|
15 | 14 |
|
| 15 | +import qualified Text.XML.Light as XML |
| 16 | + |
16 | 17 | main :: IO ()
|
17 | 18 | main = do
|
18 |
| - dbs <- traverse readCSV ["699.csv", "1003.csv"] |
19 |
| - putStrLn $ unlines $ renderSource $ concat dbs |
| 19 | + db <- readXML <$> getContents |
| 20 | + putStrLn $ unlines $ renderSource $ db |
| 21 | + |
| 22 | +data Weakness = Weakness |
| 23 | + { wid :: Word |
| 24 | + , wname :: String |
| 25 | + } |
20 | 26 |
|
21 |
| -readCSV :: FilePath -> IO CSV |
22 |
| -readCSV fp = do |
23 |
| - txt <- readFile fp |
24 |
| - case Text.CSV.parseCSV "stdin" txt of |
25 |
| - Left e -> error ("bad csv: " <> show e) |
26 |
| - Right records -> pure (drop 1 records) |
| 27 | +readXML :: String -> [Weakness] |
| 28 | +readXML str = case XML.parseXMLDoc str of |
| 29 | + Just |
| 30 | + ( XML.Element |
| 31 | + (XML.QName "Weakness_Catalog" _ _) |
| 32 | + _ |
| 33 | + ( _ |
| 34 | + : ( XML.Elem |
| 35 | + ((XML.Element (XML.QName "Weaknesses" _ _) _ xs _)) |
| 36 | + ) |
| 37 | + : _ |
| 38 | + ) |
| 39 | + _ |
| 40 | + ) -> mapMaybe toWeakness xs |
| 41 | + n -> error (show n) |
| 42 | + where |
| 43 | + toWeakness (XML.Elem (XML.Element (XML.QName "Weakness" _ _) attrs _ _)) = Just (Weakness{wid, wname}) |
| 44 | + where |
| 45 | + wid = fromMaybe (error "invalid num") $ readMaybe =<< XML.lookupAttrBy ((==) "ID" . XML.qName) attrs |
| 46 | + wname = fromMaybe (error "missing name") $ XML.lookupAttrBy ((==) "Name" . XML.qName) attrs |
| 47 | + toWeakness e = Nothing |
27 | 48 |
|
28 |
| -renderSource :: [Record] -> [String] |
| 49 | +renderSource :: [Weakness] -> [String] |
29 | 50 | renderSource xs =
|
30 | 51 | [ "{-# LANGUAGE OverloadedStrings #-}"
|
31 |
| - , "module CWE.Data where" |
| 52 | + , "module Security.CWE.Data where" |
32 | 53 | , "import Data.Text"
|
33 | 54 | , "cweData :: [(Word, Text)]"
|
34 | 55 | , "cweData = ["
|
35 | 56 | ]
|
36 |
| - <> map renderEntry (zip [0 ..] (sortOn byNum xs)) |
| 57 | + <> map renderEntry (zip [0 ..] (sortOn wid xs)) |
37 | 58 | <> [" ]"]
|
38 | 59 | where
|
39 |
| - byNum (num : _) = fromMaybe (42 :: Int) (readMaybe num) |
40 |
| - renderEntry (pos, (num : desc : _)) = " " <> sep <> " (" <> num <> ", \"" <> name <> "\")" |
| 60 | + renderEntry (pos, weakness) = " " <> sep <> " (" <> show (wid weakness) <> ", \"" <> name <> "\")" |
41 | 61 | where
|
42 | 62 | sep = if pos == 0 then " " else ","
|
43 | 63 | -- Remove extra info in parenthesis
|
44 |
| - name = dropWhileEnd (== ' ') $ takeWhile (/= '(') desc |
| 64 | + name = dropWhileEnd (== ' ') $ takeWhile (/= '(') $ escape $ wname weakness |
| 65 | + escape ('\\':rest) = '\\' : '\\' : escape rest |
| 66 | + escape (x:rest) = x : escape rest |
| 67 | + escape [] = [] |
45 | 68 | renderEntry _ = ""
|
0 commit comments