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
1 change: 0 additions & 1 deletion .github/workflows/strix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,6 @@ jobs:
STRIX_TRANSIENT_RETRY_BACKOFF_SECONDS: 3
STRIX_FAIL_ON_PROVIDER_SIGNAL: "1"
STRIX_VERTEX_FALLBACK_MODELS: ""
STRIX_PR_SCOPE_MAX_FILES_PER_BATCH: 1
NPM_CONFIG_IGNORE_SCRIPTS: "true"
PNPM_CONFIG_IGNORE_SCRIPTS: "true"
YARN_ENABLE_SCRIPTS: "false"
Expand Down
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
do not carry stale timeout-signal strings. Keep PR-scope process budgets large
enough for Strix to finalize reports after the scanner emits completion
events; a wrapper timeout after `vulnerability_count: 0` is still failed
evidence, not a pass. PR evidence should use deterministic single-file
batches until the Vertex-backed scanner proves bounded multi-file completion.
Keep
evidence, not a pass. PR evidence must present the full PR-head scope to
Strix in one scanner invocation; do not split changed files into separate
scanner runs because that breaks Strix's required whole-context contract. Keep
architecture docs and reusable Strix gate tests aligned with this rule so
stale GitHub Models, OpenAI-only, unavailable-model, blanket-warning, or
generic-key examples cannot re-enter copied workflow guidance.
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ mail/calendar/file systems.
timeout-named workflow `env:` entries. PR-scope scan budgets leave room for
report finalization after Strix emits completion events; workflow PR evidence
uses `STRIX_TARGET_PATH=__PR_SCOPE__` so the scanner target is the generated
PR-head scope, not the trusted base checkout, and runs deterministic
single-file batches so large PR scopes do not wait for a multi-file batch to
hit the process budget. Scanner child processes disable
PR-head scope, not the trusted base checkout. Strix receives that complete
PR-head scope in one scanner invocation because its analysis contract depends
on the whole changed-file context. Scanner child processes disable
npm, pnpm, yarn, and bun lifecycle scripts while inspecting PR scope data.
Wrapper timeout output is failed evidence. Pending CodeRabbit or check
evidence is a wait state, not a hard blocker.
Expand Down
20 changes: 10 additions & 10 deletions docs/plans/2026-05-29-strix-full-scan-operational-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@
- Pending checks are wait states, but a full-scan route that exceeds its process
budget is not acceptable operating evidence under the no Timeout/Fatal/Warn/
Denied policy.
- PR #311 Strix run `26661237230` timed out the first PR-scope batch after
`1200s`, then found a HIGH OIDC admin-claim issue only after rebatching. The
next head run `26662731398` remained in `Run Strix (quick)` for more than one
hour, showing that a 12-file first batch is not operationally bounded enough
for current Vertex-backed PR evidence.
- PR #311 Strix run `26661237230` exceeded the earlier process budget before
later surfacing a HIGH OIDC admin-claim issue. The next head run `26662731398`
remained in `Run Strix (quick)` for more than one hour, showing that the
Vertex-backed provider path itself needed clearer timeout evidence handling.
- PR #312 run `26669020785` used the old quarantine path and then failed after
repeated `MidStreamFallbackError` and timeout-class provider failures while
printing zero vulnerabilities. Under the no Timeout/Fatal/Warn/Denied policy,
Expand All @@ -30,8 +29,9 @@
HMAC/OIDC verification path.
- PR #312 manual current-head run `26686952879` printed zero vulnerabilities but
still timed out after `2400s`. That confirms zero-vulnerability text is not
enough; the PR-scope runner must avoid large multi-file batches that do not
complete cleanly.
enough; timeout-class evidence remains failed evidence. PR scope must still be
presented to Strix as one whole-context target rather than split into separate
scanner runs.

## Plan

Expand All @@ -47,9 +47,9 @@
forwarding from PR #303.
5. Add regression assertions so later edits cannot accidentally quarantine the
approved 3.1 route or pass after timeout/provider failure output.
6. Start PR-scope evidence with single-file deterministic batches instead of
waiting for a 12-file batch to hit the process budget and rebalance after the
timeout.
6. Present the generated PR-head scope to Strix in one scanner invocation. Do not
split changed files into separate scanner runs because Strix's whole-context
review model expects all relevant files together.
7. Validate OIDC issuer/JWKS hostnames by resolving every address to a global IP
before startup accepts the configuration, and make JWKS preload fetches
connect to that validated pinned address while preserving TLS/SNI for the
Expand Down
140 changes: 8 additions & 132 deletions scripts/ci/strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ ACTIVE_REPORTS_DIR="$STRIX_RUNTIME_DIR/reports"
STRIX_REPORTS_DIR="$ACTIVE_REPORTS_DIR"
STRIX_PROCESS_TIMEOUT_SECONDS="${STRIX_PROCESS_TIMEOUT_SECONDS:-1200}"
STRIX_TOTAL_TIMEOUT_SECONDS="${STRIX_TOTAL_TIMEOUT_SECONDS:-0}"
STRIX_PR_SCOPE_MAX_FILES_PER_BATCH="${STRIX_PR_SCOPE_MAX_FILES_PER_BATCH:-20}"
STRIX_DISABLE_PR_SCOPING="${STRIX_DISABLE_PR_SCOPING:-1}"
# shellcheck disable=SC2034 # consumed by sourced normalize_model helper
DEFAULT_PROVIDER_RAW="${STRIX_LLM_DEFAULT_PROVIDER:-}"
Expand Down Expand Up @@ -54,8 +53,6 @@ CHANGED_FILES=()
PULL_REQUEST_CHANGED_FILES=()
NORMALIZED_CHANGED_FILES=()
PULL_REQUEST_SCOPE_DIRS=()
PULL_REQUEST_SCOPE_FILE_BATCHES=()
CURRENT_PULL_REQUEST_BATCH_FILE_COUNT=0
LAST_PULL_REQUEST_SCOPE_DIR=""
TARGET_PATH_IS_INTERNAL_PR_SCOPE=0

Expand Down Expand Up @@ -570,7 +567,6 @@ require_non_negative_integer "$STRIX_TRANSIENT_RETRY_PER_MODEL" "STRIX_TRANSIENT
require_non_negative_integer "$STRIX_TRANSIENT_RETRY_BACKOFF_SECONDS" "STRIX_TRANSIENT_RETRY_BACKOFF_SECONDS"
require_non_negative_integer "$STRIX_PROCESS_TIMEOUT_SECONDS" "STRIX_PROCESS_TIMEOUT_SECONDS"
require_non_negative_integer "$STRIX_TOTAL_TIMEOUT_SECONDS" "STRIX_TOTAL_TIMEOUT_SECONDS"
require_positive_integer "$STRIX_PR_SCOPE_MAX_FILES_PER_BATCH" "STRIX_PR_SCOPE_MAX_FILES_PER_BATCH"
case "$STRIX_FAIL_ON_PROVIDER_SIGNAL" in
0 | 1)
;;
Expand Down Expand Up @@ -1449,7 +1445,6 @@ PY
TARGET_PATH="$LAST_PULL_REQUEST_SCOPE_DIR"
TARGET_PATH_IS_INTERNAL_PR_SCOPE=1
printf "Using bounded PR-head blob scope for pull request_target Strix scan with %s scannable changed file(s).\n" "$total_files" >&2
PULL_REQUEST_SCOPE_FILE_BATCHES=()
return 0
fi
return 2
Expand All @@ -1472,48 +1467,20 @@ PY
printf "Using full target path for pull request Strix scan with %s scannable changed file(s).\n" "$total_files" >&2
fi
fi
PULL_REQUEST_SCOPE_FILE_BATCHES=()
return 0
fi
PULL_REQUEST_SCOPE_FILE_BATCHES=()
local batch_start=0
while [ "$batch_start" -lt "$total_files" ]; do
local batch_files=("${CHANGED_FILES[@]:batch_start:STRIX_PR_SCOPE_MAX_FILES_PER_BATCH}")
PULL_REQUEST_SCOPE_FILE_BATCHES+=("$(printf '%s\n' "${batch_files[@]}")")
batch_start=$((batch_start + STRIX_PR_SCOPE_MAX_FILES_PER_BATCH))
done
local build_scope_rc=0
build_pull_request_scope_dir "${CHANGED_FILES[@]}" || build_scope_rc=$?
if [ "$build_scope_rc" -ne 0 ]; then
return 2
fi
TARGET_PATH="$LAST_PULL_REQUEST_SCOPE_DIR"
TARGET_PATH_IS_INTERNAL_PR_SCOPE=1
printf "Scoped pull request Strix scan to %s changed file(s)" "$total_files" >&2
printf ".\n" >&2
if [ "${#PULL_REQUEST_SCOPE_FILE_BATCHES[@]}" -gt 1 ]; then
printf "Split pull request Strix scan into %s batch(es) of at most %s file(s).\n" \
"${#PULL_REQUEST_SCOPE_FILE_BATCHES[@]}" \
"$STRIX_PR_SCOPE_MAX_FILES_PER_BATCH" >&2
fi
return 0
}

should_rebalance_pull_request_batch() {
if ! is_pull_request_event; then
return 1
fi
if [ "$CURRENT_PULL_REQUEST_BATCH_FILE_COUNT" -le 1 ]; then
return 1
fi
if provider_signal_fail_closed_enabled; then
return 1
fi
if [ "$INFRA_ERROR_DETECTED" -ne 1 ]; then
return 1
fi
if [ "$(remaining_total_budget)" -le 0 ]; then
return 1
fi
if is_timeout_error; then
return 0
fi
return 1
}

extract_vulnerability_locations() {
local vuln_file="$1"
local location
Expand Down Expand Up @@ -2878,10 +2845,6 @@ run_current_target_scan() {
return 1
fi

if should_rebalance_pull_request_batch; then
return 75
fi

if has_only_below_threshold_vulnerabilities; then
return 0
fi
Expand Down Expand Up @@ -2990,98 +2953,11 @@ run_current_target_scan() {

prepare_pull_request_scan_scope
if [ "$TARGET_PATH_REQUESTS_PR_SCOPE" -eq 1 ] &&
[ "$TARGET_PATH_IS_INTERNAL_PR_SCOPE" -ne 1 ] &&
[ "${#PULL_REQUEST_SCOPE_FILE_BATCHES[@]}" -eq 0 ]; then
[ "$TARGET_PATH_IS_INTERNAL_PR_SCOPE" -ne 1 ]; then
echo "ERROR: STRIX_TARGET_PATH=$PR_SCOPE_TARGET_SENTINEL did not produce a PR scan scope." >&2
exit 2
fi

run_pull_request_batch_files() {
local batch_label="$1"
local total_batches="$2"
local batch_files_text="$3"
local -a batch_files=()
local previous_target_path="$TARGET_PATH"
local previous_target_is_internal="$TARGET_PATH_IS_INTERNAL_PR_SCOPE"
mapfile -t batch_files <<<"$batch_files_text"
if [ "${#batch_files[@]}" -eq 0 ]; then
echo "ERROR: pull request Strix batch '$batch_label' has no files to scan." >&2
return 1
fi

local previous_batch_file_count="$CURRENT_PULL_REQUEST_BATCH_FILE_COUNT"
CURRENT_PULL_REQUEST_BATCH_FILE_COUNT="${#batch_files[@]}"
if ! build_pull_request_scope_dir "${batch_files[@]}"; then
CURRENT_PULL_REQUEST_BATCH_FILE_COUNT="$previous_batch_file_count"
TARGET_PATH="$previous_target_path"
TARGET_PATH_IS_INTERNAL_PR_SCOPE="$previous_target_is_internal"
return 1
fi
TARGET_PATH="$LAST_PULL_REQUEST_SCOPE_DIR"
TARGET_PATH_IS_INTERNAL_PR_SCOPE=1
echo "Running pull request Strix batch ${batch_label}/${total_batches}." >&2

local batch_rc=0
run_current_target_scan || batch_rc=$?
if [ "$batch_rc" -eq 0 ]; then
capture_preexisting_report_dirs
CURRENT_PULL_REQUEST_BATCH_FILE_COUNT="$previous_batch_file_count"
TARGET_PATH="$previous_target_path"
TARGET_PATH_IS_INTERNAL_PR_SCOPE="$previous_target_is_internal"
return 0
fi

if [ "$batch_rc" -eq 75 ]; then
local midpoint=$((CURRENT_PULL_REQUEST_BATCH_FILE_COUNT / 2))
if [ "$midpoint" -le 0 ]; then
midpoint=1
fi
echo "Rebalancing pull request Strix batch ${batch_label}/${total_batches} into smaller batches after timeout." >&2
local first_half second_half
first_half="$(printf '%s\n' "${batch_files[@]:0:midpoint}")"
second_half="$(printf '%s\n' "${batch_files[@]:midpoint}")"
local first_half_rc=0
run_pull_request_batch_files "${batch_label}.1" "$total_batches" "$first_half" || first_half_rc=$?
if [ "$first_half_rc" -ne 0 ]; then
CURRENT_PULL_REQUEST_BATCH_FILE_COUNT="$previous_batch_file_count"
TARGET_PATH="$previous_target_path"
TARGET_PATH_IS_INTERNAL_PR_SCOPE="$previous_target_is_internal"
return "$first_half_rc"
fi
local second_half_rc=0
run_pull_request_batch_files "${batch_label}.2" "$total_batches" "$second_half" || second_half_rc=$?
if [ "$second_half_rc" -ne 0 ]; then
CURRENT_PULL_REQUEST_BATCH_FILE_COUNT="$previous_batch_file_count"
TARGET_PATH="$previous_target_path"
TARGET_PATH_IS_INTERNAL_PR_SCOPE="$previous_target_is_internal"
return "$second_half_rc"
fi
CURRENT_PULL_REQUEST_BATCH_FILE_COUNT="$previous_batch_file_count"
TARGET_PATH="$previous_target_path"
TARGET_PATH_IS_INTERNAL_PR_SCOPE="$previous_target_is_internal"
return 0
fi

CURRENT_PULL_REQUEST_BATCH_FILE_COUNT="$previous_batch_file_count"
TARGET_PATH="$previous_target_path"
TARGET_PATH_IS_INTERNAL_PR_SCOPE="$previous_target_is_internal"
return "$batch_rc"
}

if [ "${#PULL_REQUEST_SCOPE_FILE_BATCHES[@]}" -gt 0 ]; then
total_batches="${#PULL_REQUEST_SCOPE_FILE_BATCHES[@]}"
batch_number=0
for batch_files_text in "${PULL_REQUEST_SCOPE_FILE_BATCHES[@]}"; do
batch_number=$((batch_number + 1))
batch_rc=0
run_pull_request_batch_files "$batch_number" "$total_batches" "$batch_files_text" || batch_rc=$?
if [ "$batch_rc" -ne 0 ]; then
exit "$batch_rc"
fi
done
exit 0
fi

scan_rc=0
run_current_target_scan || scan_rc=$?
exit "$scan_rc"
Loading
Loading