diff --git a/.agents/skills/manage-ci/references/current-inventory.md b/.agents/skills/manage-ci/references/current-inventory.md index 6a4ebdadd0..91e2649c33 100644 --- a/.agents/skills/manage-ci/references/current-inventory.md +++ b/.agents/skills/manage-ci/references/current-inventory.md @@ -105,10 +105,10 @@ from that same catalog. - `prepare-static-abi-input`: portable static ABI archive. - `compose-product-input`: exact host/runtime verification and composition. - `restore-smoke-inputs`: product/model extraction for consumers. -- `select-ci-runners`: provider labels, Depot cache permission, and the - provider-derived `allow_native_github_cache` output. Depot-selected direct - PRs set it to false; hosted PR and trusted main/release/manual selections - retain native GitHub cache behavior. +- `select-ci-runners`: provider labels, cache permissions, and the + provider-derived `allow_native_github_cache` / `allow_depot_remote_cache` + outputs. Every Depot selection sets both outputs to false; hosted PR, + release, and cache-warmer selections retain native GitHub cache behavior. - `configure-sccache-gha`: event/provider-derived compiler-cache setup. - `capture-sccache-stats`: machine-readable cache evidence. @@ -124,7 +124,9 @@ under `ci/` or this inventory. Artifacts are correctness boundaries; caches only accelerate regeneration. PR artifacts generally retain for one day. Protected same-repository and fork lanes cannot publish shared trusted-main caches, and Depot cache access is -denied. Large Cargo target caches restore trusted-main entries but remain +denied. The Depot namespace is intentionally unused by trusted workflows; +purge/expiry is required before PR activation, and an inert proxy is not +authority-isolation proof. Large Cargo target caches restore trusted-main entries but remain restore-only on PRs. Exact Linux static ABI, Swift ABI, macOS Metal unit ABI, and Windows native ABI caches may publish into GitHub's isolated PR merge-ref scope for same-PR reruns. The Website slice is the sole publisher for the @@ -170,10 +172,10 @@ Relevant repository variable names include `DEPOT_RUNNERS_ENABLED`, `DEPOT_PR_CANARY_REF` (absent by default; one exact `refs/pull//merge` ref only). The latter is a bounded selector canary, not a cache-isolation proof or a replacement for the global PR gate. -The eligible five-lane Depot-PR graph now disables every native GitHub cache +The eligible five-lane Depot graph now disables every native GitHub cache consumer (explicit cache actions, setup-* package caches, rust-cache, static / -Metal / Windows / Swift ABI caches and Windows SDK cache toggles) when that -output is false; cache misses rebuild normally. This checked-in mode does not +Metal / Windows / Swift ABI caches and Windows SDK cache toggles) and Depot +remote cache when those outputs are false; cache misses rebuild normally. This checked-in mode does not prove the absence of ambient Depot/WebDAV authority, so the runtime sentinel and no-secret/no-token canaries remain required. Other variables include `CUDA_VERSION`, `VULKAN_SDK_VERSION`, smoke configuration variables, and release/deployment diff --git a/.github/actions/audit-depot-pr-isolation/action.yml b/.github/actions/audit-depot-pr-isolation/action.yml index 1ed56e1b60..bec76e8ba0 100644 --- a/.github/actions/audit-depot-pr-isolation/action.yml +++ b/.github/actions/audit-depot-pr-isolation/action.yml @@ -9,6 +9,12 @@ inputs: depot_selected: description: Whether the centralized runner policy selected a Depot executor. required: true + allow_native_github_cache: + description: Central cache policy output for native GitHub Actions cache APIs. + required: true + allow_depot_remote_cache: + description: Central cache policy output for Depot's remote cache. + required: true runs: using: composite @@ -18,20 +24,45 @@ runs: env: INPUT_ORIGINAL_EVENT_NAME: ${{ inputs.original_event_name }} INPUT_DEPOT_SELECTED: ${{ inputs.depot_selected }} + INPUT_ALLOW_NATIVE_GITHUB_CACHE: ${{ inputs.allow_native_github_cache }} + INPUT_ALLOW_DEPOT_REMOTE_CACHE: ${{ inputs.allow_depot_remote_cache }} run: | set -euo pipefail original_event="${INPUT_ORIGINAL_EVENT_NAME:-${GITHUB_EVENT_NAME:-}}" - if [[ "$original_event" != "pull_request" && - "$original_event" != "pull_request_target" ]]; then - exit 0 - fi - depot_selected="${INPUT_DEPOT_SELECTED:-}" if [[ "$depot_selected" != "true" && "$depot_selected" != "false" ]]; then - echo "depot_selected must be true or false, got: $depot_selected" >&2 + echo "depot_selected must be true or false (depot_selected)" >&2 + exit 1 + fi + allow_native_github_cache="${INPUT_ALLOW_NATIVE_GITHUB_CACHE:-}" + if [[ "$allow_native_github_cache" != "true" && + "$allow_native_github_cache" != "false" ]]; then + echo "allow_native_github_cache must be true or false (allow_native_github_cache)" >&2 + exit 1 + fi + allow_depot_remote_cache="${INPUT_ALLOW_DEPOT_REMOTE_CACHE:-}" + if [[ "$allow_depot_remote_cache" != "true" && + "$allow_depot_remote_cache" != "false" ]]; then + echo "allow_depot_remote_cache must be true or false (allow_depot_remote_cache)" >&2 exit 1 fi + if [[ "$depot_selected" == "true" && + "$allow_native_github_cache" != "false" ]]; then + echo "Depot selection requires native GitHub cache disabled (allow_native_github_cache)" >&2 + exit 1 + fi + if [[ "$depot_selected" == "true" && + "$allow_depot_remote_cache" != "false" ]]; then + echo "Depot selection requires remote cache disabled (allow_depot_remote_cache)" >&2 + exit 1 + fi + + if [[ "$original_event" != "pull_request" && + "$original_event" != "pull_request_target" ]]; then + exit 0 + fi + forbidden_names=( DEPOT_CACHE_TOKEN DEPOT_TOKEN @@ -45,50 +76,91 @@ runs: SCCACHE_WEBDAV_TOKEN SCCACHE_WEBDAV_USERNAME SCCACHE_WEBDAV_PASSWORD + SCCACHE_BUCKET + SCCACHE_ENDPOINT TURBO_TOKEN TURBO_API TURBO_TEAM GOCACHEPROG + REGISTRY_TOKEN + REGISTRY_USERNAME + REGISTRY_PASSWORD + REGISTRY_AUTH_TOKEN + NPM_TOKEN + NODE_AUTH_TOKEN + CARGO_REGISTRIES_CRATES_IO_TOKEN ) for name in "${forbidden_names[@]}"; do if [[ -n "${!name:-}" ]]; then - echo "PR runner received forbidden credential/cache authority: $name" >&2 + echo "PR runner received forbidden credential/cache authority ($name)" >&2 exit 1 fi done - for endpoint_name in ACTIONS_CACHE_URL ACTIONS_RESULTS_URL; do + endpoint_host() { + local endpoint="$1" + local authority="${endpoint#*://}" + authority="${authority%%[/?#]*}" + printf '%s' "$authority" + } + + is_github_endpoint() { + local endpoint="$1" + local endpoint_lower + endpoint_lower="$(printf '%s' "$endpoint" | tr '[:upper:]' '[:lower:]')" + local authority + authority="$(endpoint_host "$endpoint_lower")" + [[ "$endpoint_lower" == https://* ]] || return 1 + [[ "$authority" != *"@"* ]] || return 1 + [[ "$authority" =~ ^([a-z0-9-]+\.)*actions\.githubusercontent\.com(:[0-9]{1,5})?$ ]] + } + + is_loopback_endpoint() { + local endpoint="$1" + local endpoint_lower + endpoint_lower="$(printf '%s' "$endpoint" | tr '[:upper:]' '[:lower:]')" + # Loopback proxies require a numeric TCP port and an explicit path. + if [[ ! "$endpoint_lower" =~ ^https?://(localhost|127\.0\.0\.1|\[::1\]):([0-9]{1,5})/[^[:space:]]*$ ]]; then + return 1 + fi + local port="${BASH_REMATCH[2]}" + (( port >= 1 && port <= 65535 )) + } + + for endpoint_name in ACTIONS_CACHE_URL ACTIONS_RESULTS_URL ACTIONS_RUNTIME_URL; do endpoint="${!endpoint_name:-}" if [[ -z "$endpoint" ]]; then continue fi endpoint_lower="$(printf '%s' "$endpoint" | tr '[:upper:]' '[:lower:]')" if [[ "$endpoint_lower" == *depot.dev* ]]; then - echo "PR runner received a Depot Actions endpoint: $endpoint_name" >&2 + echo "PR runner received a Depot Actions endpoint ($endpoint_name)" >&2 exit 1 fi - if [[ "$endpoint_lower" =~ ^https?://[^/]*@ ]]; then - echo "PR runner received an Actions endpoint with URL userinfo: $endpoint_name" >&2 + authority="$(endpoint_host "$endpoint_lower")" + if [[ "$authority" == *"@"* ]]; then + echo "PR runner received an Actions endpoint with URL userinfo ($endpoint_name)" >&2 exit 1 fi if [[ "$depot_selected" != "true" ]]; then continue fi - if [[ ! "$endpoint_lower" =~ ^https://([a-z0-9-]+\.)*actions\.githubusercontent\.com(:[0-9]+)?([/?#]|$) ]]; then - echo "PR runner received a non-GitHub Actions endpoint: $endpoint_name" >&2 + if ! is_github_endpoint "$endpoint" && + ! is_loopback_endpoint "$endpoint"; then + echo "PR runner received a non-GitHub/non-loopback Actions endpoint ($endpoint_name)" >&2 exit 1 fi done docker_auth_config="${DOCKER_AUTH_CONFIG:-}" - if [[ -n "$docker_auth_config" ]] && - printf '%s' "$docker_auth_config" | grep -Eiq 'depot\.dev'; then - echo "PR runner has Depot registry authentication configured" >&2 + if [[ -n "$docker_auth_config" ]]; then + echo "PR runner has Docker registry authentication configured (DOCKER_AUTH_CONFIG)" >&2 exit 1 fi docker_config="${DOCKER_CONFIG:-${HOME:-}/.docker}/config.json" - if [[ -f "$docker_config" ]] && grep -Eiq 'depot\.dev' "$docker_config"; then - echo "PR runner has Depot registry authentication configured" >&2 + if [[ -f "$docker_config" ]] && + grep -Eiq '"(auths|credHelpers|credsStore)"[[:space:]]*:' "$docker_config"; then + echo "PR runner has Docker registry authentication configured (config.json)" >&2 exit 1 fi diff --git a/.github/actions/configure-sccache-gha/action.yml b/.github/actions/configure-sccache-gha/action.yml index 170dcaf8f0..edab3cfb7d 100644 --- a/.github/actions/configure-sccache-gha/action.yml +++ b/.github/actions/configure-sccache-gha/action.yml @@ -6,6 +6,10 @@ inputs: description: Allow this trusted job to read and write Depot's repository-scoped WebDAV cache. required: false default: "false" + allow_native_github_cache: + description: Allow this job to use GitHub Actions cache as an sccache backend. + required: false + default: "false" runs: using: composite @@ -14,6 +18,7 @@ runs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 env: INPUT_ALLOW_DEPOT_REMOTE_CACHE: ${{ inputs.allow_depot_remote_cache }} + INPUT_ALLOW_NATIVE_GITHUB_CACHE: ${{ inputs.allow_native_github_cache }} DISPATCH_ORIGINAL_EVENT_NAME: ${{ github.event.inputs.original_event_name || '' }} with: script: | @@ -28,6 +33,17 @@ runs: ); return; } + const allowNativeGithubCache = + (process.env.INPUT_ALLOW_NATIVE_GITHUB_CACHE || '').toLowerCase(); + if ( + allowNativeGithubCache !== 'true' && + allowNativeGithubCache !== 'false' + ) { + core.setFailed( + 'allow_native_github_cache must be the string true or false.', + ); + return; + } const eventName = process.env.GITHUB_EVENT_NAME || ''; const effectiveEventName = @@ -148,11 +164,14 @@ runs: } if ( - allowDepotRemoteCache === 'false' && - (webdavEndpoint || webdavToken) + allowNativeGithubCache === 'false' || + (allowDepotRemoteCache === 'false' && + (webdavEndpoint || webdavToken)) ) { core.info( - 'Depot cache is present but disabled for this trust context; using job-local disk only.', + allowNativeGithubCache === 'false' + ? 'Native GitHub and Depot cache disabled for this trust context; using job-local disk only.' + : 'Depot cache is present but disabled for this trust context; using job-local disk only.', ); core.exportVariable('SCCACHE_WEBDAV_ENDPOINT', ''); core.exportVariable('SCCACHE_WEBDAV_TOKEN', ''); diff --git a/.github/actions/select-ci-runners/action.yml b/.github/actions/select-ci-runners/action.yml index 8a4cf7c14a..f2c5249352 100644 --- a/.github/actions/select-ci-runners/action.yml +++ b/.github/actions/select-ci-runners/action.yml @@ -187,7 +187,6 @@ runs: "$INPUT_REF" == "refs/heads/main" && \ "$INPUT_DEPOT_MAIN_ENABLED" == "true" ]]; then depot_enabled=true - allow_depot_remote_cache=true fi ;; *) @@ -195,24 +194,13 @@ runs: ;; esac - # Depot's repository-scoped cache is never authorized by a PR gate. - # Trusted main push/dispatch paths are the only paths that may retain - # the existing remote-cache behavior. - if [[ "$depot_enabled" == "true" && \ - "$is_direct_pull_request" != "true" && \ - "$is_dispatched_pull_request" != "true" && \ - "$INPUT_EVENT_NAME" == "workflow_dispatch" ]]; then - allow_depot_remote_cache=true - fi - - # Depot runners do not provide GitHub's branch-isolated cache - # authority. Native GitHub cache APIs are therefore disabled for a - # directly selected PR, while hosted PRs and trusted main/release or - # manual paths retain their existing cache behavior. This value is - # derived only from the protected provider policy; callers cannot opt - # a Depot PR back in by supplying a cache-related input. - if [[ "$depot_enabled" == "true" && \ - "$is_direct_pull_request" == "true" ]]; then + # Depot's Actions cache namespace is intentionally inert for every + # Depot selection. Native GitHub cache APIs and Depot's remote cache + # are both disabled; hosted selections retain native GitHub cache + # behavior. These values are derived only from provider policy, so a + # caller cannot opt a Depot build back into either cache authority. + if [[ "$depot_enabled" == "true" ]]; then + allow_depot_remote_cache=false allow_native_github_cache=false fi diff --git a/.github/workflows/ci-linux-host-slice.yml b/.github/workflows/ci-linux-host-slice.yml index 9de40a47d7..884f58edd2 100644 --- a/.github/workflows/ci-linux-host-slice.yml +++ b/.github/workflows/ci-linux-host-slice.yml @@ -106,10 +106,12 @@ jobs: RUSTC_WRAPPER: sccache RUSTFLAGS: "-C link-arg=-fuse-ld=lld" steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner_8, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} @@ -119,6 +121,7 @@ jobs: - uses: ./.github/actions/configure-sccache-gha with: allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} - if: ${{ needs.runner_policy.outputs.allow_native_github_cache == 'true' }} uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 snapshot 2026-03-12 continue-on-error: true diff --git a/.github/workflows/ci-linux-product-slice.yml b/.github/workflows/ci-linux-product-slice.yml index e64c2e3807..50b172b5a9 100644 --- a/.github/workflows/ci-linux-product-slice.yml +++ b/.github/workflows/ci-linux-product-slice.yml @@ -45,6 +45,7 @@ jobs: contents: read outputs: runner: ${{ steps.policy.outputs.runner }} + allow_depot_remote_cache: ${{ steps.policy.outputs.allow_depot_remote_cache }} allow_native_github_cache: ${{ steps.policy.outputs.allow_native_github_cache }} steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 @@ -83,10 +84,12 @@ jobs: run: shell: bash steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} diff --git a/.github/workflows/ci-linux-runtime-slice.yml b/.github/workflows/ci-linux-runtime-slice.yml index ad43dd454d..fefa7e994d 100644 --- a/.github/workflows/ci-linux-runtime-slice.yml +++ b/.github/workflows/ci-linux-runtime-slice.yml @@ -104,10 +104,12 @@ jobs: LLAMA_STAGE_SKIP_NCCL: "1" RUSTC_WRAPPER: sccache steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner_16, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} @@ -126,6 +128,7 @@ jobs: - uses: ./.github/actions/configure-sccache-gha with: allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} - if: ${{ needs.runner_policy.outputs.allow_native_github_cache == 'true' }} uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 snapshot 2026-03-12 continue-on-error: true diff --git a/.github/workflows/ci-macos-host-slice.yml b/.github/workflows/ci-macos-host-slice.yml index 3887600350..1b6289f20a 100644 --- a/.github/workflows/ci-macos-host-slice.yml +++ b/.github/workflows/ci-macos-host-slice.yml @@ -58,6 +58,7 @@ jobs: contents: read outputs: runner_macos: ${{ steps.policy.outputs.runner_macos }} + allow_depot_remote_cache: ${{ steps.policy.outputs.allow_depot_remote_cache }} allow_native_github_cache: ${{ steps.policy.outputs.allow_native_github_cache }} steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 @@ -90,10 +91,12 @@ jobs: matrix: host: ${{ fromJson(inputs.hosts_matrix) }} steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner_macos, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} diff --git a/.github/workflows/ci-macos-product-slice.yml b/.github/workflows/ci-macos-product-slice.yml index 3f9b94f70b..50beb09893 100644 --- a/.github/workflows/ci-macos-product-slice.yml +++ b/.github/workflows/ci-macos-product-slice.yml @@ -44,6 +44,7 @@ jobs: contents: read outputs: runner_macos: ${{ steps.policy.outputs.runner_macos }} + allow_depot_remote_cache: ${{ steps.policy.outputs.allow_depot_remote_cache }} allow_native_github_cache: ${{ steps.policy.outputs.allow_native_github_cache }} steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 @@ -76,10 +77,12 @@ jobs: matrix: runtime: ${{ fromJson(inputs.runtime_matrix) }} steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner_macos, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} diff --git a/.github/workflows/ci-macos-runtime-slice.yml b/.github/workflows/ci-macos-runtime-slice.yml index e4946bfb81..f8a87ecc69 100644 --- a/.github/workflows/ci-macos-runtime-slice.yml +++ b/.github/workflows/ci-macos-runtime-slice.yml @@ -49,6 +49,7 @@ jobs: contents: read outputs: runner_macos: ${{ steps.policy.outputs.runner_macos }} + allow_depot_remote_cache: ${{ steps.policy.outputs.allow_depot_remote_cache }} allow_native_github_cache: ${{ steps.policy.outputs.allow_native_github_cache }} steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 @@ -84,10 +85,12 @@ jobs: LLAMA_STAGE_BACKEND: ${{ matrix.runtime.backend }} LLAMA_STAGE_BUILD_DIR: ${{ matrix.runtime.build_dir }} steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner_macos, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} diff --git a/.github/workflows/ci-platform-checks-slice.yml b/.github/workflows/ci-platform-checks-slice.yml index dd99d954a5..6643a14cb4 100644 --- a/.github/workflows/ci-platform-checks-slice.yml +++ b/.github/workflows/ci-platform-checks-slice.yml @@ -56,6 +56,7 @@ jobs: runner_macos: ${{ steps.policy.outputs.runner_macos }} runner_windows: ${{ steps.policy.outputs.runner_windows }} runner_by_platform: ${{ steps.platform_runners.outputs.runner_by_platform }} + allow_depot_remote_cache: ${{ steps.policy.outputs.allow_depot_remote_cache }} allow_native_github_cache: ${{ steps.policy.outputs.allow_native_github_cache }} steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 @@ -97,10 +98,12 @@ jobs: matrix: check: ${{ fromJson(inputs.platform_checks_matrix) }} steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(fromJSON(needs.runner_policy.outputs.runner_by_platform)[matrix.check.platform], 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} diff --git a/.github/workflows/ci-quality-slice.yml b/.github/workflows/ci-quality-slice.yml index ed1e1ff452..31a1a9ba5f 100644 --- a/.github/workflows/ci-quality-slice.yml +++ b/.github/workflows/ci-quality-slice.yml @@ -92,10 +92,12 @@ jobs: runs-on: ${{ needs.runner_policy.outputs.runner_4 }} timeout-minutes: 20 steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner_4, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} @@ -127,10 +129,12 @@ jobs: runs-on: ${{ needs.runner_policy.outputs.runner_4 }} timeout-minutes: 15 steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner_4, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} @@ -161,10 +165,12 @@ jobs: RUSTFLAGS: "-C link-arg=-fuse-ld=lld" RUSTC_WRAPPER: sccache steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner_8, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} @@ -174,6 +180,7 @@ jobs: - uses: ./.github/actions/configure-sccache-gha with: allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} - if: ${{ needs.runner_policy.outputs.allow_native_github_cache == 'true' }} uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 snapshot 2026-03-12 continue-on-error: true @@ -212,10 +219,12 @@ jobs: runs-on: ${{ needs.runner_policy.outputs.runner_4 }} timeout-minutes: 5 steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner_4, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} diff --git a/.github/workflows/ci-rust-tests-slice.yml b/.github/workflows/ci-rust-tests-slice.yml index 2e86599f96..e055546022 100644 --- a/.github/workflows/ci-rust-tests-slice.yml +++ b/.github/workflows/ci-rust-tests-slice.yml @@ -59,6 +59,7 @@ jobs: contents: read outputs: runner: ${{ steps.policy.outputs.runner }} + allow_depot_remote_cache: ${{ steps.policy.outputs.allow_depot_remote_cache }} allow_native_github_cache: ${{ steps.policy.outputs.allow_native_github_cache }} steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 @@ -104,10 +105,12 @@ jobs: RUSTFLAGS: "-C link-arg=-fuse-ld=lld" RUSTC_WRAPPER: sccache steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} @@ -120,7 +123,8 @@ jobs: pinned_epoch: ${{ inputs.static_abi_toolchain_epoch }} - uses: ./.github/actions/configure-sccache-gha with: - allow_depot_remote_cache: "false" + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} - if: ${{ needs.runner_policy.outputs.allow_native_github_cache == 'true' }} uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 snapshot 2026-03-12 continue-on-error: true diff --git a/.github/workflows/ci-ui-artifact-slice.yml b/.github/workflows/ci-ui-artifact-slice.yml index dfe8ad48f7..c8bf1d955c 100644 --- a/.github/workflows/ci-ui-artifact-slice.yml +++ b/.github/workflows/ci-ui-artifact-slice.yml @@ -42,6 +42,7 @@ jobs: contents: read outputs: runner_4: ${{ steps.policy.outputs.runner_4 }} + allow_depot_remote_cache: ${{ steps.policy.outputs.allow_depot_remote_cache }} allow_native_github_cache: ${{ steps.policy.outputs.allow_native_github_cache }} steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 @@ -73,10 +74,12 @@ jobs: run: working-directory: crates/mesh-llm-ui steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner_4, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} diff --git a/.github/workflows/ci-web-slice.yml b/.github/workflows/ci-web-slice.yml index 780dc40d95..73fc5aa273 100644 --- a/.github/workflows/ci-web-slice.yml +++ b/.github/workflows/ci-web-slice.yml @@ -41,6 +41,7 @@ jobs: contents: read outputs: runner_4: ${{ steps.policy.outputs.runner_4 }} + allow_depot_remote_cache: ${{ steps.policy.outputs.allow_depot_remote_cache }} allow_native_github_cache: ${{ steps.policy.outputs.allow_native_github_cache }} steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 @@ -72,10 +73,12 @@ jobs: run: working-directory: crates/mesh-llm-ui steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner_4, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} @@ -119,10 +122,12 @@ jobs: runs-on: ${{ needs.runner_policy.outputs.runner_4 }} timeout-minutes: 20 steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner_4, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} diff --git a/.github/workflows/ci-windows-host-slice.yml b/.github/workflows/ci-windows-host-slice.yml index 7b98e230c6..cdc2a6e08f 100644 --- a/.github/workflows/ci-windows-host-slice.yml +++ b/.github/workflows/ci-windows-host-slice.yml @@ -58,6 +58,7 @@ jobs: contents: read outputs: runner_windows: ${{ steps.policy.outputs.runner_windows }} + allow_depot_remote_cache: ${{ steps.policy.outputs.allow_depot_remote_cache }} allow_native_github_cache: ${{ steps.policy.outputs.allow_native_github_cache }} steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 @@ -93,10 +94,12 @@ jobs: MESH_LLM_REQUIRE_SCCACHE: "1" RUSTC_WRAPPER: sccache steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner_windows, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} @@ -108,7 +111,8 @@ jobs: - uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9 - uses: ./.github/actions/configure-sccache-gha with: - allow_depot_remote_cache: "false" + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} - if: ${{ needs.runner_policy.outputs.allow_native_github_cache == 'true' }} uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 snapshot 2026-03-12 continue-on-error: true diff --git a/.github/workflows/ci-windows-product-slice.yml b/.github/workflows/ci-windows-product-slice.yml index a88231451b..48595c606c 100644 --- a/.github/workflows/ci-windows-product-slice.yml +++ b/.github/workflows/ci-windows-product-slice.yml @@ -44,6 +44,7 @@ jobs: contents: read outputs: runner_windows: ${{ steps.policy.outputs.runner_windows }} + allow_depot_remote_cache: ${{ steps.policy.outputs.allow_depot_remote_cache }} allow_native_github_cache: ${{ steps.policy.outputs.allow_native_github_cache }} steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 @@ -76,10 +77,12 @@ jobs: matrix: runtime: ${{ fromJson(inputs.runtime_matrix) }} steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner_windows, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} diff --git a/.github/workflows/ci-windows-runtime-slice.yml b/.github/workflows/ci-windows-runtime-slice.yml index 27384e73e2..28a45af267 100644 --- a/.github/workflows/ci-windows-runtime-slice.yml +++ b/.github/workflows/ci-windows-runtime-slice.yml @@ -48,6 +48,7 @@ jobs: contents: read outputs: runner_windows: ${{ steps.policy.outputs.runner_windows }} + allow_depot_remote_cache: ${{ steps.policy.outputs.allow_depot_remote_cache }} allow_native_github_cache: ${{ steps.policy.outputs.allow_native_github_cache }} steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 @@ -87,10 +88,12 @@ jobs: WINDOWS_VULKAN_SDK_VERSION: ${{ vars.VULKAN_SDK_VERSION || '1.4.328.1' }} ROCM_HIP_SDK_FILENAME: AMD-Software-PRO-Edition-25.Q3-WinSvr2022-For-HIP.exe steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner_windows, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - name: Validate immutable source SHA shell: pwsh env: @@ -111,7 +114,8 @@ jobs: - uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9 - uses: ./.github/actions/configure-sccache-gha with: - allow_depot_remote_cache: "false" + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} - uses: ./.github/actions/resolve-native-toolchain-epoch id: native_toolchain - uses: ./.github/actions/restore-windows-abi-cache diff --git a/.github/workflows/depot-canary.yml b/.github/workflows/depot-canary.yml index 1ad77c603b..8a1b2fb58d 100644 --- a/.github/workflows/depot-canary.yml +++ b/.github/workflows/depot-canary.yml @@ -54,6 +54,15 @@ jobs: # intentionally disabled. Fail closed if the runner still receives # any Depot cache/registry authority or transparently redirects the # GitHub cache service. Names are checked without printing values. + depot_selected=true + allow_native_github_cache=false + allow_depot_remote_cache=false + if [[ "$depot_selected" != "true" || + "$allow_native_github_cache" != "false" || + "$allow_depot_remote_cache" != "false" ]]; then + echo "canary cache policy is inconsistent (cache policy)" >&2 + exit 1 + fi forbidden_names=( DEPOT_CACHE_TOKEN DEPOT_CACHE_URL @@ -67,42 +76,92 @@ jobs: SCCACHE_WEBDAV_TOKEN SCCACHE_WEBDAV_USERNAME SCCACHE_WEBDAV_PASSWORD + SCCACHE_BUCKET + SCCACHE_ENDPOINT + TURBO_TOKEN + TURBO_API + TURBO_TEAM + GOCACHEPROG + REGISTRY_TOKEN + REGISTRY_USERNAME + REGISTRY_PASSWORD + REGISTRY_AUTH_TOKEN + NPM_TOKEN + NODE_AUTH_TOKEN + CARGO_REGISTRIES_CRATES_IO_TOKEN ) for name in "${forbidden_names[@]}"; do if [[ -n "${!name:-}" ]]; then - echo "forbidden Depot cache/registry setting was injected: $name" >&2 + echo "forbidden Depot cache/registry setting was injected ($name)" >&2 exit 1 fi done - actions_cache_url="${ACTIONS_CACHE_URL:-}" - actions_results_url="${ACTIONS_RESULTS_URL:-}" - if [[ "${actions_cache_url,,}" == *depot.dev* || - "${actions_results_url,,}" == *depot.dev* ]]; then - echo "GitHub Actions cache was transparently redirected to Depot" >&2 - exit 1 - fi - for endpoint_name in ACTIONS_CACHE_URL ACTIONS_RESULTS_URL; do + + endpoint_host() { + local endpoint="$1" + local authority="${endpoint#*://}" + authority="${authority%%[/?#]*}" + printf '%s' "$authority" + } + + is_github_endpoint() { + local endpoint="$1" + local endpoint_lower + endpoint_lower="$(printf '%s' "$endpoint" | tr '[:upper:]' '[:lower:]')" + local authority + authority="$(endpoint_host "$endpoint_lower")" + [[ "$endpoint_lower" == https://* ]] || return 1 + [[ "$authority" != *"@"* ]] || return 1 + [[ "$authority" =~ ^([a-z0-9-]+\.)*actions\.githubusercontent\.com(:[0-9]{1,5})?$ ]] + } + + is_loopback_endpoint() { + local endpoint="$1" + local endpoint_lower + endpoint_lower="$(printf '%s' "$endpoint" | tr '[:upper:]' '[:lower:]')" + # Loopback proxies require a numeric TCP port and an explicit path. + if [[ ! "$endpoint_lower" =~ ^https?://(localhost|127\.0\.0\.1|\[::1\]):([0-9]{1,5})/[^[:space:]]*$ ]]; then + return 1 + fi + local port="${BASH_REMATCH[2]}" + (( port >= 1 && port <= 65535 )) + } + + for endpoint_name in ACTIONS_CACHE_URL ACTIONS_RESULTS_URL ACTIONS_RUNTIME_URL; do endpoint="${!endpoint_name:-}" if [[ -z "$endpoint" ]]; then continue fi - endpoint_lower="${endpoint,,}" - if [[ ! "$endpoint_lower" =~ ^https://([a-z0-9-]+\.)*actions\.githubusercontent\.com(:[0-9]+)?([/?#]|$) ]]; then - echo "GitHub Actions endpoint is not GitHub-owned: $endpoint_name" >&2 + endpoint_lower="$(printf '%s' "$endpoint" | tr '[:upper:]' '[:lower:]')" + # The endpoint may be the expected runner-local inert proxy. + # Never accept arbitrary remote endpoints, URL userinfo, or + # lookalike host suffixes. + authority="$(endpoint_host "$endpoint_lower")" + if [[ "$endpoint_lower" == *depot.dev* ]]; then + echo "GitHub Actions cache was transparently redirected to Depot (endpoint)" >&2 + exit 1 + fi + if [[ "$authority" == *"@"* ]]; then + echo "GitHub Actions endpoint contains URL userinfo (endpoint)" >&2 + exit 1 + fi + if ! is_github_endpoint "$endpoint" && + ! is_loopback_endpoint "$endpoint"; then + echo "GitHub Actions endpoint is not GitHub-owned or loopback (endpoint)" >&2 exit 1 fi done docker_auth_config="${DOCKER_AUTH_CONFIG:-}" - if [[ "${docker_auth_config,,}" == *depot.dev* ]]; then - echo "Docker registry authentication points at Depot" >&2 + if [[ -n "$docker_auth_config" ]]; then + echo "Docker registry authentication is configured (DOCKER_AUTH_CONFIG)" >&2 exit 1 fi docker_home="${HOME:-}" docker_config="${DOCKER_CONFIG:-$docker_home/.docker}/config.json" if [[ -f "$docker_config" ]] && - grep -Eiq '(^|[^[:alnum:]])(registry\.)?depot\.dev([^[:alnum:]]|$)' \ + grep -Eiq '"(auths|credHelpers|credsStore)"[[:space:]]*:' \ "$docker_config"; then - echo "Docker config contains Depot registry authentication" >&2 + echo "Docker registry authentication is configured (config.json)" >&2 exit 1 fi diff --git a/.github/workflows/hf-download-smoke.yml b/.github/workflows/hf-download-smoke.yml index d29fc93dfd..5439ae09b3 100644 --- a/.github/workflows/hf-download-smoke.yml +++ b/.github/workflows/hf-download-smoke.yml @@ -53,6 +53,8 @@ jobs: EOF - uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9 - uses: ./.github/actions/configure-sccache-gha + with: + allow_native_github_cache: "true" - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 snapshot 2026-03-12 with: workspaces: . -> target diff --git a/.github/workflows/native-sdk-artifact.yml b/.github/workflows/native-sdk-artifact.yml index e806aec03b..1cc68a9cbf 100644 --- a/.github/workflows/native-sdk-artifact.yml +++ b/.github/workflows/native-sdk-artifact.yml @@ -102,7 +102,7 @@ jobs: outputs: runner: ${{ steps.resolve.outputs.runner }} allow_depot_remote_cache: ${{ steps.resolve.outputs.allow_depot_remote_cache }} - allow_native_github_cache: ${{ steps.policy.outputs.allow_native_github_cache }} + allow_native_github_cache: ${{ steps.resolve.outputs.allow_native_github_cache }} steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: @@ -130,6 +130,7 @@ jobs: RUNNER_SIZE: ${{ inputs.runner_size }} POLICY_EVENT_NAME: ${{ github.event_name }} ALLOW_DEPOT_REMOTE_CACHE: ${{ steps.policy.outputs.allow_depot_remote_cache }} + ALLOW_NATIVE_GITHUB_CACHE: ${{ steps.policy.outputs.allow_native_github_cache }} RUNNER_DEFAULT: ${{ steps.policy.outputs.runner }} RUNNER_4: ${{ steps.policy.outputs.runner_4 }} RUNNER_8: ${{ steps.policy.outputs.runner_8 }} @@ -170,8 +171,16 @@ jobs: ;; *) echo "unsupported native SDK producer target: $TARGET" >&2; exit 1 ;; esac - echo "runner=$runner" >> "$GITHUB_OUTPUT" - echo "allow_depot_remote_cache=$ALLOW_DEPOT_REMOTE_CACHE" >> "$GITHUB_OUTPUT" + if [[ "$runner" == depot-* ]]; then + ALLOW_NATIVE_GITHUB_CACHE=false + else + ALLOW_NATIVE_GITHUB_CACHE=true + fi + { + echo "runner=$runner" + echo "allow_depot_remote_cache=$ALLOW_DEPOT_REMOTE_CACHE" + echo "allow_native_github_cache=$ALLOW_NATIVE_GITHUB_CACHE" + } >> "$GITHUB_OUTPUT" produce_linux_static_abi: needs: runner_policy @@ -209,10 +218,12 @@ jobs: env: LLAMA_STAGE_BUILD_DIR: .deps/llama.cpp/build-stage-abi-static steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} @@ -250,6 +261,7 @@ jobs: - uses: ./.github/actions/configure-sccache-gha with: allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} - name: Prepare patched llama.cpp checkout for ABI reuse if: ${{ inputs.static_abi_artifact_name != '' }} @@ -314,10 +326,12 @@ jobs: permissions: contents: read steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} @@ -341,6 +355,7 @@ jobs: - uses: ./.github/actions/configure-sccache-gha with: allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} - name: Install macOS native SDK dependencies run: brew install cmake ninja lld diff --git a/.github/workflows/node-sdk-addon-artifact.yml b/.github/workflows/node-sdk-addon-artifact.yml index 66c335304b..bba2ecfe24 100644 --- a/.github/workflows/node-sdk-addon-artifact.yml +++ b/.github/workflows/node-sdk-addon-artifact.yml @@ -97,6 +97,7 @@ jobs: - uses: ./.github/actions/configure-sccache-gha with: allow_depot_remote_cache: "false" + allow_native_github_cache: "true" - name: Build, smoke, and stage immutable addon env: NODE_SDK_TARGET: ${{ inputs.target }} @@ -191,6 +192,7 @@ jobs: - uses: ./.github/actions/configure-sccache-gha with: allow_depot_remote_cache: "false" + allow_native_github_cache: "true" - name: Install macOS native dependencies run: brew install cmake ninja lld - name: Configure and validate macOS x64 linker @@ -301,6 +303,7 @@ jobs: - uses: ./.github/actions/configure-sccache-gha with: allow_depot_remote_cache: "false" + allow_native_github_cache: "true" - name: Build, smoke, and stage immutable addon env: NODE_SDK_TARGET: ${{ inputs.target }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2c5b8a4a03..cadafa2db5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -62,6 +62,7 @@ jobs: force_hosted_runners: ${{ steps.meta.outputs.force_hosted_runners }} depot_enabled: ${{ steps.runners.outputs.depot_enabled }} allow_depot_remote_cache: ${{ steps.runners.outputs.allow_depot_remote_cache }} + allow_native_github_cache: ${{ steps.runners.outputs.allow_native_github_cache }} runner: ${{ steps.runners.outputs.runner }} runner_4: ${{ steps.runners.outputs.runner_4 }} runner_8: ${{ steps.runners.outputs.runner_8 }} @@ -189,6 +190,7 @@ jobs: - uses: ./.github/actions/configure-sccache-gha with: allow_depot_remote_cache: ${{ needs.metadata.outputs.allow_depot_remote_cache }} + allow_native_github_cache: "true" - name: Install Linux dependencies if: runner.os == 'Linux' @@ -434,6 +436,7 @@ jobs: - uses: ./.github/actions/configure-sccache-gha with: allow_depot_remote_cache: ${{ needs.metadata.outputs.allow_depot_remote_cache }} + allow_native_github_cache: ${{ ((matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(needs.metadata.outputs.runner_8, 'depot-')) || (matrix.target == 'aarch64-unknown-linux-gnu' && startsWith(needs.metadata.outputs.runner_arm_8, 'depot-'))) && 'false' || 'true' }} - name: Install Linux dependencies if: runner.os == 'Linux' @@ -511,6 +514,7 @@ jobs: - uses: ./.github/actions/configure-sccache-gha with: allow_depot_remote_cache: ${{ needs.metadata.outputs.allow_depot_remote_cache }} + allow_native_github_cache: "true" - name: Prepare dispatched release version if: github.event_name == 'workflow_dispatch' env: @@ -580,6 +584,7 @@ jobs: - uses: ./.github/actions/configure-sccache-gha with: allow_depot_remote_cache: ${{ needs.metadata.outputs.allow_depot_remote_cache }} + allow_native_github_cache: "true" - name: Cache native runtime CUDA backend build uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0 with: @@ -637,7 +642,9 @@ jobs: - uses: ./.github/actions/configure-sccache-gha with: allow_depot_remote_cache: ${{ needs.metadata.outputs.allow_depot_remote_cache }} + allow_native_github_cache: ${{ startsWith(needs.metadata.outputs.runner_16, 'depot-') && 'false' || 'true' }} - name: Cache native runtime ROCm backend build + if: ${{ !startsWith(needs.metadata.outputs.runner_16, 'depot-') }} uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0 with: path: ${{ env.LLAMA_STAGE_BUILD_DIR }} @@ -693,7 +700,9 @@ jobs: - uses: ./.github/actions/configure-sccache-gha with: allow_depot_remote_cache: ${{ needs.metadata.outputs.allow_depot_remote_cache }} + allow_native_github_cache: ${{ startsWith(needs.metadata.outputs.runner_16, 'depot-') && 'false' || 'true' }} - name: Cache native runtime Vulkan backend build + if: ${{ !startsWith(needs.metadata.outputs.runner_16, 'depot-') }} uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0 with: path: ${{ env.LLAMA_STAGE_BUILD_DIR }} diff --git a/.github/workflows/static-abi-artifact.yml b/.github/workflows/static-abi-artifact.yml index e57b2ed62c..b560f54319 100644 --- a/.github/workflows/static-abi-artifact.yml +++ b/.github/workflows/static-abi-artifact.yml @@ -146,10 +146,12 @@ jobs: MESH_LLM_REQUIRE_SCCACHE: "1" SCCACHE_GHA_ENABLED: "true" steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} @@ -167,6 +169,7 @@ jobs: - uses: ./.github/actions/configure-sccache-gha with: allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} # Prepare before restoring the nested build cache. prepare-llama replaces # an unowned .deps/llama.cpp directory, so doing this after cache restore diff --git a/.github/workflows/swift-sdk-artifact.yml b/.github/workflows/swift-sdk-artifact.yml index a046d7d6d8..ebbbab1778 100644 --- a/.github/workflows/swift-sdk-artifact.yml +++ b/.github/workflows/swift-sdk-artifact.yml @@ -65,6 +65,7 @@ jobs: contents: read outputs: runner_macos: ${{ steps.policy.outputs.runner_macos }} + allow_depot_remote_cache: ${{ steps.policy.outputs.allow_depot_remote_cache }} allow_native_github_cache: ${{ steps.policy.outputs.allow_native_github_cache }} steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 @@ -102,10 +103,12 @@ jobs: SCCACHE_GHA_ENABLED: "true" SCCACHE_GHA_RW_MODE: ${{ (github.event_name == 'pull_request' || github.event_name == 'pull_request_target' || github.event.inputs.original_event_name == 'pull_request' || github.event.inputs.original_event_name == 'pull_request_target') && 'READ_ONLY' || 'READ_WRITE' }} steps: - - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8 + - uses: Mesh-LLM/mesh-llm/.github/actions/audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8 with: original_event_name: ${{ inputs.original_event_name }} depot_selected: ${{ startsWith(needs.runner_policy.outputs.runner_macos, 'depot-') }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ inputs.source_sha || github.sha }} @@ -158,6 +161,9 @@ jobs: - uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9 - uses: ./.github/actions/configure-sccache-gha + with: + allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }} + allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }} - name: Install macOS SDK build dependencies run: brew install cmake ninja lld diff --git a/.omo/specs/pr-ci-optimization.md b/.omo/specs/pr-ci-optimization.md index 6c192bf3ce..bb8f7f2a71 100644 --- a/.omo/specs/pr-ci-optimization.md +++ b/.omo/specs/pr-ci-optimization.md @@ -235,12 +235,17 @@ global `DEPOT_PR_RUNNERS_ENABLED` gate remains absent/false. Fork heads, GitHub-hosted runners. Depot's documented GitHub cache path is repository-scoped and not branch-isolated; automatic cache redirection can expose repository-wide cache authority to PR code. Cache-key prefixes are not -isolation. The central selector now emits `allow_native_github_cache=false` -for a Depot-selected direct PR, and all eligible native GitHub cache consumers -are conditionally disabled while the underlying install/build commands remain -unchanged. This removes the checked-in cache API path but is not an ambient -Depot/WebDAV authority proof; the actual runner sentinel and no-token checks -remain required before enabling the canary or global PR gate. +isolation. The central selector now emits both +`allow_native_github_cache=false` and `allow_depot_remote_cache=false` for +every Depot selection, including trusted main; all eligible native GitHub and +Depot remote-cache consumers are conditionally disabled while the underlying +install/build commands remain unchanged. Hosted release and cache-warmer +paths retain their existing GitHub cache behavior. The Depot namespace is +intentionally unused by trusted workflows, so existing entries must be purged +or expire before the PR gate. A GitHub-owned or strict loopback proxy is inert +transport only, not an ambient authority proof; the actual runner sentinel +and no-token checks remain required before enabling the canary or global PR +gate. Before a PR Depot path is enabled, an administrator must prove: diff --git a/ci/DEPOT_MIGRATION.md b/ci/DEPOT_MIGRATION.md index d4d3614a33..bc23e4180e 100644 --- a/ci/DEPOT_MIGRATION.md +++ b/ci/DEPOT_MIGRATION.md @@ -7,6 +7,10 @@ this repository and the protected workflow allowlist. The checked-in graph and collector define the remaining branch/main and same-repository/fork canaries; those runtime checks still block PR activation. +Checked-in policy now treats Depot's cache namespace as unused: every Depot +selection disables both native GitHub Actions cache and Depot remote cache. +Purge or expiry of existing entries remains an activation prerequisite. + The complete PR/main composition design is in `.omo/specs/pr-ci-optimization.md`. This document contains only the durable Depot policy and activation gates. It intentionally contains no historical run @@ -40,10 +44,17 @@ Depot is a placement provider, not a different CI graph. remains hosted. - Callers never provide a raw Depot label or a separate remote-cache permission. Runner and cache policy come from one event-derived decision. -- The PR isolation audit receives that selected-provider decision. Depot-selected - PR jobs require GitHub-owned Actions endpoints; hosted PR jobs allow the - runner's approved local transport while still rejecting Depot credentials, - `depot.dev` redirects, and URL userinfo. +- The PR isolation audit receives that selected-provider and cache-policy + decision. Depot-selected PR jobs accept only GitHub-owned Actions endpoints + or a strict loopback proxy (`http[s]://localhost|127.0.0.1|[::1]:/`); + hosted PR jobs retain their approved local transport while still rejecting + Depot credentials, `depot.dev` redirects, and URL userinfo. +- The Depot cache namespace is intentionally unused by trusted workflows: + Depot selections disable both native GitHub cache APIs and Depot remote + cache. Purge or expire any existing namespace entries before enabling the PR + gate. A proxy's presence is inert transport, not proof of authority + isolation; activation remains blocked until no trusted consumer uses Depot + cache. Disabling Depot must change placement only. It must not change plan membership, commands, artifacts, smoke coverage or required checks. @@ -88,7 +99,8 @@ when landing the composable graph: 4. From `main`, manually dispatch `CI ยท Plan` with `use_depot=true`. This exercises the split Quality/Linux graphs as a bounded provider canary without changing the plan, commands, artifacts or required summaries. - Verify the eligible jobs report Depot labels and Depot cache evidence while + Verify the eligible jobs report Depot labels and no Depot cache evidence (the + namespace must remain inert) while macOS, Windows, credentialed smoke and GPU jobs retain their documented providers. 5. When the canary is green, set `DEPOT_RUNNERS_ENABLED=true` for normal trusted @@ -201,8 +213,9 @@ The remaining runtime questions are: 1. Does a fresh Depot runner expose any ambient Depot/WebDAV/cache authority to a PR job even when the checked-in native cache consumers are disabled? -2. Does a trusted main build retain its intended cache behavior with automatic - Depot connectivity disabled, or should it use GitHub native cache only? +2. Do hosted release and cache-warmer jobs retain their intended GitHub cache + behavior while trusted Depot selections remain cache-inert, and have all + existing Depot namespace entries been purged or expired? 3. Can a same-repository PR and a fork PR both run the protected canary with no Depot cache/registry authority and no entry that trusted main later restores? 4. Does provider parity hold for the same checked plan, commands, artifacts, @@ -210,8 +223,12 @@ The remaining runtime questions are: 5. Does the restricted runner group continue to allow only the exact protected workflow refs after the PR canary is enabled? -The selector now emits a provider-derived `allow_native_github_cache` output. -Every eligible Depot-selected direct PR cache consumer is skipped or passed a +The selector now emits provider-derived `allow_native_github_cache` and +`allow_depot_remote_cache` outputs. Every Depot selection emits +`allow_native_github_cache=false` and `allow_depot_remote_cache=false`; hosted +selections retain native GitHub cache (`allow_native_github_cache=true`) while +Depot remote cache remains disabled (`allow_depot_remote_cache=false`). Every +eligible Depot-selected direct PR cache consumer is skipped or passed a disabled cache input, while installation and build commands remain active; cache misses therefore rebuild normally. This closes the checked-in native GitHub-cache path but does not prove that a fresh Depot runner cannot reach an @@ -265,7 +282,8 @@ the untrusted PR probe: 4. Both must fail to read the trusted sentinel. 5. Both must fail to publish an entry that trusted main later restores. 6. Both must receive no cache/registry token and no repository secret. -7. Trusted main must retain its intended cache behavior. +7. Hosted release/cache-warmer jobs must retain their intended GitHub cache + behavior; trusted Depot selections must remain cache-inert. 8. Provider rollback must send the identical plan to GitHub-hosted runners. Cache-key separation alone does not satisfy this test. diff --git a/ci/ci.md b/ci/ci.md index 06a4db484a..36fd4c12a9 100644 --- a/ci/ci.md +++ b/ci/ci.md @@ -282,6 +282,16 @@ smokes and other hardware-qualified work retain explicit approved placement. Provider choice never changes plan membership, commands, artifacts, tests or summaries. +The central selector makes the Depot cache namespace intentionally inert for +every Depot selection, including trusted `main`: it emits both +`allow_native_github_cache=false` and `allow_depot_remote_cache=false`. Hosted +release and cache-warmer workflows retain their existing GitHub cache behavior. +Any pre-existing Depot namespace entries must be purged or allowed to expire +before the PR gate is enabled. A GitHub-owned or strict loopback Actions-cache +proxy is inert transport only; its presence is not proof of authority +isolation, and the gate remains closed until no trusted workflow consumes the +Depot namespace. + The selector also accepts the optional repository variable `DEPOT_PR_CANARY_REF`. When it is absent (the default), no canary PR is selected and the normal global `DEPOT_PR_RUNNERS_ENABLED` gate is unchanged. @@ -324,14 +334,16 @@ The implemented policy uses that isolation selectively: | Website npm store | Website-only lockfile-keyed cache | Later same-PR website runs avoid downloading the unchanged dependency store | | GitHub artifacts | Never used as cross-run caches | Immutable producers/consumers remain correct within one run; reruns recreate run-scoped artifacts | -For a Depot-selected direct PR, the central runner policy emits -`allow_native_github_cache=false`. Every native GitHub cache consumer in the +For any Depot-selected run, the central runner policy emits +`allow_native_github_cache=false` and `allow_depot_remote_cache=false`. Every +native GitHub cache consumer in the eligible five-lane build graph (explicit `actions/cache`, setup-node package caches, rust-cache, static/Metal/Windows/Swift ABI caches, and Windows SDK cache toggles) is then skipped or disabled; the installation and build steps -still run and regenerate on a miss. Hosted PRs and trusted main/release/manual -paths retain the existing cache behavior. This is a checked-in consumer -policy, not proof that a Depot runner has no ambient Depot/WebDAV authority. +still run and regenerate on a miss. Hosted PRs and trusted hosted +main/release/manual paths retain the existing cache behavior. This is a +checked-in consumer policy, not proof that a Depot runner has no ambient +Depot/WebDAV authority. This is intentionally not a universal PR write-through policy. Cargo target caches are commonly hundreds of megabytes to several gigabytes per row; making @@ -343,11 +355,12 @@ must still regenerate successfully after a miss. Depot PR execution is not enabled. The bounded `DEPOT_PR_CANARY_REF` selector hook exists only to exercise a single protected same-repository ref after the -external gates are ready. The implemented no-native-cache mode prevents the -checked-in GitHub cache consumers from reading or writing on that Depot PR, -but it does not prove that a runner has no ambient Depot/WebDAV/cache -authority. A protected runner-group check, no-secret/no-token execution and -the non-secret sentinel canary in `ci/DEPOT_MIGRATION.md` remain prerequisites. +external gates are ready. The implemented cache-inert mode prevents the +checked-in GitHub and Depot cache consumers from reading or writing on any +Depot run, but it does not prove that a runner has no ambient Depot/WebDAV/cache +authority. A protected runner-group check, no-secret/no-token execution, +namespace purge/expiry, and the non-secret sentinel canary in +`ci/DEPOT_MIGRATION.md` remain prerequisites. Do not change Depot settings or runner groups in a workflow refactor. The external administrative posture now has automatic Depot Cache and Registry diff --git a/scripts/tests/test_ci_artifact_actions.py b/scripts/tests/test_ci_artifact_actions.py index 2f5081c8d8..d68216a4c7 100644 --- a/scripts/tests/test_ci_artifact_actions.py +++ b/scripts/tests/test_ci_artifact_actions.py @@ -38,7 +38,7 @@ def test_external_actions_have_sha_and_release_provenance(self) -> None: } protected_pre_checkout_action = ( "Mesh-LLM/mesh-llm/.github/actions/" - "audit-depot-pr-isolation@98909c0909a947944dd3215ff4ef2c7f431e4ea8" + "audit-depot-pr-isolation@b5dc126b0abe9b990cccbbf65796c26af7a09dc8" ) for path in (*action_files, *workflow_files): @@ -434,6 +434,10 @@ def run_reusable_runner_policy( "allow_depot_remote_cache", selected["allow_depot_remote_cache"], ) + outputs.setdefault( + "allow_native_github_cache", + selected["allow_native_github_cache"], + ) return result, outputs def test_host_action_uses_canonical_dynamic_host_builder(self) -> None: @@ -1261,9 +1265,13 @@ def test_protected_reusable_runner_policy_is_fail_closed(self) -> None: ) self.assertEqual(result.returncode, 0, result.stderr) self.assertEqual(outputs["runner"], expected_runner) + self.assertEqual( + outputs["allow_native_github_cache"], + "false", + ) self.assertEqual( outputs["allow_depot_remote_cache"], - "true", + "false", ) result, outputs = self.run_reusable_runner_policy( @@ -1277,11 +1285,30 @@ def test_protected_reusable_runner_policy_is_fail_closed(self) -> None: ) self.assertEqual(result.returncode, 0, result.stderr) self.assertEqual(outputs["runner"], "ubuntu-24.04-arm") + self.assertEqual( + outputs["allow_native_github_cache"], + "true", + ) self.assertEqual( outputs["allow_depot_remote_cache"], "false", ) + if workflow_name == "native-sdk-artifact.yml": + result, outputs = self.run_reusable_runner_policy( + workflow_name, + repository="Mesh-LLM/mesh-llm", + event_name="push", + ref="refs/heads/main", + depot_enabled="true", + target="aarch64-apple-darwin", + runner_size="8", + ) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(outputs["runner"], "macos-15") + self.assertEqual(outputs["allow_native_github_cache"], "true") + self.assertEqual(outputs["allow_depot_remote_cache"], "false") + result, outputs = self.run_reusable_runner_policy( workflow_name, repository="Mesh-LLM/mesh-llm", @@ -1315,7 +1342,7 @@ def test_protected_reusable_runner_policy_is_fail_closed(self) -> None: ) self.assertEqual( outputs["allow_depot_remote_cache"], - "true", + "false", ) for event_name, ref, manual_use_depot in ( @@ -1817,6 +1844,8 @@ def test_sccache_prefers_depot_webdav_with_disk_fallback(self) -> None: self.assertIn("allow_depot_remote_cache", action) self.assertIn('default: "false"', action) + self.assertIn("allow_native_github_cache", action) + self.assertIn('default: "false"', action) self.assertIn("SCCACHE_WEBDAV_ENDPOINT", action) self.assertIn("DEPOT_CACHE_TOKEN", action) self.assertIn("process.env.SCCACHE_DIR", action) @@ -1833,6 +1862,10 @@ def test_sccache_prefers_depot_webdav_with_disk_fallback(self) -> None: "Depot cache is present but disabled for this trust context", action, ) + self.assertIn( + "Native GitHub and Depot cache disabled for this trust context", + action, + ) self.assertIn( "'Unable to start baked sccache with its trust-isolated disk cache.'", action, @@ -1901,7 +1934,7 @@ def test_runner_selection_uses_event_repository_and_ref_policy(self) -> None: "", "false", "depot-ubuntu-24.04", - "true", + "false", ), ( "workflow_dispatch", @@ -1911,7 +1944,7 @@ def test_runner_selection_uses_event_repository_and_ref_policy(self) -> None: "", "false", "depot-ubuntu-24.04", - "true", + "false", ), ( "workflow_dispatch", @@ -1921,7 +1954,7 @@ def test_runner_selection_uses_event_repository_and_ref_policy(self) -> None: "", "false", "depot-ubuntu-24.04", - "true", + "false", ), ( "workflow_dispatch", @@ -1931,7 +1964,7 @@ def test_runner_selection_uses_event_repository_and_ref_policy(self) -> None: "push", "false", "depot-ubuntu-24.04", - "true", + "false", ), ( "workflow_dispatch", @@ -1951,7 +1984,7 @@ def test_runner_selection_uses_event_repository_and_ref_policy(self) -> None: "", "false", "depot-ubuntu-24.04", - "true", + "false", ), ( "push", @@ -2021,7 +2054,7 @@ def test_runner_selection_uses_event_repository_and_ref_policy(self) -> None: ) expected_native_cache = ( "false" - if enabled == "true" and event_name == "pull_request" + if enabled == "true" else "true" ) self.assertEqual( @@ -2386,6 +2419,12 @@ def step_block(workflow: str, marker: str) -> str: windows = ( ROOT / ".github" / "workflows" / "ci-windows-runtime-slice.yml" ).read_text(encoding="utf-8") + release = ( + ROOT / ".github" / "workflows" / "release.yml" + ).read_text(encoding="utf-8") + warmer = ( + ROOT / ".github" / "workflows" / "windows-warm-caches.yml" + ).read_text(encoding="utf-8") native_cache_expression = ( "needs.runner_policy.outputs.allow_native_github_cache == 'true'" ) @@ -2418,6 +2457,62 @@ def step_block(workflow: str, marker: str) -> str: action = self.read_action(action_name) self.assertIn("inputs.allow-native-github-cache == 'true'", action) + # Trusted Depot release selections must leave native cache consumers + # inert, while the hosted release/cache-warmer paths retain their + # existing GitHub cache opt-in. + self.assertIn( + "allow_native_github_cache: ${{ steps.runners.outputs.allow_native_github_cache }}", + release, + ) + for cache_name in ( + "Cache native runtime ROCm backend build", + "Cache native runtime Vulkan backend build", + ): + cache_start = release.index(f"name: {cache_name}") + cache_block = release[cache_start : release.find("\n - ", cache_start + 1)] + self.assertIn( + "!startsWith(needs.metadata.outputs.runner_16, 'depot-')", + cache_block, + ) + self.assertGreaterEqual( + warmer.count('allow-native-github-cache: "true"'), + 2, + ) + + def test_depot_sccache_consumers_receive_both_central_cache_outputs(self) -> None: + provider_workflows = ( + "ci-quality-slice.yml", + "ci-linux-host-slice.yml", + "ci-linux-runtime-slice.yml", + "ci-rust-tests-slice.yml", + "ci-windows-host-slice.yml", + "ci-windows-runtime-slice.yml", + "static-abi-artifact.yml", + "native-sdk-artifact.yml", + "swift-sdk-artifact.yml", + ) + for filename in provider_workflows: + workflow = ( + ROOT / ".github" / "workflows" / filename + ).read_text(encoding="utf-8") + self.assertIn( + "allow_depot_remote_cache: ${{ needs.runner_policy.outputs.allow_depot_remote_cache }}", + workflow, + filename, + ) + self.assertIn( + "allow_native_github_cache: ${{ needs.runner_policy.outputs.allow_native_github_cache }}", + workflow, + filename, + ) + release = ( + ROOT / ".github" / "workflows" / "release.yml" + ).read_text(encoding="utf-8") + self.assertIn( + "allow_native_github_cache: ${{ ((matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(needs.metadata.outputs.runner_8, 'depot-')) || (matrix.target == 'aarch64-unknown-linux-gnu' && startsWith(needs.metadata.outputs.runner_arm_8, 'depot-'))) && 'false' || 'true' }}", + release, + ) + if __name__ == "__main__": unittest.main() diff --git a/scripts/tests/test_depot_canary_workflow.py b/scripts/tests/test_depot_canary_workflow.py index ca773ac85f..a8f23dd3a7 100644 --- a/scripts/tests/test_depot_canary_workflow.py +++ b/scripts/tests/test_depot_canary_workflow.py @@ -53,16 +53,21 @@ def test_canary_fails_closed_on_cache_and_registry_injection(self) -> None: ): with self.subTest(name=name): self.assertIn(name, self.workflow) - self.assertIn('actions_cache_url="${ACTIONS_CACHE_URL:-}"', self.workflow) - self.assertIn('actions_results_url="${ACTIONS_RESULTS_URL:-}"', self.workflow) - self.assertIn("${actions_cache_url,,}", self.workflow) - self.assertIn("${actions_results_url,,}", self.workflow) + self.assertIn('for endpoint_name in ACTIONS_CACHE_URL ACTIONS_RESULTS_URL ACTIONS_RUNTIME_URL; do', self.workflow) + self.assertIn('endpoint_host() {', self.workflow) + self.assertIn('is_loopback_endpoint() {', self.workflow) + self.assertIn(r"\[::1\]", self.workflow) + self.assertIn("numeric", self.workflow.lower()) self.assertIn("transparently redirected to Depot", self.workflow) self.assertIn("ACTIONS_RESULTS_URL", self.workflow) self.assertIn("actions\\.githubusercontent\\.com", self.workflow) + self.assertNotIn(",,}", self.workflow) + self.assertIn( + "printf '%s' \"$endpoint\" | tr '[:upper:]' '[:lower:]'", + self.workflow, + ) self.assertIn('docker_auth_config="${DOCKER_AUTH_CONFIG:-}"', self.workflow) - self.assertIn("${docker_auth_config,,}", self.workflow) - self.assertIn("Docker config contains Depot registry authentication", self.workflow) + self.assertIn("Docker registry authentication is configured", self.workflow) self.assertIn( "Depot cache credentials/endpoints injected | no", self.workflow, @@ -87,20 +92,19 @@ def test_pr_audit_uses_portable_endpoint_and_docker_config_checks(self) -> None: / "audit-depot-pr-isolation" / "action.yml" ).read_text(encoding="utf-8") + self.assertNotIn(",,}", action) self.assertIn( - 'endpoint_lower="$(printf \'%s\' "$endpoint" | tr ' - "'[:upper:]' '[:lower:]')\"", + "printf '%s' \"$endpoint\" | tr '[:upper:]' '[:lower:]'", action, ) self.assertIn("depot_selected", action) self.assertIn("INPUT_DEPOT_SELECTED", action) self.assertIn('if [[ "$endpoint_lower" == *depot.dev* ]]', action) + self.assertIn("allow_native_github_cache", action) + self.assertIn("allow_depot_remote_cache", action) self.assertIn("URL userinfo", action) - self.assertIn( - 'docker_config="${DOCKER_CONFIG:-${HOME:-}/.docker}/config.json"', - action, - ) - self.assertIn("grep -Eiq 'depot\\.dev'", action) + self.assertIn('docker_config="${DOCKER_CONFIG:-${HOME:-}/.docker}/config.json"', action) + self.assertIn('grep -Eiq \'"(auths|credHelpers|credsStore)"', action) def test_pr_audit_receives_central_runner_provider_selection(self) -> None: workflow_root = ROOT / ".github" / "workflows" @@ -128,10 +132,7 @@ def test_endpoint_and_docker_auth_probes_fail_closed(self) -> None: ).read_text(encoding="utf-8") action_run = action.split(" run: |\n", maxsplit=1)[1] action_script = dedent(action_run) - canary_start = self.workflow.index( - " for endpoint_name in ACTIONS_CACHE_URL " - "ACTIONS_RESULTS_URL; do", - ) + canary_start = self.workflow.index(" depot_selected=true") canary_end = self.workflow.index( " {\n", canary_start, @@ -147,6 +148,7 @@ def run_probe( docker_auth_config: str | None = None, docker_config_content: str | None = None, depot_selected: str = "true", + unset_endpoints: bool = False, **extra_environment: str, ) -> subprocess.CompletedProcess[str]: with ( @@ -165,10 +167,22 @@ def run_probe( "GITHUB_EVENT_NAME": "pull_request", "INPUT_ORIGINAL_EVENT_NAME": "pull_request", "INPUT_DEPOT_SELECTED": depot_selected, + "INPUT_ALLOW_NATIVE_GITHUB_CACHE": ( + "false" if depot_selected == "true" else "true" + ), + "INPUT_ALLOW_DEPOT_REMOTE_CACHE": "false", "ACTIONS_CACHE_URL": cache_url, "ACTIONS_RESULTS_URL": results_url, + "ACTIONS_RUNTIME_URL": "", **extra_environment, } + if unset_endpoints: + for endpoint_name in ( + "ACTIONS_CACHE_URL", + "ACTIONS_RESULTS_URL", + "ACTIONS_RUNTIME_URL", + ): + environment.pop(endpoint_name, None) if docker_auth_config is not None: environment["DOCKER_AUTH_CONFIG"] = docker_auth_config return subprocess.run( @@ -192,6 +206,10 @@ def run_probe( "HTTPS://ACTIONS.GITHUBUSERCONTENT.COM?cache=1", "https://results-receiver.actions.githubusercontent.com#results", ), + ( + "http://[::1]:12345/_apis/artifactcache/", + "HTTPS://LOCALHOST:12346/results", + ), ) hosted_endpoints = ( ( @@ -216,6 +234,26 @@ def run_probe( "https://actions.githubusercontent.com.evil/cache", valid_endpoints[0][1], ), + ( + "http://user@localhost:1234/cache", + valid_endpoints[0][1], + ), + ( + "http://localhost.evil:1234/cache", + valid_endpoints[0][1], + ), + ( + "https://cache.example.invalid/cache", + valid_endpoints[0][1], + ), + ( + "http://[::1]:abc/cache", + valid_endpoints[0][1], + ), + ( + "HTTPS://CACHE.DEPOT.DEV/cache", + valid_endpoints[0][1], + ), ) absent_endpoints = ( ("", ""), @@ -253,11 +291,33 @@ def run_probe( with self.subTest(script=script_name, absent_endpoints=endpoints): result = run_probe(script, *endpoints) self.assertEqual(result.returncode, 0, result.stderr) + with self.subTest(script=script_name, unset_endpoints=True): + result = run_probe( + script, + "", + "", + unset_endpoints=True, + ) + self.assertEqual(result.returncode, 0, result.stderr) for endpoints in invalid_endpoints: with self.subTest(script=script_name, endpoints=endpoints): result = run_probe(script, *endpoints) self.assertNotEqual(result.returncode, 0) if script_name == "audit action": + with self.subTest(script=script_name, policy="native cache enabled"): + result = run_probe( + script, + *valid_endpoints[0], + INPUT_ALLOW_NATIVE_GITHUB_CACHE="true", + ) + self.assertNotEqual(result.returncode, 0) + with self.subTest(script=script_name, policy="Depot remote cache enabled"): + result = run_probe( + script, + *valid_endpoints[0], + INPUT_ALLOW_DEPOT_REMOTE_CACHE="true", + ) + self.assertNotEqual(result.returncode, 0) for endpoints in ( ( "https://cache.depot.dev/cache", @@ -307,13 +367,13 @@ def run_probe( docker_config_content=depot_config, ) self.assertNotEqual(result.returncode, 0) - with self.subTest(script=script_name, auth="safe config.json"): + with self.subTest(script=script_name, auth="any config.json"): result = run_probe( script, *valid_endpoints[0], docker_config_content=safe_config, ) - self.assertEqual(result.returncode, 0, result.stderr) + self.assertNotEqual(result.returncode, 0) with self.subTest(script=script_name, auth="unset"): result = run_probe(script, *valid_endpoints[0]) self.assertEqual(result.returncode, 0, result.stderr) diff --git a/scripts/tests/test_release_workflow_artifacts.py b/scripts/tests/test_release_workflow_artifacts.py index fc7cf6877b..7aee611966 100644 --- a/scripts/tests/test_release_workflow_artifacts.py +++ b/scripts/tests/test_release_workflow_artifacts.py @@ -160,6 +160,60 @@ def test_release_routes_only_initial_non_secret_linux_lanes( ) self.assertNotIn("USE_SELF_HOSTED", arm_smoke) + def test_native_runtime_cache_policy_tracks_effective_runner(self) -> None: + workflow = RELEASE_WORKFLOW.read_text(encoding="utf-8") + native_runtime = job_block( + workflow, + "build_native_runtime", + "build_native_runtime_linux_aarch64_cuda", + ) + rocm = job_block( + workflow, + "build_native_runtime_linux_x86_64_rocm", + "build_native_runtime_linux_x86_64_vulkan", + ) + vulkan = job_block( + workflow, + "build_native_runtime_linux_x86_64_vulkan", + "build_swift_sdk_artifact", + ) + self.assertIn( + "allow_native_github_cache: ${{ ((matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(needs.metadata.outputs.runner_8, 'depot-')) || (matrix.target == 'aarch64-unknown-linux-gnu' && startsWith(needs.metadata.outputs.runner_arm_8, 'depot-'))) && 'false' || 'true' }}", + native_runtime, + ) + for target, runner_8, runner_arm_8, expected in ( + ("x86_64-unknown-linux-gnu", "depot-ubuntu-24.04-8", "ubuntu-24.04-arm", "false"), + ("x86_64-unknown-linux-gnu", "ubuntu-24.04", "ubuntu-24.04-arm", "true"), + ("aarch64-unknown-linux-gnu", "ubuntu-24.04", "depot-ubuntu-24.04-arm-8", "false"), + ("aarch64-apple-darwin", "depot-ubuntu-24.04-8", "depot-ubuntu-24.04-arm-8", "true"), + ): + depot = ( + target == "x86_64-unknown-linux-gnu" and runner_8.startswith("depot-") + ) or ( + target == "aarch64-unknown-linux-gnu" + and runner_arm_8.startswith("depot-") + ) + self.assertEqual("false" if depot else "true", expected) + + for runner_16, expected in ( + ("depot-ubuntu-24.04-16", "false"), + ("ubuntu-24.04", "true"), + ): + self.assertEqual( + "false" if runner_16.startswith("depot-") else "true", + expected, + ) + + effective_runner_16_cache_gate = ( + "if: ${{ !startsWith(needs.metadata.outputs.runner_16, 'depot-') }}" + ) + provider_level_cache_gate = ( + "if: ${{ needs.metadata.outputs.allow_native_github_cache == 'true' }}" + ) + for producer in (rocm, vulkan): + self.assertIn(effective_runner_16_cache_gate, producer) + self.assertNotIn(provider_level_cache_gate, producer) + def test_inference_smoke_consumes_composed_product(self) -> None: workflow = RELEASE_WORKFLOW.read_text(encoding="utf-8") diff --git a/scripts/tests/test_sccache_evidence.py b/scripts/tests/test_sccache_evidence.py index 3f7d7fbfbc..bdeada3d96 100644 --- a/scripts/tests/test_sccache_evidence.py +++ b/scripts/tests/test_sccache_evidence.py @@ -9,6 +9,8 @@ import tempfile import unittest +import yaml + ROOT = Path(__file__).resolve().parents[2] ACTION_DIR = ROOT / ".github" / "actions" / "capture-sccache-stats" @@ -60,6 +62,60 @@ def valid_payload(*, compile_requests: int = 12) -> dict[str, object]: class SccacheEvidenceTests(unittest.TestCase): + def test_configure_callers_declare_native_cache_policy(self) -> None: + policy = "${{ needs.runner_policy.outputs.allow_native_github_cache }}" + effective_release = ( + "${{ ((matrix.target == 'x86_64-unknown-linux-gnu' && " + "startsWith(needs.metadata.outputs.runner_8, 'depot-')) || " + "(matrix.target == 'aarch64-unknown-linux-gnu' && " + "startsWith(needs.metadata.outputs.runner_arm_8, 'depot-'))) " + "&& 'false' || 'true' }}" + ) + effective_release_runner_16 = ( + "${{ startsWith(needs.metadata.outputs.runner_16, 'depot-') " + "&& 'false' || 'true' }}" + ) + expected = { + ("ci-linux-host-slice.yml", "linux_host"): policy, + ("ci-linux-runtime-slice.yml", "linux_runtime"): policy, + ("ci-quality-slice.yml", "rust_clippy"): policy, + ("ci-rust-tests-slice.yml", "rust_tests"): policy, + ("ci-windows-host-slice.yml", "windows_host"): policy, + ("ci-windows-runtime-slice.yml", "windows_runtime"): policy, + ("hf-download-smoke.yml", "hf_download_smoke"): "true", + ("native-sdk-artifact.yml", "linux_native_sdk_artifact"): policy, + ("native-sdk-artifact.yml", "macos_native_sdk_artifact"): policy, + ("node-sdk-addon-artifact.yml", "linux_addon"): "true", + ("node-sdk-addon-artifact.yml", "macos_addon"): "true", + ("node-sdk-addon-artifact.yml", "windows_addon"): "true", + ("release.yml", "build"): "true", + ("release.yml", "build_native_runtime"): effective_release, + ("release.yml", "build_native_runtime_linux_aarch64_cuda"): "true", + ("release.yml", "build_native_runtime_linux_x86_64_cuda"): "true", + ("release.yml", "build_native_runtime_linux_x86_64_rocm"): effective_release_runner_16, + ("release.yml", "build_native_runtime_linux_x86_64_vulkan"): effective_release_runner_16, + ("static-abi-artifact.yml", "static_abi_artifact"): policy, + ("swift-sdk-artifact.yml", "swift_sdk_artifact"): policy, + } + actual: dict[tuple[str, str], str] = {} + for workflow_path in sorted((ROOT / ".github" / "workflows").glob("*.yml")): + workflow = yaml.safe_load(workflow_path.read_text(encoding="utf-8")) or {} + for job_name, job in (workflow.get("jobs") or {}).items(): + for step in job.get("steps") or []: + if step.get("uses") != "./.github/actions/configure-sccache-gha": + continue + with_values = step.get("with") or {} + self.assertIn( + "allow_native_github_cache", + with_values, + f"{workflow_path.name}:{job_name} must set cache policy", + ) + actual[(workflow_path.name, job_name)] = str( + with_values["allow_native_github_cache"], + ) + self.assertEqual(set(expected), set(actual)) + self.assertEqual(expected, actual) + def run_capture( self, payload: dict[str, object],