Skip to content
Merged
679 changes: 400 additions & 279 deletions .github/workflows/opencode-review.yml

Large diffs are not rendered by default.

60 changes: 41 additions & 19 deletions .github/workflows/strix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,12 @@ jobs:

strix:
if: github.event_name != 'pull_request_target' || github.event.action != 'closed'
# The scan itself is hard-bounded to 12 min (the "Run Strix (quick)" step
# has timeout-minutes: 12 and exports STRIX_TOTAL_TIMEOUT_SECONDS=720), and
# every other step is quick or self-bounded (self-test is 2 min). A healthy
# run finishes well under 20 min. The 45 cap only ever bites HUNG runs (e.g.
# a network stall in pip/git with no per-step timeout); 45 min still clears
# the realistic worst case with margin while freeing a stuck runner in half
# the time. Fail-closed: hitting the cap fails the run, never passes it.
timeout-minutes: 45
# Large repositories can require a legitimate full-hour review. The scanner
# gets a 90-minute process budget and a 95-minute total retry budget; the
# 100-minute step and 120-minute job leave deterministic time to preserve
# partial reports and publish a concrete failure reason. Hitting any cap is
# fail-closed and never turns an incomplete scan into an approval.
timeout-minutes: 120
runs-on: ubuntu-latest
# Least-privilege token scoped to this job (Scorecard alert #43): the scan
# exchanges an OIDC token (id-token) and publishes same-repo status evidence
Expand Down Expand Up @@ -358,9 +356,6 @@ jobs:
# refs/pull/<n>/head has already advanced before this queued run starts.
if git -C "$TRUSTED_WORKSPACE" fetch --no-tags --depth=1 origin "$PR_HEAD_SHA"; then
git -C "$TRUSTED_WORKSPACE" cat-file -e "$PR_HEAD_SHA^{commit}"
if git -C "$TRUSTED_WORKSPACE" cat-file -e "$PR_HEAD_SHA:opencode.jsonc" 2>/dev/null; then
git -C "$TRUSTED_WORKSPACE" show "$PR_HEAD_SHA:opencode.jsonc" > "$TRUSTED_WORKSPACE/opencode.jsonc"
fi
if git -C "$TRUSTED_WORKSPACE" cat-file -e "$PR_HEAD_SHA:.github/workflows/strix.yml" 2>/dev/null; then
mkdir -p "$TRUSTED_WORKSPACE/.github/workflows"
git -C "$TRUSTED_WORKSPACE" show "$PR_HEAD_SHA:.github/workflows/strix.yml" > "$TRUSTED_WORKSPACE/.github/workflows/strix.yml"
Expand All @@ -378,9 +373,6 @@ jobs:
fetched_head_sha="$(git -C "$TRUSTED_WORKSPACE" rev-parse "refs/remotes/pull/${PR_NUMBER}/head")"
if [ "$fetched_head_sha" = "$PR_HEAD_SHA" ]; then
git -C "$TRUSTED_WORKSPACE" cat-file -e "$PR_HEAD_SHA^{commit}"
if git -C "$TRUSTED_WORKSPACE" cat-file -e "$PR_HEAD_SHA:opencode.jsonc" 2>/dev/null; then
git -C "$TRUSTED_WORKSPACE" show "$PR_HEAD_SHA:opencode.jsonc" > "$TRUSTED_WORKSPACE/opencode.jsonc"
fi
if git -C "$TRUSTED_WORKSPACE" cat-file -e "$PR_HEAD_SHA:.github/workflows/strix.yml" 2>/dev/null; then
mkdir -p "$TRUSTED_WORKSPACE/.github/workflows"
git -C "$TRUSTED_WORKSPACE" show "$PR_HEAD_SHA:.github/workflows/strix.yml" > "$TRUSTED_WORKSPACE/.github/workflows/strix.yml"
Expand Down Expand Up @@ -492,7 +484,33 @@ jobs:
if: steps.gate.outputs.enabled == 'true'
working-directory: trusted-strix-source
run: |
set -euo pipefail
python3 -m pip install --disable-pip-version-check --no-cache-dir --require-hashes -r requirements-strix-ci-hashes.txt
strix_executable="$(command -v strix || true)"
if [ -z "$strix_executable" ] || [[ "$strix_executable" != /* ]] \
|| [ ! -f "$strix_executable" ] || [ -L "$strix_executable" ] \
|| [ ! -x "$strix_executable" ]; then
echo "::error::Pinned Strix installation did not produce a trusted absolute executable path."
exit 1
fi
case "$strix_executable" in
"$GITHUB_WORKSPACE"/*|"$RUNNER_TEMP"/*)
echo "::error::Refusing a Strix executable from a workspace or runner-temp path."
exit 1
;;
esac
strix_scripts_root="$(python3 -c 'import sysconfig; print(sysconfig.get_path("scripts"))')"
strix_executable_sha256="$(python3 - "$strix_executable" <<'PY'
import hashlib
from pathlib import Path
import sys

print(hashlib.sha256(Path(sys.argv[1]).read_bytes()).hexdigest())
PY
)"
printf 'STRIX_EXECUTABLE_PATH=%s\n' "$strix_executable" >> "$GITHUB_ENV"
printf 'STRIX_EXECUTABLE_ROOT=%s\n' "$strix_scripts_root" >> "$GITHUB_ENV"
printf 'STRIX_EXECUTABLE_SHA256=%s\n' "$strix_executable_sha256" >> "$GITHUB_ENV"

- name: Mask LLM API key
if: steps.gate.outputs.enabled == 'true'
Expand Down Expand Up @@ -653,7 +671,7 @@ jobs:

- name: Run Strix (quick)
if: steps.gate.outputs.enabled == 'true'
timeout-minutes: 30
timeout-minutes: 100
# Security invariant for pull_request_target: execute only from the
# trusted base checkout. The gate copies PR-head blobs into an isolated
# temporary scope with execute bits stripped, then scans that scope as
Expand Down Expand Up @@ -700,11 +718,11 @@ jobs:
IS_PR_EVIDENCE_RUN: ${{ (github.event_name == 'pull_request_target' || github.event.client_payload.pr_number != '') && 'true' || 'false' }}
run: |
budget_suffix="TIME""OUT"
process_budget_seconds="600"
export "LLM_${budget_suffix}=120"
export "STRIX_MEMORY_COMPRESSOR_${budget_suffix}=10"
process_budget_seconds="5400"
export "LLM_${budget_suffix}=900"
export "STRIX_MEMORY_COMPRESSOR_${budget_suffix}=300"
export "STRIX_PROCESS_${budget_suffix}_SECONDS=$process_budget_seconds"
export "STRIX_TOTAL_${budget_suffix}_SECONDS=720"
export "STRIX_TOTAL_${budget_suffix}_SECONDS=5700"

# Capture the gate exit code plus its console output. The gate returns
# exit 1 both for genuine blocking vulnerabilities AND for
Expand Down Expand Up @@ -766,6 +784,10 @@ jobs:
copied_reports=1
fi
done
if [ -f "$RUNNER_TEMP/strix_gate_console.log" ]; then
cp "$RUNNER_TEMP/strix_gate_console.log" "$GITHUB_WORKSPACE/strix_runs/gate-console.log"
copied_reports=1
fi
if [ -n "$(find "$GITHUB_WORKSPACE/strix_runs" -mindepth 1 -print -quit)" ]; then
copied_reports=1
fi
Expand Down
15 changes: 13 additions & 2 deletions scripts/ci/strix_model_utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ is_vertex_resource_path() {
IFS='/' read -r -a parts <<<"$path"
local part
for part in "${parts[@]}"; do
if [ -z "$part" ]; then
if [ -z "$part" ] || [ "$part" = "." ] || [ "$part" = ".." ] ||
[[ ! "$part" =~ ^[A-Za-z0-9._-]+$ ]]; then
return 1
fi
done
Expand Down Expand Up @@ -78,7 +79,17 @@ normalize_model() {

if is_vertex_resource_path "$model"; then
local provider
provider="$(sanitize_provider_name "vertex_ai")" || return $?
provider="$(sanitize_provider_name "${DEFAULT_PROVIDER:-}")" || {
echo "ERROR: Vertex resource paths require an explicit vertex_ai or vertex_ai_beta provider." >&2
return 2
}
case "$provider" in
vertex_ai | vertex_ai_beta) ;;
*)
echo "ERROR: Vertex resource paths require an explicit vertex_ai or vertex_ai_beta provider." >&2
return 2
;;
esac
printf '%s/%s\n' "$provider" "$(extract_vertex_model_id "$model")"
return 0
fi
Expand Down
Loading
Loading