Skip to content

Commit 669c59d

Browse files
committed
Added hardening script
1 parent ded5713 commit 669c59d

File tree

4 files changed

+55
-23
lines changed

4 files changed

+55
-23
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Repository = "https://github.com/pixee/codemodder-python"
4545

4646
[project.scripts]
4747
codemodder = "codemodder.codemodder:main"
48+
codemodder_hardening = "codemodder.codemodder:harden"
4849
generate-docs = 'codemodder.scripts.generate_docs:main'
4950
get-hashes = 'codemodder.scripts.get_hashes:main'
5051

src/codemodder/codemodder.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ def log_report(context, output, elapsed_ms, files_to_analyze, token_usage):
7373
def apply_codemods(
7474
context: CodemodExecutionContext,
7575
codemods_to_run: Sequence[BaseCodemod],
76+
hardening: bool,
7677
) -> TokenUsage:
7778
log_section("scanning")
7879
token_usage = TokenUsage()
@@ -89,7 +90,7 @@ def apply_codemods(
8990
for codemod in codemods_to_run:
9091
# NOTE: this may be used as a progress indicator by upstream tools
9192
logger.info("running codemod %s", codemod.id)
92-
if codemod_token_usage := codemod.apply(context):
93+
if codemod_token_usage := codemod.apply(context, hardening):
9394
log_token_usage(f"Codemod {codemod.id}", codemod_token_usage)
9495
token_usage += codemod_token_usage
9596

@@ -135,6 +136,7 @@ def run(
135136
sast_only: bool = False,
136137
ai_client: bool = True,
137138
log_matched_files: bool = False,
139+
hardening: bool = False,
138140
) -> tuple[CodeTF | None, int, TokenUsage]:
139141
start = datetime.datetime.now()
140142

@@ -206,7 +208,7 @@ def run(
206208
context.find_and_fix_paths,
207209
)
208210

209-
token_usage = apply_codemods(context, codemods_to_run)
211+
token_usage = apply_codemods(context, codemods_to_run, hardening)
210212

211213
elapsed = datetime.datetime.now() - start
212214
elapsed_ms = int(elapsed.total_seconds() * 1000)
@@ -231,7 +233,7 @@ def run(
231233
return codetf, 0, token_usage
232234

233235

234-
def _run_cli(original_args) -> int:
236+
def _run_cli(original_args, hardening=False) -> int:
235237
codemod_registry = registry.load_registered_codemods()
236238
argv = parse_args(original_args, codemod_registry)
237239
if not os.path.exists(argv.directory):
@@ -270,7 +272,8 @@ def _run_cli(original_args) -> int:
270272

271273
_, status, _ = run(
272274
argv.directory,
273-
argv.dry_run,
275+
# Force dry-run if not hardening
276+
argv.dry_run if hardening else True,
274277
argv.output,
275278
argv.output_format,
276279
argv.verbose,
@@ -284,10 +287,26 @@ def _run_cli(original_args) -> int:
284287
codemod_registry=codemod_registry,
285288
sast_only=argv.sonar_issues_json or argv.sarif,
286289
log_matched_files=True,
290+
hardening=hardening,
287291
)
288292
return status
289293

290294

295+
"""
296+
Hardens a project. The application will write all the fixes into the files.
297+
"""
298+
299+
300+
def harden():
301+
sys_argv = sys.argv[1:]
302+
sys.exit(_run_cli(sys_argv, True))
303+
304+
305+
"""
306+
Remediates a project. The application will suggest fix for each separate issue found. No files will be written.
307+
"""
308+
309+
291310
def main():
292311
sys_argv = sys.argv[1:]
293312
sys.exit(_run_cli(sys_argv))

src/codemodder/codemods/base_codemod.py

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ def _apply(
189189
self,
190190
context: CodemodExecutionContext,
191191
rules: list[str],
192+
hardening: bool,
192193
) -> None | TokenUsage:
193194
if self.provider and (
194195
not (provider := context.providers.get_provider(self.provider))
@@ -226,21 +227,26 @@ def _apply(
226227
logger.debug("No files matched for %s", self.id)
227228
return None
228229

229-
# Do each result independently
230-
if results:
230+
# Do each result independently and outputs the diffs
231+
if not hardening:
231232
# gather positional arguments for the map
232-
resultset_arguments = []
233+
resultset_arguments: list[ResultSet | None] = []
233234
path_arguments = []
234-
for result in results.results_for_rules(rules):
235-
# this need to be the same type of ResultSet as results
236-
singleton = results.__class__()
237-
singleton.add_result(result)
238-
result_locations = self.get_files_to_analyze(context, singleton)
239-
# We do an execution for each location in the result
240-
# So we duplicate the resultset argument for each location
241-
for loc in result_locations:
242-
resultset_arguments.append(singleton)
243-
path_arguments.append(loc)
235+
if results:
236+
for result in results.results_for_rules(rules):
237+
# this need to be the same type of ResultSet as results
238+
singleton = results.__class__()
239+
singleton.add_result(result)
240+
result_locations = self.get_files_to_analyze(context, singleton)
241+
# We do an execution for each location in the result
242+
# So we duplicate the resultset argument for each location
243+
for loc in result_locations:
244+
resultset_arguments.append(singleton)
245+
path_arguments.append(loc)
246+
# An exception for find-and-fix codemods
247+
else:
248+
resultset_arguments = [None]
249+
path_arguments = files_to_analyze
244250

245251
contexts: list = []
246252
with ThreadPoolExecutor() as executor:
@@ -251,13 +257,13 @@ def _apply(
251257
path, context, resultset, rules
252258
),
253259
path_arguments,
254-
resultset_arguments,
260+
resultset_arguments or [None],
255261
)
256262
)
257263
executor.shutdown(wait=True)
258264

259265
context.process_results(self.id, contexts)
260-
# for find and fix codemods
266+
# Hardens all findings per file at once and writes the fixed code into the file
261267
else:
262268
process_file = functools.partial(
263269
self._process_file, context=context, results=results, rules=rules
@@ -276,7 +282,9 @@ def _apply(
276282
context.process_results(self.id, contexts)
277283
return None
278284

279-
def apply(self, context: CodemodExecutionContext) -> None | TokenUsage:
285+
def apply(
286+
self, context: CodemodExecutionContext, hardening: bool = False
287+
) -> None | TokenUsage:
280288
"""
281289
Apply the codemod with the given codemod execution context
282290
@@ -292,7 +300,7 @@ def apply(self, context: CodemodExecutionContext) -> None | TokenUsage:
292300
293301
:param context: The codemod execution context
294302
"""
295-
return self._apply(context, [self._internal_name])
303+
return self._apply(context, [self._internal_name], hardening)
296304

297305
def _process_file(
298306
self,
@@ -390,8 +398,10 @@ def __init__(
390398
if requested_rules:
391399
self.requested_rules.extend(requested_rules)
392400

393-
def apply(self, context: CodemodExecutionContext) -> None | TokenUsage:
394-
return self._apply(context, self.requested_rules)
401+
def apply(
402+
self, context: CodemodExecutionContext, hardening: bool = False
403+
) -> None | TokenUsage:
404+
return self._apply(context, self.requested_rules, hardening)
395405

396406
def get_files_to_analyze(
397407
self,

src/core_codemods/defectdojo/api.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,11 @@ def from_core_codemod(
7676
def apply(
7777
self,
7878
context: CodemodExecutionContext,
79+
hardening: bool = False,
7980
) -> None:
8081
self._apply(
8182
context,
8283
# We know this has a tool because we created it with `from_core_codemod`
8384
cast(ToolMetadata, self._metadata.tool).rule_ids,
85+
hardening,
8486
)

0 commit comments

Comments
 (0)