Skip to content
Merged
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
68 changes: 68 additions & 0 deletions requirements-opencode-review-ci-hashes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,70 @@ coverage==7.14.3 \
# via
# -r requirements-opencode-review-ci.txt
# pytest-cov
hypothesis==6.163.0 \
--hash=sha256:002a9709345892279fb0e81b5a05b72d08cfe81f937339827be0d588607ca9b0 \
--hash=sha256:00d3091b28de83c5116e0ccd9a4bcb28ef61d2aace5df91093bb22434fd2350c \
--hash=sha256:0a0c396244c13805edcb73ff467c4c8178ccefc41c4ef5ed00a68e612fd773e9 \
--hash=sha256:0a933aca9ebf9daf951d07cf01200c94c321b6ee0b42cc7b67675c9686d914c2 \
--hash=sha256:0cba5202f74e7e4cdb676d86f26e8cc1b4fdc88f7f58ba73c8ac45b6b22f3070 \
--hash=sha256:213527755f0fc2b1f3721e73fd60023e2752a48f914e3e2df8d35111956ae5c8 \
--hash=sha256:21e72e8d5818e5ef8cd6a2191c386e3fd1a6d9e3739cf97289b4d9b5dbc8e38d \
--hash=sha256:2849c23b2e0fe2eef4c1ec336b01eac7ad7397c49fca43c264f59ec1e6046eac \
--hash=sha256:28a6cc1c25a6cc9b6ec079eaabd32ac769994831ecddd57123ce43c9056dcf34 \
--hash=sha256:31dc46c48aa53c3ec92d03120978ca7f19b9cf96d195ed3fc93503f1433c94a6 \
--hash=sha256:320b076bf6436f971f1c73ee651e60001226d1b4e341f2c4a1ca87248261ca03 \
--hash=sha256:331906cb029b6b360b8ebac3ec00c3cfa720037fe2efb294a503a1979c9a9a8f \
--hash=sha256:34fc895691a2420595506eb17f3a104f2fa9039f013c0770a6cc2743ccaf6fed \
--hash=sha256:3b6cee2afe6c67b31a4a64b63a876e0b020befdc61daabea80f7a0e14f19203a \
--hash=sha256:3f3cceb4720a39127622fbf3bcebe1775b894372c53b5edddfdef10bbdeef9ec \
--hash=sha256:40dfab6fe6a02a80abef81aebf88e53cd529e3f2f6ba3486b674a67b1f4a3512 \
--hash=sha256:4159a1c2560e10de51b1c14956e277eb1b37526c9abef9e87c1e531760486448 \
--hash=sha256:487ab8ec2f01a225d6a1e2ceadc5290cde2c691952bd2e7f76199cf82e06fb25 \
--hash=sha256:4ab0dadc09c537d4ac57e564039dfe7daf09c98375306d54bfc0fd6c218efcca \
--hash=sha256:50073f8e63c1e7d3403899755657a990d8bba7b5b5bff66b1c56796d4969bb28 \
--hash=sha256:520480d4bd3a17557616c25923640953e360332c89d012fffcebd69857e674a9 \
--hash=sha256:52f16840add2eb02c2416f3b83cec4f527b6c19699f2d31eff4859233c715526 \
--hash=sha256:56ed585baab75cb98462c57ca88bbdc6a9d935a14118dd572fb476c3ecec2a06 \
--hash=sha256:58be45d1737bf8c2e10cf29505c0f10f8a23d61bc82e4339182a6c8251cbc2d9 \
--hash=sha256:59f5fdb8addb44c17520a60d50542d9db6ceba577bbf54efefa9c10ee20be140 \
--hash=sha256:5a3ac6c62d49f7fe518dfe7fa924fa03aac839993702207802b0e45f9e1b0dab \
--hash=sha256:67d1593941ede41052b4a35ec25b50d0e280358c7674ef7812d520010e7e8bdf \
--hash=sha256:6ae63dec6d1d467b7f4737455f81a7a82f14a41c14510937fcfbc726a085b5f8 \
--hash=sha256:7a3db868a943c814cc557104712d43bf609adfe5ea9f708f38377d366b4855f8 \
--hash=sha256:7ca7b20bf38d51e15f7808b0239791c4792b1709ce0c63093acaff56a09c31e6 \
--hash=sha256:7cb3d927360fe73f9a06d646e6082237142ee39c24679c7133d22bf06dd03b45 \
--hash=sha256:7ef8954e37c80e0c46e6161eef1c72c71059b95250e620a77bd646f6c7a52a2d \
--hash=sha256:8aac96db8a6c7ee43aba2ee0d3c43893da1fb7c38ed54790c1be2b6d8fd87b96 \
--hash=sha256:8c5d1e6bad47edf6fb1d7406cf6d67314ac08325c63a49550d782a4596ea302b \
--hash=sha256:9105c66ea8dbc108adc42058bb7b65bd953f53ee178bf63bf9ebb0cded6c8c96 \
--hash=sha256:9be37b7ddf0af9e3f9112cd133afc34e78a56da1f96db5f2b4fc289fe1c4d1c3 \
--hash=sha256:9c084749c115ea7918cf7efa144682783da17eec70d1276689182b871126e715 \
--hash=sha256:9d23f0f3a14bb6e6f99c793d340196dba4af95ba25bfcab624d1794f540f5e27 \
--hash=sha256:a16ebce774755a7a652bd44c62101dc914372ed1a98935969624848c9627b4a4 \
--hash=sha256:a2a20e9835d3c4b293a709ee6ef769bcb18c6ed4ef337a9e251c1a9496d5e8be \
--hash=sha256:a57352efa938889ea9992667a5014c0fc870d03945de71918574d1cf28276378 \
--hash=sha256:ab34c61d9249f1a8129cb4276062c04e3e47b5be8de6446e7c7fe11362d6fe43 \
--hash=sha256:b123b4995a7612f1130e2b2362c9a5d0568df887bf7e7bdb45c23af8cd5423c9 \
--hash=sha256:b268211e625cd550e361fc387bf1db5deb1e9cae0ce4041116f0a0aafeef7c06 \
--hash=sha256:b2ddcdaf6691101e06dc4a5add7b8c8fdf1e68daba599255a281f3f3550d3331 \
--hash=sha256:b4ad2134405d5345434c22dea96bbc12c85abcfc3c253a8063dbc9ff01164555 \
--hash=sha256:b839dfd1342bb50570cb0c66b80322307cdb468abf14faf5df4dab022bc1b9ce \
--hash=sha256:b8f22fb8218ba6a452bf9000fc656e1ed57625d17cc8a3871a0fcea3b1b69ebf \
--hash=sha256:bd312b15044b1c1a0920a5827a830559b2d1fa380851cedf509f8b835309c5b9 \
--hash=sha256:c0ec3b709508ccd835d8ded1db025b7800618f2289a22a6bfd4927da5f4eb33c \
--hash=sha256:c4f5be1482189c7b0a1dcac269fffe97a7d18cc04ac9a9a4d6613212dd87f38b \
--hash=sha256:ca1b48bde68c528a79dec2a2859e05035802e5b1c9c3579f388c9de6ed6d0148 \
--hash=sha256:d0838a28e9943d5b834ebae59b02adda76e2cd1e65caa808104c72102052057d \
--hash=sha256:e165f6cc2075059b7c95dac1612bfb25494f72d90f56880e84c288b089f8a896 \
--hash=sha256:e568a3d766b7ba8df00e0c33efc4c6530cde14fbc72daabe4824eed211ed7596 \
--hash=sha256:ee47c2cb1be03a052ebd3549dad07f636a98b3ccfd7acbe5e17b3b7da0ab9e37 \
--hash=sha256:f1fe222f50a1898e87a1e7323ab35f9e956278efabe4dd55a1342808206d05ad \
--hash=sha256:f28ad27193c1fbcfb52ef2ee63d2b721563525089e80962b4268b306dac45507 \
--hash=sha256:f2f1b67a48da86d3e41c9445367b49a49f7efdb60fc8b5e3593f05e6afb2efbe \
--hash=sha256:f7f706df6839dcc53f20833f2933cbcd126fd2fdee7c312e053de49df4b64e44 \
--hash=sha256:fae7305ae20fddeea09df317b920c45d3e20bfedbdb041f4db6ca5267c458189 \
--hash=sha256:ffdda3006a383a48f71a23b4f2b3fae3fe1b09af67925d885985f7ec34d66bcb
# via -r requirements-opencode-review-ci.txt
iniconfig==2.3.0 \
--hash=sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730 \
--hash=sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12
Expand Down Expand Up @@ -143,6 +207,10 @@ pytest-cov==7.1.0 \
--hash=sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2 \
--hash=sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678
# via -r requirements-opencode-review-ci.txt
sortedcontainers==2.4.0 \
--hash=sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88 \
--hash=sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0
# via hypothesis
tabulate==0.10.0 \
--hash=sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d \
--hash=sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3
Expand Down
4 changes: 4 additions & 0 deletions requirements-opencode-review-ci.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
coverage==7.14.3
# hypothesis (MPL-2.0, permissive test tool) so the coverage-evidence sandbox can
# run repos' always-on property tests (tests/fuzz/*) instead of ImportError-ing on
# collection. Matches the >=6.100 floor used by consumer repos (e.g. contextual-orchestrator).
hypothesis>=6.100
interrogate==1.7.0
pytest==9.1.1
pytest-cov==7.1.0
Expand Down
9 changes: 9 additions & 0 deletions scripts/ci/strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1497,6 +1497,15 @@ build_pull_request_head_tree_scope_dir() {
[ -n "$metadata" ] || continue
# shellcheck disable=SC2086 # metadata is exactly git ls-tree's mode/type/object tuple.
read -r mode object_type object_hash <<<"$metadata"
# Git submodule pointers (gitlinks) list as mode 160000 / type commit in
# the recursive tree. They carry no scannable blob content in this
# repository (the submodule's files live in a separate repository), so
# skip them here exactly as the changed-file scope path does, instead of
# failing closed on a legitimately non-blob tree entry.
if [ "$mode" = "160000" ] || [ "$object_type" = "commit" ]; then
echo "INFO: pull request head tree entry is a git submodule pointer; excluding content from PR-scoped Strix input: $relative_path" >&2
continue
fi
if [ "$object_type" != "blob" ]; then
echo "ERROR: pull request head tree entry is not a blob; failing closed: $relative_path" >&2
return 2
Expand Down
120 changes: 120 additions & 0 deletions scripts/ci/test_strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7580,6 +7580,124 @@ EOF
rm -rf "$tmp_dir"
}

run_full_head_scope_skips_gitlink_case() {
# Regression for the full PR-head blob scope path
# (build_pull_request_head_tree_scope_dir): when a PR triggers full-head
# context (e.g. a Dockerfile change) in a repository that contains a git
# submodule, the gitlink tree entry (mode 160000 / type commit) must be
# skipped during full-tree materialization, not treated as a non-blob
# entry that fails the scope closed. Without the skip, every
# submodule-bearing repository fails Strix on any Dockerfile/compose PR.
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 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"
# The full-head scope must materialize the changed Dockerfile and the
# unchanged docs context, and must never materialize the gitlink as a path.
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
dockerfile="$target_path/Dockerfile"
if [ ! -f "$dockerfile" ] || ! grep -Fq -- 'FROM python:3.12-slim AS head' "$dockerfile"; then
echo "Error: changed Dockerfile missing head content" >&2
exit 61
fi
context_file="$target_path/docs/full-scope-context.md"
if [ ! -f "$context_file" ] || ! grep -Fq -- 'HEAD_FULL_SCOPE_CONTEXT_SHOULD_BE_SCANNED' "$context_file"; then
echo "Error: full PR head scoped context missing" >&2
exit 65
fi
if [ -e "$target_path/vendor/newsdom-api" ]; then
echo "Error: gitlink must not be materialized as a path" >&2
exit 69
fi
echo "scan ok with PR head content"
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
mkdir -p docs
printf '%s\n' 'BASE_FULL_SCOPE_CONTEXT_SHOULD_NOT_BE_SCANNED' >docs/full-scope-context.md
printf '%s\n' 'FROM python:3.12-slim AS base' >Dockerfile
git add .
git commit -qm 'base commit'
)
local seed_sha
seed_sha="$(git -C "$repo_root_dir" rev-parse HEAD)"
# Add the SAME unchanged gitlink to both base and head, so the regression
# proves an *unchanged* submodule pointer is skipped in the full tree.
git -C "$repo_root_dir" update-index --add --cacheinfo "160000,$seed_sha,vendor/newsdom-api"
git -C "$repo_root_dir" commit -qm 'add gitlink to base'
local base_sha
base_sha="$(git -C "$repo_root_dir" rev-parse HEAD)"
(
cd "$repo_root_dir"
printf '%s\n' 'HEAD_FULL_SCOPE_CONTEXT_SHOULD_BE_SCANNED' >docs/full-scope-context.md
printf '%s\n' 'FROM python:3.12-slim AS head' >Dockerfile
# Stage only the changed files. `git add .` would stage removal of the
# not-checked-out gitlink and drop it from the head tree, so the full-tree
# materialization would never see the submodule pointer this case exists
# to exercise.
git add docs/full-scope-context.md Dockerfile
git commit -qm 'head commit changes Dockerfile'
)
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_NUMBER="123" \
PR_BASE_SHA="$base_sha" \
PR_HEAD_SHA="$head_sha" \
STRIX_TEST_CHANGED_FILES_OVERRIDE="Dockerfile" \
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 "0" "$rc" "full-head-scope gitlink skip exits successfully"
assert_file_contains "$output_log" "scan ok with PR head content" "full-head-scope gitlink skip scans head content"
assert_file_contains "$output_log" "git submodule pointer; excluding content from PR-scoped Strix input: vendor/newsdom-api" "full-head-scope gitlink skip reason is visible"

rm -rf "$tmp_dir"
}

run_pull_request_target_rejects_unsafe_changed_path_case() {
local case_name="$1"
local changed_file="$2"
Expand Down Expand Up @@ -8809,6 +8927,8 @@ run_pull_request_target_irregular_head_entry_fails_closed_case \

run_pull_request_target_gitlink_is_explicitly_skipped_case

run_full_head_scope_skips_gitlink_case

run_pull_request_target_aborts_on_pr_head_blob_failure_case \
"pull-request-target-modified-file-pr-head-tree-lookup-failure" \
"src/existing.py" \
Expand Down
Loading