@@ -370,155 +370,153 @@ Parsed `gl-sast-report.json` and merged overlapping issues.
370
370
371
371
**Requirement**: This job depends on the previous stage output of the `security_priority.md` file to use as input to generate the patch file for creating an MR
372
372
` ` ` yaml
373
- # --- Resolution prompt (produces unified git diffs only) ---
374
- CODEX_DIFF_PROMPT: |
375
- You are a secure code remediation assistant.
376
- You will receive:
377
- - The repository working tree (read-only)
378
- - One vulnerability (JSON from a GitLab SAST report)
379
- - Allowed files list
373
+ stages:
374
+ - remediation
380
375
376
+ default:
377
+ image: node:24
381
378
382
- GOAL:
383
- - Create the minimal, safe fix for the vulnerability.
384
- - Output a unified git diff that applies cleanly with ` git apply -p0` (or -p1 for a/ b/ paths).
385
- - Prefer surgical changes : input validation, safe APIs, parameterized queries, permission checks.
386
- - Do NOT refactor broadly or change unrelated code.
387
-
388
-
389
- RULES (must follow exactly) :
390
- - PRINT ONLY the diff between the markers below.
391
- - Use repo-relative paths; `diff --git a/path b/path` headers are accepted.
392
- - No binary file changes. No prose/explanations outside the markers.
393
-
394
-
395
- MARKERS :
396
- === BEGIN_UNIFIED_DIFF ===
397
- <unified diff here>
398
- === END_UNIFIED_DIFF ===
399
-
400
-
401
- If no safe fix is possible without deeper changes, output an empty diff between the markers.
402
-
379
+ variables:
380
+ # Inputs/outputs
381
+ SAST_REPORT_PATH: "gl-sast-report.json"
382
+ PATCH_DIR: "codex_patches"
383
+ CODEX_DIFF_RAW: "artifacts/codex-diff-raw.log"
384
+
385
+ # --- Resolution prompt (produces unified git diffs only) ---
386
+ CODEX_DIFF_PROMPT: |
387
+ You are a secure code remediation assistant.
388
+ You will receive:
389
+ - The repository working tree (read-only)
390
+ - One vulnerability (JSON from a GitLab SAST report)
391
+ - Allowed files list
392
+
393
+ GOAL:
394
+ - Create the minimal, safe fix for the vulnerability.
395
+ - Output a unified git diff that applies cleanly with ` git apply -p0` (or -p1 for a/ b/ paths).
396
+ - Prefer surgical changes : input validation, safe APIs, parameterized queries, permission checks.
397
+ - Do NOT refactor broadly or change unrelated code.
398
+
399
+ RULES (must follow exactly) :
400
+ - PRINT ONLY the diff between the markers below.
401
+ - Use repo-relative paths; `diff --git a/path b/path` headers are accepted.
402
+ - No binary file changes. No prose/explanations outside the markers.
403
+
404
+ MARKERS :
405
+ === BEGIN_UNIFIED_DIFF ===
406
+ <unified diff here>
407
+ === END_UNIFIED_DIFF ===
408
+
409
+ If no safe fix is possible without deeper changes, output an empty diff between the markers.
403
410
404
411
# ---------------------------
405
- # Stage: remediation → Job 2 (Resolution / git diffs)
412
+ # Stage: remediation → Generate unified diffs/patches
406
413
# ---------------------------
407
414
codex_resolution :
408
- stage : remediation
409
- needs :
410
- - job : codex_recommendations
411
- artifacts : true
412
- rules :
413
- - if : ' $OPENAI_API_KEY'
414
- when : on_success
415
- - when : never
416
- variables :
417
- SAST_REPORT_PATH : " gl-sast-report.json"
418
- PATCH_DIR : " codex_patches"
419
- CODEX_DIFF_RAW : " artifacts/codex-diff-raw.log"
420
- script :
421
- - set -euo pipefail
422
- - mkdir -p "$PATCH_DIR" artifacts
423
-
424
- - apt-get update && apt-get install -y --no-install-recommends bash git jq curl ca-certificates
425
- - npm -g i @openai/codex@latest
426
- - git --version && codex --version || true
427
-
415
+ stage : remediation
416
+ rules :
417
+ - if : ' $OPENAI_API_KEY'
418
+ when : on_success
419
+ - when : never
420
+ script :
421
+ - set -euo pipefail
422
+ - mkdir -p "$PATCH_DIR" artifacts
428
423
429
- # If SAST missing, no-op (job still visible/success)
430
- - |
431
- if [ ! -s "${SAST_REPORT_PATH}" ]; then
432
- echo "No SAST report found; resolution will no-op."
433
- printf "CODEX_CREATED_PATCHES=false\n" > codex.env
434
- exit 0
435
- fi
424
+ # Deps
425
+ - apt-get update && apt-get install -y --no-install-recommends bash git jq curl ca-certificates
426
+ - npm -g i @openai/codex@latest
427
+ - git --version && codex --version || true
436
428
437
- # Filter High/Critical
438
- - |
439
- jq -c '.vulnerabilities[]? | select((.severity|ascii_downcase)=="high" or (.severity|ascii_downcase)=="critical")' "$SAST_REPORT_PATH" \
440
- | nl -ba > /tmp/hicrit.txt || true
429
+ # Require SAST report; no-op if missing
430
+ - |
431
+ if [ ! -s "${SAST_REPORT_PATH}" ]; then
432
+ echo "No SAST report found; remediation will no-op."
433
+ printf "CODEX_CREATED_PATCHES=false\n" > codex.env
434
+ exit 0
435
+ fi
441
436
437
+ # Pull High/Critical items
438
+ - jq -c '.vulnerabilities[]? | select((.severity|ascii_downcase)=="high" or (.severity|ascii_downcase)=="critical")' "$SAST_REPORT_PATH" \
439
+ | nl -ba > /tmp/hicrit.txt || true
440
+ - |
441
+ if [ ! -s /tmp/hicrit.txt ]; then
442
+ echo "No High/Critical vulnerabilities found. Nothing to fix."
443
+ printf "CODEX_CREATED_PATCHES=false\n" > codex.env
444
+ exit 0
445
+ fi
442
446
443
- if [ ! -s /tmp/hicrit.txt ]; then
444
- echo "No High/Critical vulnerabilities found. Nothing to fix."
445
- printf "CODEX_CREATED_PATCHES=false\n" > codex.env
446
- exit 0
447
- fi
447
+ # Ground Codex to actual repo files
448
+ - FILE_LIST="$(git ls-files | sed 's/^/- /')"
448
449
449
- - FILE_LIST="$(git ls-files | sed 's/^/- /')"
450
- - git config user.name "CI Codex Bot"
451
- -
git config user.email "[email protected] "
450
+ # Identity for any local patch ops
451
+ - git config user.name "CI Codex Bot"
452
+ -
git config user.email "[email protected] "
452
453
453
- - created=0
454
+ - created=0
454
455
455
- # Loop per finding → compose prompt via a temp file (robust) → run Codex → extract diff
456
- - |
457
- while IFS=$'\t' read -r idx vuln_json; do
458
- echo "Processing vulnerability #$idx"
459
- echo "$vuln_json" > "/tmp/vuln-$idx.json"
460
-
461
- # --- Compose prompt into a temp file (no heredocs/quoting traps) ---
462
- PROMPT_FILE="$(mktemp)"
463
- {
464
- printf "%s\n\n" "$CODEX_DIFF_PROMPT"
465
- printf "VULNERABILITY_JSON:\n<<JSON\n"
466
- cat "/tmp/vuln-$idx.json"
467
- printf "\nJSON\n\n"
468
- printf "EXISTING_REPOSITORY_FILES (exact list):\n"
469
- printf "%s\n" "$FILE_LIST"
470
- } > "$PROMPT_FILE"
471
-
472
- PER_FINDING_PROMPT="$(tr -d '\r' < "$PROMPT_FILE")"
473
- rm -f "$PROMPT_FILE"
474
-
475
- : > "$CODEX_DIFF_RAW"
476
- set +o pipefail
477
- codex exec --full-auto "$PER_FINDING_PROMPT" | tee -a "$CODEX_DIFF_RAW" >/dev/null
478
- RC=${PIPESTATUS[0]}
479
- set -o pipefail
480
- echo "Codex (diff) exit code: ${RC}"
481
-
482
- OUT_PATCH="$PATCH_DIR/fix-$idx.patch"
483
- sed -E 's/\x1B\[[0-9;]*[A-Za-z]//g' "$CODEX_DIFF_RAW" \
484
- | tr -d '\r' \
485
- | awk '
486
- /^\s*=== BEGIN_UNIFIED_DIFF ===\s*$/ {grab=1; next}
487
- /^\s*=== END_UNIFIED_DIFF ===\s*$/ {grab=0}
488
- grab
489
- ' > "$OUT_PATCH"
490
-
491
- # must contain at least one diff hunk
492
- if ! [ -s "$OUT_PATCH" ] || ! grep -qE '^\s*diff --git ' "$OUT_PATCH"; then
493
- echo " No usable diff produced for #$idx; skipping."
494
- rm -f "$OUT_PATCH"
495
- continue
496
- fi
497
-
498
- # Validate apply; accept -p0 (repo-relative) or -p1 (a/ b/ prefixes)
499
- if git apply --check -p0 "$OUT_PATCH" || git apply --check -p1 "$OUT_PATCH"; then
500
- echo " Patch validated for #$idx → $OUT_PATCH"
501
- created=$((created+1))
502
- else
503
- echo " Patch failed to apply cleanly; removing."
504
- rm -f "$OUT_PATCH"
505
- fi
506
- done < /tmp/hicrit.txt
507
-
508
- echo "Total patches created: $created"
509
- if [ "$created" -gt 0 ]; then
510
- printf "CODEX_CREATED_PATCHES=true\nPATCH_DIR=%s\n" "$PATCH_DIR" > codex.env
511
- else
512
- printf "CODEX_CREATED_PATCHES=false\n" > codex.env
513
- fi
514
- artifacts :
515
- when : always
516
- paths :
517
- - codex_patches/
518
- - artifacts/codex-diff-raw.log
519
- reports :
520
- dotenv : codex.env
521
- expire_in : 14 days
456
+ # Loop: build prompt (robust temp-file), run Codex, extract diff, validate
457
+ - |
458
+ while IFS=$'\t' read -r idx vuln_json; do
459
+ echo "Processing vulnerability #$idx"
460
+ echo "$vuln_json" > "/tmp/vuln-$idx.json"
461
+
462
+ PROMPT_FILE="$(mktemp)"
463
+ {
464
+ printf "%s\n\n" "$CODEX_DIFF_PROMPT"
465
+ printf "VULNERABILITY_JSON:\n<<JSON\n"
466
+ cat "/tmp/vuln-$idx.json"
467
+ printf "\nJSON\n\n"
468
+ printf "EXISTING_REPOSITORY_FILES (exact list):\n"
469
+ printf "%s\n" "$FILE_LIST"
470
+ } > "$PROMPT_FILE"
471
+
472
+ PER_FINDING_PROMPT="$(tr -d '\r' < "$PROMPT_FILE")"
473
+ rm -f "$PROMPT_FILE"
474
+
475
+ : > "$CODEX_DIFF_RAW"
476
+ set +o pipefail
477
+ codex exec --full-auto "$PER_FINDING_PROMPT" | tee -a "$CODEX_DIFF_RAW" >/dev/null
478
+ RC=${PIPESTATUS[0]}
479
+ set -o pipefail
480
+ echo "Codex (diff) exit code: ${RC}"
481
+
482
+ OUT_PATCH="$PATCH_DIR/fix-$idx.patch"
483
+ sed -E 's/\x1B\[[0-9;]*[A-Za-z]//g' "$CODEX_DIFF_RAW" \
484
+ | tr -d '\r' \
485
+ | awk '
486
+ /^\s*=== BEGIN_UNIFIED_DIFF ===\s*$/ {grab=1; next}
487
+ /^\s*=== END_UNIFIED_DIFF ===\s*$/ {grab=0}
488
+ grab
489
+ ' > "$OUT_PATCH"
490
+
491
+ if ! [ -s "$OUT_PATCH" ] || ! grep -qE '^\s*diff --git ' "$OUT_PATCH"; then
492
+ echo " No usable diff produced for #$idx; skipping."
493
+ rm -f "$OUT_PATCH"
494
+ continue
495
+ fi
496
+
497
+ # Validate: accept -p0 (repo-relative) or -p1 (a/ b/ prefixes)
498
+ if git apply --check -p0 "$OUT_PATCH" || git apply --check -p1 "$OUT_PATCH"; then
499
+ echo " Patch validated → $OUT_PATCH"
500
+ created=$((created+1))
501
+ else
502
+ echo " Patch failed to apply cleanly; removing."
503
+ rm -f "$OUT_PATCH"
504
+ fi
505
+ done < /tmp/hicrit.txt
506
+
507
+ if [ "$created" -gt 0 ]; then
508
+ printf "CODEX_CREATED_PATCHES=true\nPATCH_DIR=%s\n" "$PATCH_DIR" > codex.env
509
+ else
510
+ printf "CODEX_CREATED_PATCHES=false\n" > codex.env
511
+ fi
512
+ artifacts :
513
+ when : always
514
+ paths :
515
+ - codex_patches/
516
+ - artifacts/codex-diff-raw.log
517
+ reports :
518
+ dotenv : codex.env
519
+ expire_in : 14 days
522
520
` ` `
523
521
524
522
Example generated patch:
0 commit comments