@@ -116,6 +116,157 @@ def iter_content(self, chunk_size=None):
116116 self .assertCountEqual (nodes [0 ].todict (), expected [0 ].todict ())
117117 self .assertCountEqual (nodes [1 ].todict (), expected [1 ].todict ())
118118
119+ @patch .object (requests , "get" )
120+ def test_register_CWE_inherits_mappings_transitively (self , mock_requests ) -> None :
121+ tmpdir = mkdtemp ()
122+ tmpFile = os .path .join (tmpdir , "cwe.xml" )
123+ tmpzip = os .path .join (tmpdir , "cwe.zip" )
124+ with open (tmpFile , "w" ) as cx :
125+ cx .write (self .CWE_transitive_xml )
126+ with zipfile .ZipFile (tmpzip , "w" , zipfile .ZIP_DEFLATED ) as zipf :
127+ zipf .write (tmpFile , arcname = "cwe.xml" )
128+
129+ class fakeRequest :
130+ def iter_content (self , chunk_size = None ):
131+ with open (tmpzip , "rb" ) as zipf :
132+ return [zipf .read ()]
133+
134+ mock_requests .return_value = fakeRequest ()
135+
136+ cre = defs .CRE (id = "089-089" , name = "CRE-Injection" )
137+ dbcre = self .collection .add_cre (cre = cre )
138+ dbcwe = self .collection .add_node (defs .Standard (name = "CWE" , sectionID = "89" ))
139+ self .collection .add_link (dbcre , dbcwe , defs .LinkTypes .LinkedTo )
140+
141+ entries = cwe .CWE ().parse (
142+ cache = self .collection ,
143+ ph = prompt_client .PromptHandler (database = self .collection ),
144+ )
145+ imported_cwes = {node .sectionID : node for node in entries .results ["CWE" ]}
146+
147+ self .assertEqual (imported_cwes ["2001" ].links [0 ].document .todict (), cre .todict ())
148+ self .assertEqual (imported_cwes ["2002" ].links [0 ].document .todict (), cre .todict ())
149+
150+ @patch .object (requests , "get" )
151+ def test_register_CWE_applies_fallback_family_mappings (self , mock_requests ) -> None :
152+ tmpdir = mkdtemp ()
153+ tmpFile = os .path .join (tmpdir , "cwe.xml" )
154+ tmpzip = os .path .join (tmpdir , "cwe.zip" )
155+ with open (tmpFile , "w" ) as cx :
156+ cx .write (self .CWE_fallback_xml )
157+ with zipfile .ZipFile (tmpzip , "w" , zipfile .ZIP_DEFLATED ) as zipf :
158+ zipf .write (tmpFile , arcname = "cwe.xml" )
159+
160+ class fakeRequest :
161+ def iter_content (self , chunk_size = None ):
162+ with open (tmpzip , "rb" ) as zipf :
163+ return [zipf .read ()]
164+
165+ mock_requests .return_value = fakeRequest ()
166+
167+ injection_cre = defs .CRE (id = "760-764" , name = "Injection protection" )
168+ xss_cre = defs .CRE (id = "760-765" , name = "XSS protection" )
169+ xxe_cre = defs .CRE (id = "764-507" , name = "Restrict XML parsing (against XXE)" )
170+ auth_cre = defs .CRE (
171+ id = "117-371" , name = "Use a centralized access control mechanism"
172+ )
173+ authn_cre = defs .CRE (
174+ id = "113-133" , name = "Use centralized authentication mechanism"
175+ )
176+ csrf_cre = defs .CRE (id = "028-727" , name = "CSRF protection" )
177+ ssrf_cre = defs .CRE (id = "028-728" , name = "SSRF protection" )
178+ hardcoded_secret_cre = defs .CRE (
179+ id = "774-888" , name = "Do not store secrets in the code"
180+ )
181+ password_storage_cre = defs .CRE (
182+ id = "622-203" , name = "Store passwords salted and hashed"
183+ )
184+ credential_storage_cre = defs .CRE (
185+ id = "881-321" , name = "Store credentials securely"
186+ )
187+ session_management_cre = defs .CRE (id = "177-260" , name = "Session management" )
188+ secure_cookie_cre = defs .CRE (
189+ id = "688-081" , name = 'Set "secure" attribute for cookie-based session tokens'
190+ )
191+ deserialization_cre = defs .CRE (id = "836-068" , name = "Deserialization Prevention" )
192+ self .collection .add_cre (cre = injection_cre )
193+ self .collection .add_cre (cre = xss_cre )
194+ self .collection .add_cre (cre = xxe_cre )
195+ self .collection .add_cre (cre = auth_cre )
196+ self .collection .add_cre (cre = authn_cre )
197+ self .collection .add_cre (cre = csrf_cre )
198+ self .collection .add_cre (cre = ssrf_cre )
199+ self .collection .add_cre (cre = hardcoded_secret_cre )
200+ self .collection .add_cre (cre = password_storage_cre )
201+ self .collection .add_cre (cre = credential_storage_cre )
202+ self .collection .add_cre (cre = session_management_cre )
203+ self .collection .add_cre (cre = secure_cookie_cre )
204+ self .collection .add_cre (cre = deserialization_cre )
205+
206+ entries = cwe .CWE ().parse (
207+ cache = self .collection ,
208+ ph = prompt_client .PromptHandler (database = self .collection ),
209+ )
210+ imported_cwes = {node .sectionID : node for node in entries .results ["CWE" ]}
211+
212+ self .assertEqual (
213+ imported_cwes ["89" ].links [0 ].document .todict (), injection_cre .todict ()
214+ )
215+ self .assertEqual (
216+ imported_cwes ["79" ].links [0 ].document .todict (), xss_cre .todict ()
217+ )
218+ self .assertEqual (
219+ imported_cwes ["611" ].links [0 ].document .todict (), xxe_cre .todict ()
220+ )
221+ self .assertEqual (
222+ imported_cwes ["612" ].links [0 ].document .todict (), auth_cre .todict ()
223+ )
224+ self .assertEqual (
225+ imported_cwes ["287" ].links [0 ].document .todict (), authn_cre .todict ()
226+ )
227+ self .assertEqual (
228+ imported_cwes ["352" ].links [0 ].document .todict (), csrf_cre .todict ()
229+ )
230+ self .assertEqual (
231+ imported_cwes ["918" ].links [0 ].document .todict (), ssrf_cre .todict ()
232+ )
233+ self .assertEqual (
234+ imported_cwes ["798" ].links [0 ].document .todict (),
235+ hardcoded_secret_cre .todict (),
236+ )
237+ self .assertEqual (
238+ imported_cwes ["321" ].links [0 ].document .todict (),
239+ hardcoded_secret_cre .todict (),
240+ )
241+ self .assertEqual (
242+ imported_cwes ["256" ].links [0 ].document .todict (),
243+ password_storage_cre .todict (),
244+ )
245+ self .assertEqual (
246+ imported_cwes ["257" ].links [0 ].document .todict (),
247+ password_storage_cre .todict (),
248+ )
249+ self .assertEqual (
250+ imported_cwes ["258" ].links [0 ].document .todict (),
251+ credential_storage_cre .todict (),
252+ )
253+ self .assertEqual (
254+ imported_cwes ["260" ].links [0 ].document .todict (),
255+ credential_storage_cre .todict (),
256+ )
257+ self .assertEqual (
258+ imported_cwes ["384" ].links [0 ].document .todict (),
259+ session_management_cre .todict (),
260+ )
261+ self .assertEqual (
262+ imported_cwes ["614" ].links [0 ].document .todict (),
263+ secure_cookie_cre .todict (),
264+ )
265+ self .assertEqual (
266+ imported_cwes ["502" ].links [0 ].document .todict (),
267+ deserialization_cre .todict (),
268+ )
269+
119270 CWE_xml = """<?xml version="1.0" encoding="UTF-8"?>
120271<Weakness_Catalog Name="CWE" Version="4.10" Date="2023-01-31" xmlns="http://cwe.mitre.org/cwe-6"
121272 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -514,3 +665,78 @@ def iter_content(self, chunk_size=None):
514665 </Weakness>
515666 </Weaknesses>
516667</Weakness_Catalog>"""
668+
669+ CWE_transitive_xml = """<?xml version="1.0" encoding="UTF-8"?>
670+ <Weakness_Catalog Name="CWE" Version="4.10" Date="2023-01-31" xmlns="http://cwe.mitre.org/cwe-6">
671+ <Weaknesses>
672+ <Weakness ID="2001" Name="Injection Child" Abstraction="Variant" Structure="Simple" Status="Draft">
673+ <Related_Weaknesses>
674+ <Related_Weakness Nature="ChildOf" CWE_ID="89" View_ID="1000" Ordinal="Primary" />
675+ </Related_Weaknesses>
676+ </Weakness>
677+ <Weakness ID="2002" Name="Injection Grandchild" Abstraction="Variant" Structure="Simple" Status="Draft">
678+ <Related_Weaknesses>
679+ <Related_Weakness Nature="ChildOf" CWE_ID="2001" View_ID="1000" Ordinal="Primary" />
680+ </Related_Weaknesses>
681+ </Weakness>
682+ <Weakness ID="2003" Name="Standalone" Abstraction="Variant" Structure="Simple" Status="Draft">
683+ <Description>Padding entry so xmltodict returns a list of Weakness elements.</Description>
684+ </Weakness>
685+ </Weaknesses>
686+ </Weakness_Catalog>
687+ """
688+
689+ CWE_fallback_xml = """<?xml version="1.0" encoding="UTF-8"?>
690+ <Weakness_Catalog Name="CWE" Version="4.10" Date="2023-01-31" xmlns="http://cwe.mitre.org/cwe-6">
691+ <Weaknesses>
692+ <Weakness ID="79" Name="Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')" Abstraction="Base" Structure="Simple" Status="Draft">
693+ <Description>XSS entry.</Description>
694+ </Weakness>
695+ <Weakness ID="89" Name="Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')" Abstraction="Base" Structure="Simple" Status="Draft">
696+ <Description>SQL injection entry.</Description>
697+ </Weakness>
698+ <Weakness ID="611" Name="Improper Restriction of XML External Entity Reference" Abstraction="Base" Structure="Simple" Status="Draft">
699+ <Description>XXE entry.</Description>
700+ </Weakness>
701+ <Weakness ID="612" Name="Improper Authorization of Index Containing Sensitive Information" Abstraction="Base" Structure="Simple" Status="Draft">
702+ <Description>Authorization entry.</Description>
703+ </Weakness>
704+ <Weakness ID="287" Name="Improper Authentication" Abstraction="Base" Structure="Simple" Status="Draft">
705+ <Description>Authentication entry.</Description>
706+ </Weakness>
707+ <Weakness ID="352" Name="Cross-Site Request Forgery (CSRF)" Abstraction="Base" Structure="Simple" Status="Draft">
708+ <Description>CSRF entry.</Description>
709+ </Weakness>
710+ <Weakness ID="798" Name="Use of Hard-coded Credentials" Abstraction="Base" Structure="Simple" Status="Draft">
711+ <Description>Hard-coded credentials entry.</Description>
712+ </Weakness>
713+ <Weakness ID="321" Name="Use of Hard-coded Cryptographic Key" Abstraction="Base" Structure="Simple" Status="Draft">
714+ <Description>Hard-coded key entry.</Description>
715+ </Weakness>
716+ <Weakness ID="256" Name="Plaintext Storage of a Password" Abstraction="Base" Structure="Simple" Status="Draft">
717+ <Description>Password storage entry.</Description>
718+ </Weakness>
719+ <Weakness ID="257" Name="Storing Passwords in a Recoverable Format" Abstraction="Base" Structure="Simple" Status="Draft">
720+ <Description>Recoverable password entry.</Description>
721+ </Weakness>
722+ <Weakness ID="258" Name="Empty Password in Configuration File" Abstraction="Base" Structure="Simple" Status="Draft">
723+ <Description>Password in config entry.</Description>
724+ </Weakness>
725+ <Weakness ID="260" Name="Password in Configuration File" Abstraction="Base" Structure="Simple" Status="Draft">
726+ <Description>Password in config entry.</Description>
727+ </Weakness>
728+ <Weakness ID="384" Name="Session Fixation" Abstraction="Base" Structure="Simple" Status="Draft">
729+ <Description>Session fixation entry.</Description>
730+ </Weakness>
731+ <Weakness ID="614" Name="Sensitive Cookie in HTTPS Session Without 'Secure' Attribute" Abstraction="Base" Structure="Simple" Status="Draft">
732+ <Description>Cookie secure attribute entry.</Description>
733+ </Weakness>
734+ <Weakness ID="502" Name="Deserialization of Untrusted Data" Abstraction="Base" Structure="Simple" Status="Draft">
735+ <Description>Deserialization entry.</Description>
736+ </Weakness>
737+ <Weakness ID="918" Name="Server-Side Request Forgery (SSRF)" Abstraction="Base" Structure="Simple" Status="Draft">
738+ <Description>SSRF entry.</Description>
739+ </Weakness>
740+ </Weaknesses>
741+ </Weakness_Catalog>
742+ """
0 commit comments