diff --git a/.github/workflows/strix.yml b/.github/workflows/strix.yml index 177a31aa..879aab65 100644 --- a/.github/workflows/strix.yml +++ b/.github/workflows/strix.yml @@ -485,6 +485,11 @@ jobs: working-directory: trusted-strix-source run: | set -euo pipefail + # GitHub-hosted runners may inherit a collaborative umask (0002), + # which makes pip-generated console scripts group-writable. Pin a + # private install umask before creating the credential-bearing Strix + # entry point; the runtime gate still rejects any later relaxation. + umask 022 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" != /* ]] \ @@ -508,9 +513,11 @@ jobs: 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" + { + printf 'STRIX_EXECUTABLE_PATH=%s\n' "$strix_executable" + printf 'STRIX_EXECUTABLE_ROOT=%s\n' "$strix_scripts_root" + printf 'STRIX_EXECUTABLE_SHA256=%s\n' "$strix_executable_sha256" + } >> "$GITHUB_ENV" - name: Mask LLM API key if: steps.gate.outputs.enabled == 'true' diff --git a/scripts/ci/test_strix_quick_gate.sh b/scripts/ci/test_strix_quick_gate.sh index a8e62d9d..3a1cb943 100755 --- a/scripts/ci/test_strix_quick_gate.sh +++ b/scripts/ci/test_strix_quick_gate.sh @@ -889,6 +889,7 @@ assert_opencode_review_uses_codegraph_and_gpt5_fallback() { assert_file_contains "$REPO_ROOT/.github/workflows/strix.yml" 'STRIX_EXECUTABLE_PATH=%s' "Strix workflow captures the pinned installation executable before scanning" assert_file_contains "$REPO_ROOT/.github/workflows/strix.yml" 'STRIX_EXECUTABLE_SHA256=%s' "Strix workflow pins the installed executable digest before scanning" assert_file_contains "$REPO_ROOT/.github/workflows/strix.yml" 'STRIX_EXECUTABLE_ROOT=%s' "Strix workflow pins the installed executable root before scanning" + assert_file_contains "$REPO_ROOT/.github/workflows/strix.yml" 'umask 022' "Strix workflow creates the credential-bearing executable without group/world write access" assert_file_contains "$GATE_SCRIPT" 'STRIX_EXECUTABLE_PATH must name the trusted installed Strix executable' "Strix gate requires an explicit trusted executable path" assert_file_contains "$GATE_SCRIPT" 'did not match the pinned SHA-256 digest' "Strix gate rejects executable substitution after trusted installation" assert_file_contains "$GATE_SCRIPT" 'STRIX_EXECUTABLE_PATH must be outside the untrusted scan target' "Strix executable cannot come from the scan target" @@ -3184,7 +3185,7 @@ printf '%s\n' "$target_path" >> "${FAKE_STRIX_TARGET_LOG:?}" STRIX_REPORTS_DIR="${STRIX_REPORTS_DIR:-strix_runs}" case "${FAKE_STRIX_SCENARIO:?}" in - success|runtime-env-forwarding|vertex-primary-success-timing-message|direct-openai-gpt-does-not-require-github-models-api-base|pr-executable-integrity-mismatch) +success|runtime-env-forwarding|vertex-primary-success-timing-message|direct-openai-gpt-does-not-require-github-models-api-base|pr-executable-integrity-mismatch|pr-executable-group-writable) echo "scan ok" exit 0 ;; @@ -5357,6 +5358,9 @@ PY STRIX_EXECUTABLE_SHA256="0000000000000000000000000000000000000000000000000000000000000000" ) fi + if [ "$scenario" = "pr-executable-group-writable" ]; then + chmod 0775 "$fake_strix" + fi if [ "$scenario" = "report-known-internal-warning-sanitized" ]; then env_cmd+=( FAKE_STRIX_OUTSIDE_REPORT_DIR="$repo_root_dir/outside-strix-report" @@ -5638,6 +5642,16 @@ run_filtered_gate_case_if_requested() { "" \ "" ;; + pr-executable-group-writable) + run_gate_case "pr-executable-group-writable" \ + "vertex_ai/ready-primary" \ + "" \ + "1" \ + "must not be group/world writable" \ + "0" \ + "" \ + "" + ;; vertex-primary-hallucinated-endpoint-fallback-success) run_gate_case "vertex-primary-hallucinated-endpoint-fallback-success" \ "vertex_ai/hallucination-primary" \ @@ -8752,6 +8766,15 @@ run_gate_case "pr-executable-integrity-mismatch" \ "" \ "" +run_gate_case "pr-executable-group-writable" \ + "vertex_ai/ready-primary" \ + "" \ + "1" \ + "must not be group/world writable" \ + "0" \ + "" \ + "" + run_gate_case "runtime-env-forwarding" \ "gemini/gemini-pro-3.1-preview" \ "" \