From 925f0e26d1107c3dcc0931de35725facf216959d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 19 May 2026 10:43:49 +0900 Subject: [PATCH 1/3] fix: map Strix XML file locations --- scripts/ci/strix_quick_gate.sh | 1 + scripts/ci/test_strix_quick_gate.sh | 36 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/scripts/ci/strix_quick_gate.sh b/scripts/ci/strix_quick_gate.sh index 50d2240fc..d7846b7cb 100644 --- a/scripts/ci/strix_quick_gate.sh +++ b/scripts/ci/strix_quick_gate.sh @@ -1295,6 +1295,7 @@ import sys text = Path(sys.argv[1]).read_text(encoding='utf-8', errors='replace') patterns = [ re.compile(r'(?P/workspace/[^\s`]+|[A-Za-z0-9_./\[\]-]+\.[A-Za-z0-9_]+):\d+'), + re.compile(r'\s*(?P/workspace/[^\s<`│]+|[A-Za-z0-9_./\[\]-]+\.[A-Za-z0-9_]+)\s*'), re.compile(r'^[^\S\r\n│]*[│]?[ \t]*(?:\*\*)?Target:(?:\*\*)?[ \t]*(?:File:[ \t]*)?(?P/workspace/[^\s`│]+|[A-Za-z0-9_./\[\]-]+\.[A-Za-z0-9_]+)', re.MULTILINE), re.compile(r'^[^\S\r\n│]*[│]?[ \t]*(?:\*\*)?Endpoint:(?:\*\*)?[ \t]*(?P/workspace/[^\s`│]+|[A-Za-z0-9_./\[\]-]+\.[A-Za-z0-9_]+)', re.MULTILINE), re.compile(r'(?i)(?:in\s+)?file\s+`(?P(?:\.\.?/)?[A-Za-z0-9_./\[\]-]+\.[A-Za-z0-9_]+)`'), diff --git a/scripts/ci/test_strix_quick_gate.sh b/scripts/ci/test_strix_quick_gate.sh index b77c44700..93a6c0646 100644 --- a/scripts/ci/test_strix_quick_gate.sh +++ b/scripts/ci/test_strix_quick_gate.sh @@ -1144,6 +1144,21 @@ EOS echo "Penetration test failed: changed bracketed Next.js route finding" exit 1 ;; + pr-critical-changed-xml-file-location) + mkdir -p "$STRIX_REPORTS_DIR/fake-pr-changed-xml/vulnerabilities" + cat >"$STRIX_REPORTS_DIR/fake-pr-changed-xml/vulnerabilities/vuln-0001.md" <<'EOS' +Severity: HIGH + + + sync-module-system/smart-crawling-biz/src/main/java/org/empasy/sync/modules/system/controller/SysPositionController.java + 120 + 124 + + +EOS + echo "Penetration test failed: changed XML file location finding" + exit 1 + ;; pr-critical-unmapped) mkdir -p "$STRIX_REPORTS_DIR/fake-pr-unmapped/vulnerabilities" cat >"$STRIX_REPORTS_DIR/fake-pr-unmapped/vulnerabilities/vuln-0001.md" <<'EOS' @@ -4301,6 +4316,27 @@ run_gate_case "pr-critical-changed-bracketed-next-route" \ "pull_request" \ "frontend/src/app/labels/[slug]/page.tsx" +run_gate_case "pr-critical-changed-xml-file-location" \ + "openai/gpt-4o-mini" \ + "" \ + "1" \ + "Strix finding intersects files changed in this pull request." \ + "1" \ + "openai/gpt-4o-mini" \ + "https://example.invalid" \ + "vertex_ai" \ + "__DEFAULT__" \ + "" \ + "0" \ + "MEDIUM" \ + "0" \ + "" \ + "" \ + "1200" \ + "0" \ + "pull_request" \ + "sync-module-system/smart-crawling-biz/src/main/java/org/empasy/sync/modules/system/controller/SysPositionController.java" + run_gate_case "pr-critical-changed-absolute-target" \ "openai/gpt-4o-mini" \ "" \ From fa66176de7198c5cd8d2da5b1c52902303451380 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 19 May 2026 11:15:46 +0900 Subject: [PATCH 2/3] fix: validate Strix PR commit metadata --- scripts/ci/strix_quick_gate.sh | 40 ++++++++++-- scripts/ci/test_strix_quick_gate.sh | 99 +++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 6 deletions(-) diff --git a/scripts/ci/strix_quick_gate.sh b/scripts/ci/strix_quick_gate.sh index d7846b7cb..472cc3d88 100644 --- a/scripts/ci/strix_quick_gate.sh +++ b/scripts/ci/strix_quick_gate.sh @@ -207,6 +207,17 @@ pull_request_head_blob_required() { [ "${GITHUB_EVENT_NAME:-}" = "pull_request_target" ] } +is_valid_git_commit_sha() { + local sha="$1" + [[ "$sha" =~ ^[0-9a-fA-F]{40}$ || "$sha" =~ ^[0-9a-fA-F]{64}$ ]] +} + +invalid_pull_request_sha() { + local label="$1" + echo "ERROR: pull request $label commit SHA is invalid; failing closed." >&2 + return 2 +} + pr_head_regular_file_mode() { local relative_path="$1" local head_sha tree_output line_count metadata tree_path mode object_type _object_hash @@ -214,7 +225,10 @@ pr_head_regular_file_mode() { if [ -z "$head_sha" ]; then return 2 fi - if ! git cat-file -e "$head_sha^{commit}" 2>/dev/null; then + if ! is_valid_git_commit_sha "$head_sha"; then + return 2 + fi + if ! git rev-parse --verify --quiet "$head_sha^{commit}" >/dev/null; then return 2 fi if ! tree_output="$(git ls-tree "$head_sha" -- "$relative_path")"; then @@ -639,14 +653,28 @@ PY fi return 1 fi - if ! git cat-file -e "$base_sha^{commit}" 2>/dev/null; then + if ! is_valid_git_commit_sha "$base_sha"; then + if pull_request_head_blob_required; then + invalid_pull_request_sha "base" + return 2 + fi + return 1 + fi + if ! is_valid_git_commit_sha "$head_sha"; then + if pull_request_head_blob_required; then + invalid_pull_request_sha "head" + return 2 + fi + return 1 + fi + if ! git rev-parse --verify --quiet "$base_sha^{commit}" >/dev/null; then if pull_request_head_blob_required; then echo "ERROR: pull request base commit could not be read; failing closed: $base_sha" >&2 return 2 fi return 1 fi - if ! git cat-file -e "$head_sha^{commit}" 2>/dev/null; then + if ! git rev-parse --verify --quiet "$head_sha^{commit}" >/dev/null; then if pull_request_head_blob_required; then echo "ERROR: pull request head commit could not be read; failing closed: $head_sha" >&2 return 2 @@ -655,7 +683,7 @@ PY fi local changed_files_output - if ! changed_files_output="$(git diff --name-only "$base_sha...$head_sha")"; then + if ! changed_files_output="$(git diff --name-only "$base_sha...$head_sha" --)"; then if pull_request_head_blob_required; then echo "ERROR: pull request changed file list could not be read; failing closed." >&2 return 2 @@ -992,7 +1020,7 @@ PY local copy_rc=1 local head_sha_for_copy head_sha_for_copy="$(trim_whitespace "${PR_HEAD_SHA:-}")" - if pull_request_head_blob_required || { [ -n "$head_sha_for_copy" ] && git cat-file -e "$head_sha_for_copy^{commit}" 2>/dev/null; }; then + if pull_request_head_blob_required || { [ -n "$head_sha_for_copy" ] && is_valid_git_commit_sha "$head_sha_for_copy" && git rev-parse --verify --quiet "$head_sha_for_copy^{commit}" >/dev/null; }; then copy_rc=0 copy_pr_head_blob_to_file "$relative_path" "$dst_path" || copy_rc=$? fi @@ -1041,7 +1069,7 @@ PY local copy_rc=1 local head_sha_for_copy head_sha_for_copy="$(trim_whitespace "${PR_HEAD_SHA:-}")" - if pull_request_head_blob_required || { [ -n "$head_sha_for_copy" ] && git cat-file -e "$head_sha_for_copy^{commit}" 2>/dev/null; }; then + if pull_request_head_blob_required || { [ -n "$head_sha_for_copy" ] && is_valid_git_commit_sha "$head_sha_for_copy" && git rev-parse --verify --quiet "$head_sha_for_copy^{commit}" >/dev/null; }; then copy_rc=0 copy_pr_head_blob_to_file "$relative_path" "$dst_path" || copy_rc=$? fi diff --git a/scripts/ci/test_strix_quick_gate.sh b/scripts/ci/test_strix_quick_gate.sh index 93a6c0646..96dcb76de 100644 --- a/scripts/ci/test_strix_quick_gate.sh +++ b/scripts/ci/test_strix_quick_gate.sh @@ -2288,6 +2288,97 @@ EOF rm -rf "$tmp_dir" } +run_pull_request_target_rejects_invalid_sha_case() { + local case_name="$1" + local invalid_side="$2" + + local tmp_dir + tmp_dir="$(mktemp -d)" + local bin_dir="$tmp_dir/bin" + local repo_root_dir="$tmp_dir/repo" + mkdir -p "$bin_dir" "$repo_root_dir/scripts/ci" + cp "$GATE_SCRIPT" "$repo_root_dir/scripts/ci/strix_quick_gate.sh" + cp "$REPO_ROOT/scripts/ci/strix_model_utils.sh" "$repo_root_dir/scripts/ci/strix_model_utils.sh" + chmod +x "$repo_root_dir/scripts/ci/strix_quick_gate.sh" + + local fake_strix="$bin_dir/strix" + local call_log="$tmp_dir/calls.log" + local output_log="$tmp_dir/output.log" + local strix_llm_file="$tmp_dir/strix_llm.txt" + local llm_api_key_file="$tmp_dir/llm_api_key.txt" + + cat >"$fake_strix" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +printf 'called\n' >> "${FAKE_STRIX_CALL_LOG:?}" +echo "Error: Strix should not run after invalid pull request SHA metadata" >&2 +exit 67 +EOF + chmod +x "$fake_strix" + printf '%s' 'gemini/test-model' >"$strix_llm_file" + printf '%s' 'dummy' >"$llm_api_key_file" + + ( + cd "$repo_root_dir" + git init -q + git config user.name 'Strix Test' + git config user.email 'strix-test@example.invalid' + echo 'seed' >README.md + git add . + git commit -qm 'base commit' + ) + local base_sha + base_sha="$(git -C "$repo_root_dir" rev-parse HEAD)" + ( + cd "$repo_root_dir" + echo 'head' >>README.md + git add . + git commit -qm 'head commit' + ) + local head_sha + head_sha="$(git -C "$repo_root_dir" rev-parse HEAD)" + git -C "$repo_root_dir" checkout -q "$base_sha" + + local injection_marker="STRIX_SHA_INJECTION_MARKER" + local malicious_sha='0000000000000000000000000000000000000000$(echo STRIX_SHA_INJECTION_MARKER)' + local expected_message="pull request $invalid_side commit SHA is invalid; failing closed" + if [ "$invalid_side" = "base" ]; then + base_sha="$malicious_sha" + else + head_sha="$malicious_sha" + fi + + set +e + ( + cd "$repo_root_dir" + env -u GITHUB_EVENT_PATH -u STRIX_TEST_CHANGED_FILES_OVERRIDE \ + PATH="$bin_dir:$PATH" \ + GITHUB_EVENT_NAME="pull_request_target" \ + PR_BASE_SHA="$base_sha" \ + PR_HEAD_SHA="$head_sha" \ + FAKE_STRIX_CALL_LOG="$call_log" \ + STRIX_DISABLE_PR_SCOPING="0" \ + STRIX_LLM_FILE="$strix_llm_file" \ + LLM_API_KEY_FILE="$llm_api_key_file" \ + STRIX_TARGET_PATH="." \ + STRIX_REPORTS_DIR="$repo_root_dir/strix_runs" \ + bash "./scripts/ci/strix_quick_gate.sh" >"$output_log" 2>&1 + ) + local rc=$? + set -e + + assert_equals "2" "$rc" "case=$case_name invalid PR SHA exits closed" + assert_file_contains "$output_log" "$expected_message" "case=$case_name invalid PR SHA output" + assert_file_not_contains "$output_log" "$injection_marker" "case=$case_name invalid PR SHA must not echo untrusted value" + local call_count="0" + if [ -f "$call_log" ]; then + call_count="$(wc -l <"$call_log" | tr -d ' ')" + fi + assert_equals "0" "$call_count" "case=$case_name invalid PR SHA must not invoke Strix" + + rm -rf "$tmp_dir" +} + run_pull_request_target_irregular_head_entry_fails_closed_case() { local case_name="$1" local changed_file="$2" @@ -3006,6 +3097,14 @@ run_pull_request_target_aborts_on_pr_head_blob_failure_case \ "HEAD_CONTENT_SHOULD_NOT_BECOME_PARTIAL_SCAN_INPUT" \ "diff" +run_pull_request_target_rejects_invalid_sha_case \ + "pull-request-target-invalid-base-sha-fails-closed" \ + "base" + +run_pull_request_target_rejects_invalid_sha_case \ + "pull-request-target-invalid-head-sha-fails-closed" \ + "head" + run_pull_request_target_aborts_on_pr_head_blob_failure_case \ "pull-request-target-disabled-pr-scope-pr-head-blob-read-failure" \ "src/existing.py" \ From a2b3e401cca4f77f8bc437f73d7b8ea316ae9f11 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 19 May 2026 11:40:28 +0900 Subject: [PATCH 3/3] test: clarify Strix XML fixture --- scripts/ci/test_strix_quick_gate.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/ci/test_strix_quick_gate.sh b/scripts/ci/test_strix_quick_gate.sh index 96dcb76de..30494c63f 100644 --- a/scripts/ci/test_strix_quick_gate.sh +++ b/scripts/ci/test_strix_quick_gate.sh @@ -1150,7 +1150,7 @@ EOS Severity: HIGH - sync-module-system/smart-crawling-biz/src/main/java/org/empasy/sync/modules/system/controller/SysPositionController.java + sync-module-system/smart-crawling-biz/src/main/java/org/empasy/sync/modules/system/controller/SysPositionController.java 120 124 @@ -4427,7 +4427,7 @@ run_gate_case "pr-critical-changed-xml-file-location" \ "__DEFAULT__" \ "" \ "0" \ - "MEDIUM" \ + "HIGH" \ "0" \ "" \ "" \