Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions scripts/ci/strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1180,6 +1180,7 @@ is_scannable_changed_file() {
pull_request_scope_context_files() {
local needs_backend_python=0
local needs_frontend_email_api_context=0
local needs_frontend_search_api_context=0
local needs_deployment_context=0
local changed_file normalized_changed_file
for changed_file in "$@"; do
Expand All @@ -1195,6 +1196,13 @@ pull_request_scope_context_files() {
frontend/src/components/EmailDetail.tsx | frontend/src/components/EmailList.tsx | frontend/src/app/page.tsx | frontend/src/lib/api-client.ts | frontend/src/lib/email-threading.ts)
needs_frontend_email_api_context=1
;;
# Context Search crosses the React view, the same-origin BFF, signed-session
# auth, owner-scoped search/ontology routes, and sender relationship storage.
# Supply those bounded files so Strix verifies the actual trust boundary
# instead of treating client-side result identifiers as authorization.
frontend/src/components/SearchLayout.tsx | frontend/src/app/search/page.tsx)
needs_frontend_search_api_context=1
;;
# Deployment and CI changes often reference build files that are not all
# changed in the PR. Include the trusted copies so Strix does not downgrade
# a clean finding to provider/failure-signal output due to missing Dockerfiles
Expand Down Expand Up @@ -1263,6 +1271,24 @@ backend/services/threading_service.py
EOF
fi

if [ "$needs_frontend_search_api_context" -eq 1 ]; then
cat <<'EOF'
backend/api/auth.py
backend/api/ontology.py
backend/api/search.py
backend/db/models.py
backend/main.py
backend/services/ontology_service.py
frontend/package.json
frontend/src/app/api/[...path]/route.ts
frontend/src/app/auth/session/route.ts
frontend/src/app/search/page.tsx
frontend/src/components/SearchLayout.tsx
frontend/src/lib/api-client.ts
frontend/src/lib/session-cookie.ts
EOF
Comment thread
coderabbitai[bot] marked this conversation as resolved.
fi

if [ "$needs_deployment_context" -eq 1 ]; then
cat <<'EOF'
Dockerfile
Expand Down
163 changes: 163 additions & 0 deletions scripts/ci/test_strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6230,6 +6230,14 @@ run_filtered_gate_case_if_requested() {
"1" \
"Container build manifest changed; materialized full PR-head blob scope"
;;
pull-request-target-frontend-search-context-search-layout)
run_pull_request_target_frontend_search_context_scope_case \
"frontend/src/components/SearchLayout.tsx"
;;
pull-request-target-frontend-search-context-search-page)
run_pull_request_target_frontend_search_context_scope_case \
"frontend/src/app/search/page.tsx"
;;
repository-dispatch-pr-scope-uses-head-blob)
run_pull_request_target_head_scope_case \
"repository-dispatch-pr-scope-uses-head-blob" \
Expand Down Expand Up @@ -7216,6 +7224,155 @@ EOF
rm -rf "$tmp_dir"
}

run_pull_request_target_frontend_search_context_scope_case() {
local changed_file="${1:?changed file is required}"
local case_name="pull-request-target-frontend-search-context:$changed_file"
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 context_files=(
"backend/api/auth.py"
"backend/api/ontology.py"
"backend/api/search.py"
"backend/db/models.py"
"backend/main.py"
"backend/services/ontology_service.py"
"frontend/package.json"
"frontend/src/app/api/[...path]/route.ts"
"frontend/src/app/auth/session/route.ts"
"frontend/src/app/search/page.tsx"
"frontend/src/components/SearchLayout.tsx"
"frontend/src/lib/api-client.ts"
"frontend/src/lib/session-cookie.ts"
)
local context_files_text
context_files_text="$(printf '%s\n' "${context_files[@]}")"

local fake_strix="$bin_dir/strix"
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

target_path=""
while [ "$#" -gt 0 ]; do
if [ "$1" = "-t" ] && [ "$#" -ge 2 ]; then
target_path="$2"
break
fi
shift
done

changed_file="$target_path/${FAKE_STRIX_EXPECTED_CHANGED_FILE:?}"
if ! grep -Fq -- 'HEAD_FRONTEND_SEARCH_FLOW_SHOULD_BE_SCANNED' "$changed_file"; then
echo "Error: frontend search PR-head content was not scanned" >&2
cat -- "$changed_file" >&2
exit 93
fi

while IFS= read -r context_file; do
[ -n "$context_file" ] || continue
if [ "$context_file" = "${FAKE_STRIX_EXPECTED_CHANGED_FILE:?}" ]; then
continue
fi
context_path="$target_path/$context_file"
if [ ! -f "$context_path" ]; then
echo "Error: frontend search authorization context missing: $context_file" >&2
exit 94
fi
if ! grep -Fqx -- "BASE_SEARCH_CONTEXT:$context_file" "$context_path"; then
echo "Error: frontend search context did not use trusted base content: $context_file" >&2
cat -- "$context_path" >&2
exit 95
fi
if grep -Fq -- "HEAD_SEARCH_CONTEXT_SHOULD_NOT_BE_SCANNED:$context_file" "$context_path"; then
echo "Error: unchanged frontend search context leaked PR-head content: $context_file" >&2
cat -- "$context_path" >&2
exit 96
fi
done <<<"${FAKE_STRIX_EXPECTED_CONTEXT_FILES:?}"

if [ -e "$target_path/backend/api/unrelated_admin.py" ]; then
echo "Error: unrelated backend source leaked into bounded frontend search scope" >&2
exit 97
fi

echo "scan ok with frontend search trusted cross-layer authorization context"
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'
local context_file
for context_file in "${context_files[@]}"; do
mkdir -p "$(dirname -- "$context_file")"
printf 'BASE_SEARCH_CONTEXT:%s\n' "$context_file" >"$context_file"
done
mkdir -p "$(dirname -- "$changed_file")" backend/api
printf '%s\n' 'BASE_FRONTEND_SEARCH_FLOW_SHOULD_NOT_BE_SCANNED' >"$changed_file"
printf '%s\n' 'UNRELATED_BACKEND_CONTEXT_SHOULD_NOT_BE_SCANNED' >backend/api/unrelated_admin.py
git add .
git commit -qm 'base commit'
)
local base_sha
base_sha="$(git -C "$repo_root_dir" rev-parse HEAD)"
(
cd "$repo_root_dir"
local context_file
for context_file in "${context_files[@]}"; do
printf 'HEAD_SEARCH_CONTEXT_SHOULD_NOT_BE_SCANNED:%s\n' "$context_file" >"$context_file"
done
printf '%s\n' 'HEAD_FRONTEND_SEARCH_FLOW_SHOULD_BE_SCANNED' >"$changed_file"
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"

set +e
(
cd "$repo_root_dir"
env -u GITHUB_EVENT_PATH \
PATH="$bin_dir:$PATH" \
STRIX_EXECUTABLE_PATH="$bin_dir/strix" \
STRIX_INPUT_FILE_ROOT="$tmp_dir" \
GITHUB_EVENT_NAME="pull_request_target" \
PR_BASE_SHA="$base_sha" \
PR_HEAD_SHA="$head_sha" \
STRIX_TEST_CHANGED_FILES_OVERRIDE="$changed_file" \
STRIX_DISABLE_PR_SCOPING="0" \
FAKE_STRIX_EXPECTED_CHANGED_FILE="$changed_file" \
FAKE_STRIX_EXPECTED_CONTEXT_FILES="$context_files_text" \
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 "0" "$rc" "case=$case_name exit code"
assert_file_contains "$output_log" "scan ok with frontend search trusted cross-layer authorization context" "case=$case_name output"

rm -rf "$tmp_dir"
}

run_pull_request_target_shallow_head_merge_base_fallback_case() {
local tmp_dir
tmp_dir="$(mktemp -d)"
Expand Down Expand Up @@ -9032,6 +9189,12 @@ run_pull_request_target_frontend_email_context_scope_case \
run_pull_request_target_frontend_email_context_scope_case \
"frontend/src/lib/email-threading.ts"

run_pull_request_target_frontend_search_context_scope_case \
"frontend/src/components/SearchLayout.tsx"

run_pull_request_target_frontend_search_context_scope_case \
"frontend/src/app/search/page.tsx"

run_pull_request_target_aborts_on_pr_head_blob_failure_case \
"pull-request-target-added-file-pr-head-blob-read-failure" \
"src/new_module.py" \
Expand Down
Loading