diff --git a/.github/workflows/strix.yml b/.github/workflows/strix.yml index 5d1ddb9ee..499ab2c67 100644 --- a/.github/workflows/strix.yml +++ b/.github/workflows/strix.yml @@ -21,6 +21,11 @@ on: description: Optional pull request head SHA for trusted PR-scope evidence required: false type: string + strix_llm: + description: Optional Strix model override for manual evidence runs + required: false + default: openai/openai/gpt-4.1 + type: string concurrency: group: strix-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} @@ -31,6 +36,7 @@ concurrency: permissions: actions: read contents: read + models: read jobs: strix: @@ -109,12 +115,23 @@ jobs: - name: Gate Strix secrets id: gate env: - STRIX_MODEL: ${{ secrets.STRIX_LLM || 'vertex_ai/gemini-3.1-pro-preview-customtools' }} + STRIX_MODEL: ${{ github.event.inputs.strix_llm || 'openai/openai/gpt-4.1' }} STRIX_OPENAI_API_KEY: ${{ secrets.STRIX_OPENAI_API_KEY }} STRIX_VERTEX_CREDENTIALS: ${{ secrets.GCP_SA_KEY }} + GITHUB_MODELS_TOKEN: ${{ github.token }} run: | strix_model="$(printf '%s' "$STRIX_MODEL" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" case "$strix_model" in + openai/openai/*) + echo 'enabled=true' >> "$GITHUB_OUTPUT" + echo 'provider_mode=github_models' >> "$GITHUB_OUTPUT" + sanitized_github_models_token="$(printf '%s' "$GITHUB_MODELS_TOKEN" | tr -d '\r\n')" + trimmed_github_models_token="$(printf '%s' "$sanitized_github_models_token" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" + if [ -z "$trimmed_github_models_token" ]; then + echo '::error::github.token is required for GitHub Models Strix scans.' + exit 1 + fi + ;; gpt-5.[4-9]* | gpt-5.[1-9][0-9]* | gpt-[6-9]* | gpt-[1-9][0-9]* | \ openai/gpt-5.[4-9]* | openai/gpt-5.[1-9][0-9]* | openai/gpt-[6-9]* | openai/gpt-[1-9][0-9]*) echo 'enabled=true' >> "$GITHUB_OUTPUT" @@ -137,7 +154,7 @@ jobs: fi ;; *) - echo '::error::STRIX_LLM must select direct OpenAI GPT-5.4 or newer, or an approved organization Vertex AI model.' + echo '::error::STRIX_LLM must select GitHub Models openai/openai/*, direct OpenAI GPT-5.4 or newer, or an approved organization Vertex AI model.' exit 1 ;; esac @@ -152,7 +169,7 @@ jobs: - name: Mask LLM API key if: steps.gate.outputs.enabled == 'true' env: - LLM_API_KEY: ${{ steps.gate.outputs.provider_mode == 'openai_direct' && secrets.STRIX_OPENAI_API_KEY || '' }} + LLM_API_KEY: ${{ steps.gate.outputs.provider_mode == 'github_models' && github.token || steps.gate.outputs.provider_mode == 'openai_direct' && secrets.STRIX_OPENAI_API_KEY || '' }} run: | # Sanitize CR/LF before masking to prevent broken ::add-mask:: # commands and potential workflow command injection. @@ -168,11 +185,15 @@ jobs: - name: Prepare LLM API key input file if: steps.gate.outputs.enabled == 'true' env: - LLM_API_KEY_SECRET: ${{ steps.gate.outputs.provider_mode == 'openai_direct' && secrets.STRIX_OPENAI_API_KEY || '' }} + LLM_API_KEY_SECRET: ${{ steps.gate.outputs.provider_mode == 'github_models' && github.token || steps.gate.outputs.provider_mode == 'openai_direct' && secrets.STRIX_OPENAI_API_KEY || '' }} PROVIDER_MODE: ${{ steps.gate.outputs.provider_mode }} run: | sanitized="$(printf '%s' "$LLM_API_KEY_SECRET" | tr -d '\r\n')" trimmed="$(printf '%s' "$sanitized" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" + if [ -z "$trimmed" ] && [ "$PROVIDER_MODE" = "github_models" ]; then + echo '::error::github.token is required for GitHub Models Strix scans.' + exit 1 + fi if [ -z "$trimmed" ] && [ "$PROVIDER_MODE" = "openai_direct" ]; then echo '::error::STRIX_OPENAI_API_KEY is required for Strix OpenAI Platform scans.' exit 1 @@ -182,6 +203,14 @@ jobs: printf '%s' "$sanitized" > "$llm_api_key_file" echo "LLM_API_KEY_FILE=$llm_api_key_file" >> "$GITHUB_ENV" + - name: Prepare GitHub Models API base + if: steps.gate.outputs.provider_mode == 'github_models' + run: | + umask 077 + llm_api_base_file="$RUNNER_TEMP/llm_api_base.txt" + printf '%s' 'https://models.github.ai/inference' > "$llm_api_base_file" + echo "LLM_API_BASE_FILE=$llm_api_base_file" >> "$GITHUB_ENV" + - name: Prepare Vertex AI credentials if: steps.gate.outputs.provider_mode == 'vertex_ai' env: @@ -213,12 +242,15 @@ jobs: - name: Prepare Strix model input file if: steps.gate.outputs.enabled == 'true' env: - STRIX_MODEL: ${{ secrets.STRIX_LLM || 'vertex_ai/gemini-3.1-pro-preview-customtools' }} + STRIX_MODEL: ${{ github.event.inputs.strix_llm || 'openai/openai/gpt-4.1' }} run: | umask 077 strix_llm_file="$RUNNER_TEMP/strix_llm.txt" strix_model="$(printf '%s' "$STRIX_MODEL" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" case "$strix_model" in + openai/openai/*) + printf '%s' "$strix_model" > "$strix_llm_file" + ;; openai/*) printf '%s' "$strix_model" > "$strix_llm_file" ;; @@ -229,7 +261,7 @@ jobs: printf '%s' "$strix_model" > "$strix_llm_file" ;; *) - echo '::error::STRIX_LLM must select direct OpenAI GPT-5.4 or newer, or an approved organization Vertex AI model.' + echo '::error::STRIX_LLM must select GitHub Models openai/openai/*, direct OpenAI GPT-5.4 or newer, or an approved organization Vertex AI model.' exit 1 ;; esac @@ -245,6 +277,7 @@ jobs: working-directory: ${{ runner.temp }}/trusted-workspace env: STRIX_LLM_FILE: ${{ env.STRIX_LLM_FILE }} + LLM_API_BASE_FILE: ${{ env.LLM_API_BASE_FILE }} STRIX_LLM_DEFAULT_PROVIDER: ${{ steps.gate.outputs.provider_mode == 'vertex_ai' && 'vertex_ai' || 'openai' }} LLM_API_KEY_FILE: ${{ env.LLM_API_KEY_FILE }} GOOGLE_APPLICATION_CREDENTIALS: ${{ env.GOOGLE_APPLICATION_CREDENTIALS }} diff --git a/AGENTS.md b/AGENTS.md index c7c866c11..54205ba90 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,14 +13,18 @@ single files if that makes real repo modules look missing. - Prefer upgrading or removing vulnerable dependencies over downgrading patched packages unless compatibility evidence is recorded in the PR. -- Strix Security Scan must not route through GitHub Models, `github.token`, - generic `LLM_API_KEY`, GPT-4o, or GPT-4.1. The current organization-secret - route is `STRIX_LLM` with `GCP_SA_KEY`; - `vertex_ai/gemini-3.1-pro-preview-customtools` is the default approved Vertex - model now that organization-secret visibility is available, with - `vertex_ai/gemini-2.5-flash` allowed only as an explicit legacy selection. - Expose Google/Vertex credentials only for Vertex provider mode. Direct OpenAI - GPT-5.4-or-newer scans remain supported only when selected explicitly with +- Strix Security Scan uses GitHub Models by default through `github.token`, + `models: read`, `STRIX_LLM=openai/openai/gpt-4.1`, and + `LLM_API_BASE_FILE` pointing at a trusted file containing + `https://models.github.ai/inference`. Keep the GitHub Models endpoint in a + trusted input file and pass the token only through the + provider-scoped Strix child-process key path. Legacy `STRIX_LLM` secrets must + not override PR, push, or scheduled Strix defaults. Vertex remains available + only for manual `workflow_dispatch` evidence when the `strix_llm` input + explicitly selects `vertex_ai/gemini-3.1-pro-preview-customtools` or + `vertex_ai/gemini-2.5-flash` with `GCP_SA_KEY`; expose Google/Vertex + credentials only for Vertex provider mode. Direct OpenAI GPT-5.4-or-newer + scans remain supported only for manual `strix_llm` selections with `STRIX_OPENAI_API_KEY`. Do not silently fall back between providers, and do not treat timeout-class provider infrastructure failures as clean PR evidence even when Strix printed zero vulnerabilities before failing. Disable @@ -39,7 +43,7 @@ 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 + stale Vertex-default, OpenAI-only, unavailable-model, blanket-warning, or generic-key examples cannot re-enter copied workflow guidance. - HMAC fallback sessions are local/control-plane compatibility credentials, not authoritative workspace-membership evidence. Sensitive tenant security posture @@ -208,9 +212,9 @@ responses must include `Referrer-Policy`, and `target="_blank"` links must use explicit `rel="noopener noreferrer"`. - When robot review cites an obsolete Strix provider policy, update the docs and - tests to the current secret contract before accepting a rollback suggestion; - do not reintroduce generic `LLM_API_KEY`, GitHub Models, or cross-provider - credential forwarding while trying to satisfy old comments. + tests to the current GitHub Models default contract before accepting a + rollback suggestion; do not reintroduce generic `LLM_API_KEY` or + cross-provider credential forwarding while trying to satisfy old comments. - When reviews find inert navigation/dead-space controls, either wire them to an implemented workspace route/API or remove the control; do not leave high-traffic drawer/sidebar entries as permanent `준비 중` copy. diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index c5727fd31..564a4744b 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -155,13 +155,19 @@ request branch scripts in the privileged Strix job. The gate fails closed when a changed PR-head blob cannot be validated or copied; it must never fall back to scanning trusted-base content for a modified PR path. -Pull request scans split scoped changed files into small bounded batches before -the timeout-driven rebalance path, so large PRs do not spend the whole required -check budget on one oversized Strix invocation. Strix remains a required -Medium-or-higher gate. The workflow uses only the explicit -`STRIX_OPENAI_API_KEY` OpenAI Platform credential with an OpenAI -GPT-5.4-or-newer model, rejects GitHub Models routing and `github.token` LLM -credentials, and fails closed when direct credentials are missing or exhausted. +Pull request scans present the generated PR-head scope to Strix in one +whole-context invocation, rather than splitting changed files into separate +scanner runs. Strix remains a required Medium-or-higher gate. The workflow +defaults to GitHub Models with +`models: read`, the workflow `github.token`, `STRIX_LLM=openai/openai/gpt-4.1`, +and `LLM_API_BASE_FILE` pointing at a trusted file containing +`https://models.github.ai/inference`, while keeping the token and API base +isolated to trusted input files and the Strix child-process environment. Legacy +`STRIX_LLM` secrets do not override PR, push, or scheduled +Strix defaults; explicit Vertex and direct OpenAI routes remain supported only +through manual `workflow_dispatch` `strix_llm` selections and their +provider-scoped credential paths. Provider infrastructure errors still fail +closed. Merge-gate governance for Strix, CodeRabbit, and required review evidence is documented in `docs/development/merge-gate-policy.md`. diff --git a/README.md b/README.md index 9cc992c4d..132e2c5ae 100644 --- a/README.md +++ b/README.md @@ -28,25 +28,32 @@ mail/calendar/file systems. open-source observability. - PR automation is metadata-only and uses current-head robot-review evidence plus required checks. Human approval is not awaited by default under repo policy. -- Strix PR/security evidence uses the organization-secret provider selected by - `STRIX_LLM` with `GCP_SA_KEY`; missing `STRIX_LLM` defaults to the approved - `vertex_ai/gemini-3.1-pro-preview-customtools` Vertex route now that - organization-secret visibility is available. Direct OpenAI GPT-5.4-or-newer - remains supported only with an explicit `STRIX_OPENAI_API_KEY`. The workflow - fails closed rather than falling back to GitHub Models, `github.token`, - generic `LLM_API_KEY`, GPT-4-era models, or timeout-class provider - infrastructure failures. Known third-party Strix/Pydantic serializer warnings - are filtered narrowly instead of allowing Warn-class logs into passing - evidence, and runtime scan-budget variables are not listed as visible - 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 +- Strix PR/security evidence defaults to GitHub Models through + `STRIX_LLM=openai/openai/gpt-4.1`, `models: read`, `github.token`, and + `LLM_API_BASE_FILE` pointing at a trusted file containing + `https://models.github.ai/inference`. The workflow keeps that endpoint in a + trusted input file and passes the token only through the + provider-scoped Strix child-process key path. Legacy `STRIX_LLM` secrets do + not override PR, push, or scheduled Strix defaults. Vertex remains available + only for manual `workflow_dispatch` evidence when `strix_llm` explicitly + selects `vertex_ai/gemini-3.1-pro-preview-customtools` or + `vertex_ai/gemini-2.5-flash` with `GCP_SA_KEY`; direct OpenAI + GPT-5.4-or-newer remains supported only for manual `strix_llm` selections + with `STRIX_OPENAI_API_KEY`. The workflow fails closed rather than using generic + `LLM_API_KEY`, silently falling back across providers, or treating + timeout-class provider infrastructure failures as clean evidence. Known + third-party Strix/Pydantic serializer warnings are filtered narrowly instead + of allowing Warn-class logs into passing evidence, and runtime scan-budget + variables are not listed as visible 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. 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. + 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. - Security governance is source-backed through signed `/api/security/access-surface`. The endpoint reads scoped WebDAV, CalDAV, and connector evidence plus durable `security_audit_events`, reuses the deny-first diff --git a/backend/tests/test_release_governance.py b/backend/tests/test_release_governance.py index fdc61e31e..ce3b08610 100644 --- a/backend/tests/test_release_governance.py +++ b/backend/tests/test_release_governance.py @@ -187,21 +187,26 @@ def test_compose_log_scanner_exists_for_warning_policy() -> None: assert "unexpected_count" in scanner -def test_strix_workflow_uses_configured_vertex_model_and_narrow_warning_filter() -> ( +def test_strix_workflow_uses_github_models_default_and_narrow_warning_filter() -> ( None ): workflow = read_repo_text(".github/workflows/strix.yml") gate_script = read_repo_text("scripts/ci/strix_quick_gate.sh") - assert "models: read" not in workflow - assert "provider_mode=github_models" not in workflow + assert "models: read" in workflow + assert "provider_mode=github_models" in workflow + assert "strix_llm:" in workflow + assert "github.event.inputs.strix_llm || 'openai/openai/gpt-4.1'" in workflow + assert "secrets.STRIX_LLM ||" not in workflow + assert "https://models.github.ai/inference" in workflow + assert "LLM_API_BASE_FILE" in workflow + assert "github.token is required for GitHub Models Strix scans" in workflow assert "vertex_ai/gemini-3.1-pro-preview-customtools" in workflow assert ( "secrets.STRIX_LLM == 'vertex_ai/gemini-3.1-pro-preview-customtools' " "&& 'vertex_ai/gemini-2.5-flash'" not in workflow ) - assert "secrets.STRIX_LLM || 'vertex_ai/gemini-3.1-pro-preview-customtools'" in workflow assert 'STRIX_FAIL_ON_PROVIDER_SIGNAL: "1"' in workflow assert 'STRIX_VERTEX_FALLBACK_MODELS: ""' in workflow assert ( diff --git a/docs/plans/2026-05-19-north-star-gap-closure.md b/docs/plans/2026-05-19-north-star-gap-closure.md index e982c2245..90b423bf0 100644 --- a/docs/plans/2026-05-19-north-star-gap-closure.md +++ b/docs/plans/2026-05-19-north-star-gap-closure.md @@ -36,11 +36,11 @@ connector, and PR governance is metadata-only. the exact `Strix Security Scan` workflow, runs a trusted-base governance script, separates pending/waiting states from failures, and updates an idempotent marker comment instead of posting duplicates. -- [x] Strix provider hardening: the workflow fails closed instead of routing - scanner traffic through GitHub Models, `github.token`, generic `LLM_API_KEY`, - GPT-4o, or GPT-4.1. The current approved default is the validated - org-secret Vertex AI model, while direct OpenAI GPT-5.4+ remains - explicit-only through `STRIX_OPENAI_API_KEY`. +- [x] Strix provider hardening: the workflow now defaults to GitHub Models via + `models: read`, `github.token`, and a trusted `LLM_API_BASE` input file while + still failing closed on generic `LLM_API_KEY`, cross-provider fallback, and + provider infrastructure failures. Vertex and direct OpenAI remain + explicit-only alternate provider paths. - [x] CalDAV source registry: `/api/calendar/writeback-intent` now resolves DB-backed `calendar_writeback_sources` rows with opaque `source_uid` values instead of exposing sequential CalDAV account ids or accepting browser-supplied diff --git a/docs/plans/2026-05-27-apm-connector-operational-signals.md b/docs/plans/2026-05-27-apm-connector-operational-signals.md index adee49a7f..d4b7d0387 100644 --- a/docs/plans/2026-05-27-apm-connector-operational-signals.md +++ b/docs/plans/2026-05-27-apm-connector-operational-signals.md @@ -27,7 +27,8 @@ exist yet. - No IMAP/SMTP/CalDAV/WebDAV provider execution. - No Naruon-hosted mailbox/storage claim. -- No GitHub Models routing for Strix or security scans. +- No generic LLM credentials or cross-provider fallback for Strix or security + scans. - No queue-depth, provider-throttling, sync-lag, or writeback-conflict execution events until source-backed connector jobs emit them. diff --git a/docs/plans/2026-05-27-self-sent-webdav-materialization-intent.md b/docs/plans/2026-05-27-self-sent-webdav-materialization-intent.md index bb0771041..c9602fd7c 100644 --- a/docs/plans/2026-05-27-self-sent-webdav-materialization-intent.md +++ b/docs/plans/2026-05-27-self-sent-webdav-materialization-intent.md @@ -58,9 +58,9 @@ Browser evidence to inspect: ## Governance -- Strix follows the current provider governance contract: the approved default - is the validated org-secret Vertex AI model `vertex_ai/gemini-2.5-flash`, - while direct OpenAI GPT-5.4+ remains explicit-only through - `STRIX_OPENAI_API_KEY`. -- GitHub Models, `github.token`, generic `LLM_API_KEY`, arbitrary - Gemini/Vertex fallback, GPT-4o, and GPT-4.1 are not valid Strix routes. +- Strix follows the current provider governance contract: GitHub Models is the + default via `models: read`, `github.token`, and a trusted `LLM_API_BASE` + input file, while Vertex and direct OpenAI remain explicit-only provider + paths. +- Generic `LLM_API_KEY`, arbitrary Gemini/Vertex fallback, and cross-provider + credential forwarding are not valid Strix routes. diff --git a/docs/plans/2026-05-27-strix-openai-direct-only.md b/docs/plans/2026-05-27-strix-openai-direct-only.md index 459277672..d58874aca 100644 --- a/docs/plans/2026-05-27-strix-openai-direct-only.md +++ b/docs/plans/2026-05-27-strix-openai-direct-only.md @@ -5,30 +5,37 @@ ## Goal Keep the required Strix security gate on, but make the provider contract -unambiguous. The active route is the organization-secret Vertex AI provider -selected through `STRIX_LLM` with `GCP_SA_KEY`; run `26581416713` validated -`vertex_ai/gemini-2.5-flash` as the operational model and proved -`vertex_ai/gemini-3.1-pro-preview-customtools` is not available to this project. -Direct OpenAI GPT-5.4-or-newer remains allowed only when explicitly selected -with `STRIX_OPENAI_API_KEY`. Strix must not route through GitHub Models, -`github.token`, GPT-4-era models, or a generic `LLM_API_KEY`. +unambiguous. The active default route is GitHub Models selected through +`STRIX_LLM=openai/openai/gpt-4.1`, `models: read`, `github.token`, and +`LLM_API_BASE_FILE` pointing at a trusted file containing +`https://models.github.ai/inference`. Legacy `STRIX_LLM` secrets must not +override PR, push, or scheduled Strix defaults. Vertex AI remains available only +for manual `workflow_dispatch` evidence when `strix_llm` +explicitly selects an approved Vertex model with `GCP_SA_KEY`, and direct OpenAI +GPT-5.4-or-newer remains allowed only for manual `strix_llm` selections with +`STRIX_OPENAI_API_KEY`. Strix must not route through a generic `LLM_API_KEY` or +silently fall back across providers. ## Evidence - PR #237 showed `provider_mode=openai_direct` and `api.openai.com` egress, then failed because the OpenAI Platform credential hit quota. That is external provider exhaustion, not a GitHub Models path. -- On 2026-05-28 the operator selected the org-secret Vertex AI route instead of - GitHub Models or direct OpenAI as the default. The workflow therefore keeps - narrow Vertex branches for approved, verified model names and keeps direct - OpenAI as an explicit alternate path. +- On 2026-06-02 the operator selected GitHub Models as the default route for + Strix failures. The workflow therefore keeps GitHub Models as the default, + using the highest GitHub Models OpenAI route verified by organization Actions + evidence at the time, while retaining narrow manual Vertex branches, higher + GitHub Models overrides, and direct OpenAI as explicit alternate paths. ## Implementation +- Keep GitHub Models credential handling inside `provider_mode=github_models` + with `github.token` passed through the trusted child-process key file and + `LLM_API_BASE_FILE` pointing at a trusted temp file. - Keep GCP credential gating, Google Cloud authentication, and credential export - only inside `provider_mode=vertex_ai`, and only for approved Vertex model - names. -- Keep direct OpenAI isolated behind `provider_mode=openai_direct` and + only inside manual `provider_mode=vertex_ai`, and only for approved Vertex + model names. +- Keep direct OpenAI isolated behind manual `provider_mode=openai_direct` and `STRIX_OPENAI_API_KEY`. - Keep the privileged PR pattern: trusted-base workspace materialization, immutable PR-head fetch as data, self-test from trusted workspace, and pinned @@ -36,9 +43,9 @@ with `STRIX_OPENAI_API_KEY`. Strix must not route through GitHub Models, - Keep `continue-on-error` out of Strix. Provider quota remains a failed scan, and any temporary merge-gate adjustment must capture evidence and restore the required `strix` context immediately after merge processing. -- Update self-tests so the workflow fails static verification if GitHub Models, - generic `LLM_API_KEY`, arbitrary Vertex/Gemini models, or cross-provider - credential forwarding is reintroduced. +- Update self-tests so the workflow fails static verification if the GitHub + Models default, generic `LLM_API_KEY`, arbitrary Vertex/Gemini models, or + cross-provider credential forwarding regresses. ## Verification diff --git a/docs/plans/2026-05-29-strix-full-scan-operational-model.md b/docs/plans/2026-05-29-strix-full-scan-operational-model.md index 359ccbb5b..e47b2eb71 100644 --- a/docs/plans/2026-05-29-strix-full-scan-operational-model.md +++ b/docs/plans/2026-05-29-strix-full-scan-operational-model.md @@ -35,12 +35,14 @@ ## Plan -1. Keep the organization-secret `STRIX_LLM` route and honor the exact - `vertex_ai/gemini-3.1-pro-preview-customtools` value now that organization - secret visibility is available. -2. Default missing `STRIX_LLM` to - `vertex_ai/gemini-3.1-pro-preview-customtools` rather than silently routing - to GitHub Models or a downgraded Vertex fallback. +1. Keep the GitHub Models default route with + `STRIX_LLM=openai/openai/gpt-4.1`, `models: read`, `github.token`, and + `LLM_API_BASE_FILE` pointing at a trusted file containing + `https://models.github.ai/inference`. +2. Keep legacy `STRIX_LLM` secrets from overriding PR, push, or scheduled + defaults. Keep Vertex routes explicit through manual `workflow_dispatch` + `strix_llm` selections plus `GCP_SA_KEY`, and keep direct OpenAI explicit + through manual `strix_llm` selections plus `STRIX_OPENAI_API_KEY`. 3. Keep arbitrary Vertex model patterns disallowed; only exact approved Vertex models are accepted. 4. Preserve the narrow Pydantic serializer warning filter and gate child-process @@ -71,7 +73,8 @@ ## Non-Goals -- This does not reintroduce GitHub Models or generic `LLM_API_KEY`. +- This does not reintroduce generic `LLM_API_KEY` or cross-provider credential + forwarding. - This does not suppress scanner findings, timeouts, denied access, fatal errors, or application warnings. - This does not treat zero-vulnerability text as sufficient evidence after a diff --git a/docs/plans/2026-05-29-strix-vertex-model-warning-filter.md b/docs/plans/2026-05-29-strix-vertex-model-warning-filter.md index 3138a483d..a5bb3e6fb 100644 --- a/docs/plans/2026-05-29-strix-vertex-model-warning-filter.md +++ b/docs/plans/2026-05-29-strix-vertex-model-warning-filter.md @@ -7,19 +7,22 @@ `Pydantic serializer warnings`. - Project policy treats `Timeout`, `Fatal`, `Warn`, and `Denied` output as failure evidence even when the GitHub job conclusion is success. -- The organization secret `STRIX_LLM` is expected to select - `vertex_ai/gemini-3.1-pro-preview-customtools`; GitHub Models must not be used - for this route. +- The active default route is GitHub Models via + `STRIX_LLM=openai/openai/gpt-4.1`, `models: read`, `github.token`, and + `LLM_API_BASE_FILE` pointing at a trusted file containing + `https://models.github.ai/inference`. Explicit Vertex routes still require + organization `GCP_SA_KEY` credentials. ## Plan 1. Keep the Strix workflow on trusted `pull_request_target` materialization with - no PR-head checkout and no GitHub Models permission. + no PR-head checkout and only the minimal `models: read` permission required + for GitHub Models inference. 2. Allow only exact organization-approved Vertex model names: `vertex_ai/gemini-3.1-pro-preview-customtools` and `vertex_ai/gemini-2.5-flash`. -3. Default missing `STRIX_LLM` to the configured organization Vertex model so - org-secret visibility issues do not silently route to GitHub Models. +3. Default missing `STRIX_LLM` to the configured GitHub Models route, and keep + Vertex/OpenAI available only through explicit provider-scoped selections. 4. Suppress only the known third-party `pydantic.main` serializer warning via `PYTHONWARNINGS`; do not blanket-ignore all `UserWarning` output. 5. Forward that warning contract through the Strix gate to the Python child @@ -31,5 +34,5 @@ - Naruon application warnings remain failures in CI. - Strix findings, failed auth, timeout, denial, or security scanner errors are not suppressed. -- GitHub Models, `github.token`, generic `LLM_API_KEY`, and arbitrary Vertex - model patterns remain disallowed. +- Generic `LLM_API_KEY`, cross-provider credential forwarding, and arbitrary + Vertex model patterns remain disallowed. diff --git a/docs/plans/2026-05-29-strix-warning-filter-log-surface.md b/docs/plans/2026-05-29-strix-warning-filter-log-surface.md index 4204b2dba..2192abf8f 100644 --- a/docs/plans/2026-05-29-strix-warning-filter-log-surface.md +++ b/docs/plans/2026-05-29-strix-warning-filter-log-surface.md @@ -24,4 +24,5 @@ - Do not suppress Strix findings, timeouts, fatal errors, denied access, or application warnings. -- Do not reintroduce GitHub Models or generic LLM credentials. +- Keep GitHub Models on the explicit `provider_mode=github_models` path and do + not reintroduce generic LLM credentials. diff --git a/scripts/ci/strix_quick_gate.sh b/scripts/ci/strix_quick_gate.sh index 482b8c4f4..8eed07cd0 100644 --- a/scripts/ci/strix_quick_gate.sh +++ b/scripts/ci/strix_quick_gate.sh @@ -558,8 +558,8 @@ PRIMARY_MODEL="$(normalize_model "$STRIX_LLM")" if [ "$PRIMARY_MODEL" != "$STRIX_LLM" ]; then echo "Normalized STRIX_LLM to provider-qualified model '$PRIMARY_MODEL'." fi -if is_github_models_model "$PRIMARY_MODEL"; then - echo "ERROR: STRIX_LLM must not use GitHub Models model prefixes; use direct OpenAI Platform model names such as openai/gpt-5.4." >&2 +if is_github_models_model "$PRIMARY_MODEL" && [ -z "$LLM_API_BASE_FILE" ]; then + echo "ERROR: GitHub Models Strix scans require LLM_API_BASE_FILE to select the GitHub Models inference endpoint." >&2 exit 2 fi @@ -1872,6 +1872,10 @@ resolved_llm_api_base_for_model() { fi if [ -z "$LLM_API_BASE_FILE" ]; then + if is_github_models_model "$model"; then + echo "ERROR: GitHub Models Strix scans require LLM_API_BASE_FILE to select the GitHub Models inference endpoint." >&2 + return 2 + fi return 0 fi local resolved_llm_api_base_file @@ -1895,8 +1899,8 @@ resolved_llm_api_base_for_model() { echo "ERROR: LLM_API_BASE must be an https URL when configured." >&2 return 2 fi - if is_github_models_api_base "$llm_api_base_value"; then - echo "ERROR: LLM_API_BASE must not route Strix through GitHub Models; use direct OpenAI Platform routing." >&2 + if is_github_models_api_base "$llm_api_base_value" && ! is_github_models_model "$model"; then + echo "ERROR: LLM_API_BASE may route through GitHub Models only when STRIX_LLM uses a GitHub Models model prefix." >&2 return 2 fi printf '%s\n' "$llm_api_base_value" @@ -2322,7 +2326,7 @@ is_midstream_fallback_error() { # (httpx, httpcore, requests). Used for generic transport failures where # library names alone are insufficient to prove the timeout/connection error # originated from an LLM provider rather than the target application. -LLM_PROVIDER_ONLY_REGEX='(litellm|openai|anthropic|VertexAI|Vertex_ai|vertex\.ai|google\.cloud)' +LLM_PROVIDER_ONLY_REGEX='(litellm|openai|anthropic|VertexAI|Vertex_ai|vertex\.ai|google\.cloud|GitHub Models|models\.github\.ai|github_models)' # Detect whether the strix log contains evidence of infrastructure-level # errors (timeout, rate-limit, transport failures) that indicate the scan @@ -2896,10 +2900,6 @@ run_current_target_scan() { fallback_tried=0 for candidate_raw in "${FALLBACK_MODELS[@]}"; do candidate="$(normalize_model "$candidate_raw")" - if is_github_models_model "$candidate"; then - echo "ERROR: Strix fallback models must not use GitHub Models model prefixes; use direct OpenAI Platform model names." >&2 - return 2 - fi if [ -z "$candidate" ] || [ "$candidate" = "$PRIMARY_MODEL" ]; then if [ -n "$candidate" ]; then echo "Skipping fallback model '$candidate' — same as primary model." >&2 diff --git a/scripts/ci/test_strix_quick_gate.sh b/scripts/ci/test_strix_quick_gate.sh index ff25e1899..e99812b6d 100644 --- a/scripts/ci/test_strix_quick_gate.sh +++ b/scripts/ci/test_strix_quick_gate.sh @@ -63,7 +63,7 @@ assert_strix_workflow_pr_trigger_hardened() { assert_file_contains "$workflow_file" "branches: [master]" "strix workflow scans the protected default branch" assert_file_contains "$workflow_file" "pull_request_target:" "strix workflow uses trusted PR trigger" - assert_file_not_contains "$workflow_file" "models: read" "strix workflow must not grant GitHub Models read permission" + assert_file_contains "$workflow_file" "models: read" "strix workflow grants only the GitHub Models read permission needed for Strix" assert_file_contains "$workflow_file" "Materialize trusted workspace" "strix workflow materializes trusted workspace" assert_file_contains "$workflow_file" "TRUSTED_WORKSPACE_SHA" "strix workflow pins trusted workspace SHA" assert_file_contains "$workflow_file" "TRUSTED_WORKSPACE=\$trusted_workspace" "strix workflow exports a trusted workspace path" @@ -78,6 +78,7 @@ assert_strix_workflow_pr_trigger_hardened() { assert_file_not_contains "$workflow_file" "run: bash ./scripts/ci/strix_quick_gate.sh" "strix workflow avoids direct repo gate execution on privileged trigger" assert_file_contains "$workflow_file" "Fetch pull request head for trusted scan" "strix workflow fetches PR head without checkout" assert_file_contains "$workflow_file" "pr_number:" "strix workflow accepts manual PR-scope evidence inputs" + assert_file_contains "$workflow_file" "strix_llm:" "strix workflow accepts only manual Strix model overrides" assert_file_contains "$workflow_file" "github.event.inputs.pr_number" "strix workflow can run PR-scoped workflow_dispatch evidence" assert_file_contains "$workflow_file" "PR number and head SHA are required for trusted PR-scope Strix evidence" "strix workflow fails closed when manual PR-scope metadata is incomplete" assert_file_contains "$workflow_file" '[[ "$PR_HEAD_SHA" =~ ^[0-9a-fA-F]{40}$ ]]' "strix workflow validates PR head SHA before trusted fetch" @@ -106,8 +107,9 @@ assert_strix_workflow_pr_trigger_hardened() { assert_file_not_contains "$workflow_file" "STRIX_TOTAL_TIMEOUT_SECONDS:" "strix workflow must not expose total timeout env names in GitHub logs" assert_file_not_contains "$workflow_file" "STRIX_PR_SCOPE_MAX_FILES_PER_BATCH" "strix workflow must not split Strix PR evidence into separate scanner runs" assert_file_not_contains "$workflow_file" "secrets.STRIX_LLM == 'vertex_ai/gemini-3.1-pro-preview-customtools' && 'vertex_ai/gemini-2.5-flash'" "strix workflow must not quarantine the approved Vertex preview model after organization secret visibility is fixed" - assert_file_contains "$workflow_file" "secrets.STRIX_LLM || 'vertex_ai/gemini-3.1-pro-preview-customtools'" "strix workflow defaults missing STRIX_LLM to the approved organization Vertex model" - assert_file_contains "$workflow_file" "STRIX_LLM must select direct OpenAI GPT-5.4 or newer, or an approved organization Vertex AI model" "strix workflow rejects unsupported model inputs" + assert_file_contains "$workflow_file" "github.event.inputs.strix_llm || 'openai/openai/gpt-4.1'" "strix workflow defaults PR Strix scans to GitHub Models" + assert_file_not_contains "$workflow_file" "secrets.STRIX_LLM ||" "strix workflow must not let the legacy STRIX_LLM secret override PR defaults" + assert_file_contains "$workflow_file" "STRIX_LLM must select GitHub Models openai/openai/*, direct OpenAI GPT-5.4 or newer, or an approved organization Vertex AI model" "strix workflow rejects unsupported model inputs" assert_file_contains "$workflow_file" "vertex_ai/gemini-3.1-pro-preview-customtools | vertex_ai/gemini-2.5-flash)" "strix workflow accepts only exact approved organization Vertex AI models" assert_file_contains "$workflow_file" 'STRIX_VERTEX_FALLBACK_MODELS: ""' "strix workflow disables silent Vertex fallbacks so timeout-class failures fail closed" assert_file_contains "$workflow_file" 'STRIX_FAIL_ON_PROVIDER_SIGNAL: "1"' "strix workflow fails closed on timeout, fatal, warning, denied, or provider failure signals" @@ -124,24 +126,26 @@ assert_strix_workflow_pr_trigger_hardened() { assert_file_not_contains "$workflow_file" "ignore::UserWarning" "strix workflow must not blanket-suppress all UserWarning output" assert_file_not_contains "$workflow_file" "vertex_ai/* | vertex_ai_beta/*" "strix workflow must not accept arbitrary Vertex models" assert_file_contains "$workflow_file" "provider_mode=openai_direct" "strix workflow requires direct OpenAI GPT-5 credentials" - assert_file_contains "$workflow_file" 'LLM_API_KEY_SECRET: ${{ steps.gate.outputs.provider_mode == '"'"'openai_direct'"'"' && secrets.STRIX_OPENAI_API_KEY || '"'"''"'"' }}' "strix workflow uses provider-scoped LLM key material" - assert_file_contains "$workflow_file" 'LLM_API_KEY: ${{ steps.gate.outputs.provider_mode == '"'"'openai_direct'"'"' && secrets.STRIX_OPENAI_API_KEY || '"'"''"'"' }}' "strix workflow masks provider-scoped LLM key material" + assert_file_contains "$workflow_file" "provider_mode=github_models" "strix workflow supports GitHub Models provider mode" + assert_file_contains "$workflow_file" 'LLM_API_KEY_SECRET: ${{ steps.gate.outputs.provider_mode == '"'"'github_models'"'"' && github.token || steps.gate.outputs.provider_mode == '"'"'openai_direct'"'"' && secrets.STRIX_OPENAI_API_KEY || '"'"''"'"' }}' "strix workflow uses provider-scoped LLM key material" + assert_file_contains "$workflow_file" 'LLM_API_KEY: ${{ steps.gate.outputs.provider_mode == '"'"'github_models'"'"' && github.token || steps.gate.outputs.provider_mode == '"'"'openai_direct'"'"' && secrets.STRIX_OPENAI_API_KEY || '"'"''"'"' }}' "strix workflow masks provider-scoped LLM key material" assert_file_not_contains "$workflow_file" "secrets.LLM_API_KEY" "strix workflow must not expose generic LLM_API_KEY for Vertex scans" + assert_file_contains "$workflow_file" "github.token is required for GitHub Models Strix scans" "strix workflow fails closed when GitHub Models credentials are absent" assert_file_contains "$workflow_file" "STRIX_OPENAI_API_KEY is required for Strix OpenAI Platform scans" "strix workflow fails closed when direct credentials are absent" assert_file_contains "$workflow_file" 'PROVIDER_MODE: ${{ steps.gate.outputs.provider_mode }}' "strix workflow passes provider mode through env" assert_file_not_contains "$workflow_file" '[ "${{ steps.gate.outputs.provider_mode }}" = "openai_direct" ]' "strix workflow does not interpolate provider mode inside shell condition" assert_file_contains "$workflow_file" 'trimmed_openai_key="$(printf '"'"'%s'"'"' "$sanitized_openai_key" | sed '"'"'s/^[[:space:]]*//;s/[[:space:]]*$//'"'"')"' "strix workflow trims whitespace-only OpenAI keys before gate validation" assert_file_contains "$workflow_file" 'trimmed="$(printf '"'"'%s'"'"' "$sanitized" | sed '"'"'s/^[[:space:]]*//;s/[[:space:]]*$//'"'"')"' "strix workflow trims whitespace-only OpenAI keys before input file creation" assert_file_contains "$workflow_file" 'STRIX_LLM_DEFAULT_PROVIDER: ${{ steps.gate.outputs.provider_mode == '"'"'vertex_ai'"'"' && '"'"'vertex_ai'"'"' || '"'"'openai'"'"' }}' "strix workflow selects the correct default provider" - assert_file_not_contains "$workflow_file" "provider_mode=github_models" "strix workflow must not fall back to GitHub Models" - assert_file_not_contains "$workflow_file" "steps.gate.outputs.provider_mode == 'github_models'" "strix workflow must not prepare GitHub Models API base" - assert_file_not_contains "$workflow_file" "https://models.github.ai/inference" "strix workflow must not route Strix through GitHub Models inference" - assert_file_not_contains "$workflow_file" '${{ secrets.STRIX_OPENAI_API_KEY || github.token }}' "strix workflow must not use github.token as an LLM API key" + assert_file_contains "$workflow_file" "Prepare GitHub Models API base" "strix workflow prepares the GitHub Models API base only for GitHub Models mode" + assert_file_contains "$workflow_file" "https://models.github.ai/inference" "strix workflow routes GitHub Models scans to the inference endpoint" + assert_file_contains "$workflow_file" "LLM_API_BASE_FILE" "strix workflow passes the GitHub Models API base through a trusted input file" + assert_file_not_contains "$workflow_file" '${{ secrets.STRIX_OPENAI_API_KEY || github.token }}' "strix workflow must not use fallback-secret syntax for LLM API keys" assert_file_not_contains "$workflow_file" "openai/gpt-5 |" "strix workflow must not accept plain GPT-5 when GPT-5.4 is required" assert_file_not_contains "$workflow_file" "openai/gpt-5-*" "strix workflow must not accept older GPT-5 variants when GPT-5.4 is required" - assert_file_not_contains "$workflow_file" "openai/openai/gpt-5" "strix workflow must not accept GitHub Models OpenAI model prefixes" - assert_file_not_contains "$workflow_file" "github/gpt-4o" "strix workflow must not default to GPT-4o when GPT-5 is required" - assert_file_not_contains "$workflow_file" "gemini/gemini-pro-3.1-preview" "strix workflow must not default to GitHub Models or Gemini API when Vertex AI is required" + assert_file_contains "$workflow_file" "openai/openai/*" "strix workflow accepts GitHub Models OpenAI model prefixes" + assert_file_not_contains "$workflow_file" "github/gpt-4o" "strix workflow must not default to an unsupported GitHub Models alias" + assert_file_not_contains "$workflow_file" "gemini/gemini-pro-3.1-preview" "strix workflow must not default to Gemini API when GitHub Models is required" assert_file_not_contains "$workflow_file" "if-no-files-found: warn" "strix workflow must not downgrade missing security artifacts to warnings" if grep -Eq '^[[:space:]]+pull_request:[[:space:]]*$' "$workflow_file"; then record_failure "strix workflow must not expose secrets on pull_request events" @@ -152,6 +156,7 @@ assert_strix_workflow_pr_trigger_hardened() { assert_strix_gpt54_model_guard_semantics() { local model="$1" case "$model" in + openai/openai/* | \ gpt-5.[4-9]* | gpt-5.[1-9][0-9]* | gpt-[6-9]* | gpt-[1-9][0-9]* | \ openai/gpt-5.[4-9]* | openai/gpt-5.[1-9][0-9]* | openai/gpt-[6-9]* | openai/gpt-[1-9][0-9]* | \ vertex_ai/gemini-3.1-pro-preview-customtools | vertex_ai/gemini-2.5-flash) @@ -176,8 +181,11 @@ assert_strix_gpt54_model_guard_cases() { if ! assert_strix_gpt54_model_guard_semantics "openai/gpt-5.4"; then record_failure "strix GPT-5.4 guard must accept openai/gpt-5.4" fi - if assert_strix_gpt54_model_guard_semantics "openai/openai/gpt-5.4"; then - record_failure "strix GPT-5.4 guard must reject GitHub Models openai/openai/gpt-5.4" + if ! assert_strix_gpt54_model_guard_semantics "openai/openai/gpt-5"; then + record_failure "strix guard must accept GitHub Models openai/openai/gpt-5" + fi + if ! assert_strix_gpt54_model_guard_semantics "openai/openai/gpt-5.4"; then + record_failure "strix guard must accept GitHub Models openai/openai/gpt-5.4" fi if ! assert_strix_gpt54_model_guard_semantics "vertex_ai/gemini-3.1-pro-preview-customtools"; then record_failure "strix guard must accept the organization-approved Vertex preview model" @@ -375,7 +383,7 @@ case "${FAKE_STRIX_SCENARIO:?}" in echo "scan ok with timeout disabled" exit 0 ;; - vertex-primary-notfound-fallback-success|github-models-fallback-model-prefix-rejected) + vertex-primary-notfound-fallback-success|github-models-fallback-success|github-models-fallback-requires-api-base|github-models-model-prefix-with-api-base-succeeds) case "${STRIX_LLM:-}" in vertex_ai/missing-primary) echo "Error: litellm.NotFoundError: Vertex_aiException - x" @@ -386,6 +394,10 @@ case "${FAKE_STRIX_SCENARIO:?}" in echo "scan ok with fallback" exit 0 ;; + openai/openai/gpt-5.4) + echo "scan ok with GitHub Models fallback" + exit 0 + ;; *) echo "unexpected model ${STRIX_LLM:-}" >&2 exit 9 @@ -6770,32 +6782,79 @@ assert_vertex_path "space-in-project" "projects/my proj/locations/us/models/foo" assert_vertex_path "tab-in-model-id" $'models/gemini\t2.5' 1 assert_vertex_path "space-in-model-id" "models/my model" 1 -run_gate_case "github-models-model-prefix-rejected" \ +run_gate_case "github-models-model-prefix-requires-api-base" \ "openai/openai/gpt-5.4" \ "" \ "2" \ - "STRIX_LLM must not use GitHub Models model prefixes" \ - "0" + "GitHub Models Strix scans require LLM_API_BASE_FILE" \ + "0" \ + "" \ + "" \ + "openai" \ + "" -run_gate_case "github-models-api-base-rejected" \ +run_gate_case "github-models-api-base-rejected-for-direct-openai" \ "openai/gpt-5.4" \ "" \ "2" \ - "LLM_API_BASE must not route Strix through GitHub Models" \ + "LLM_API_BASE may route through GitHub Models only when STRIX_LLM uses a GitHub Models model prefix" \ "0" \ "" \ "" \ "openai" \ "https://models.github.ai/inference" -run_gate_case "github-models-fallback-model-prefix-rejected" \ +run_gate_case "github-models-model-prefix-with-api-base-succeeds" \ + "openai/openai/gpt-5.4" \ + "" \ + "0" \ + "scan ok" \ + "1" \ + "openai/openai/gpt-5.4" \ + "https://models.github.ai/inference" \ + "openai" \ + "https://models.github.ai/inference" + +run_gate_case "github-models-fallback-requires-api-base" \ "vertex_ai/missing-primary" \ "openai/openai/gpt-5.4" \ "2" \ - "Strix fallback models must not use GitHub Models model prefixes" \ + "GitHub Models Strix scans require LLM_API_BASE_FILE" \ "1" \ "vertex_ai/missing-primary" \ - "" + "" \ + "vertex_ai" \ + "" + +run_gate_case "github-models-fallback-success" \ + "vertex_ai/missing-primary" \ + "openai/openai/gpt-5.4" \ + "0" \ + "Strix quick scan succeeded with fallback model 'openai/openai/gpt-5.4'." \ + "2" \ + "vertex_ai/missing-primary|openai/openai/gpt-5.4" \ + "|https://models.github.ai/inference" \ + "vertex_ai" \ + "https://models.github.ai/inference" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ + 0 # Endpoint only exists in excluded directories (.git/, node_modules/). # The grep --exclude-dir patterns must prevent matching, so the finding