Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/runtime-isolation-host-profile.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Runtime Isolation Host Profile

on:
workflow_dispatch:

permissions:
contents: read

jobs:
profile-current-runner:
runs-on: self-hosted
timeout-minutes: 10
steps:
- name: Checkout BinancePlatform
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6

- name: Collect redacted host, egress, and secret-boundary profile
env:
RUNTIME_EGRESS_CHECK_URL: ${{ vars.BINANCE_RUNTIME_EGRESS_CHECK_URL }}
RUNTIME_EXPECTED_EGRESS_SHA256: ${{ vars.BINANCE_RUNTIME_EGRESS_SHA256 }}
run: |
set -euo pipefail
python3 scripts/runtime_isolation_host_probe.py \
--workflow .github/workflows/main.yml \
--output reports/runtime_isolation_host_profile.json

- name: Upload redacted host profile
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: runtime-isolation-host-profile-${{ github.run_id }}
path: reports/runtime_isolation_host_profile.json
if-no-files-found: error
retention-days: 7
114 changes: 107 additions & 7 deletions .github/workflows/runtime-isolation-shadow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ name: Runtime Isolation Shadow Fixture

on:
workflow_dispatch:
inputs:
include_current_runner:
description: "Also replay the no-order fixture on the current self-hosted runner"
required: false
default: false
type: boolean

permissions:
contents: read
Expand Down Expand Up @@ -57,16 +63,110 @@ jobs:
BINANCE_DRY_RUN: "true"
run: |
set -euo pipefail
uv run --no-sync python run_cycle_replay.py \
--run-id "isolation-shadow-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" \
--output reports/runtime_isolation_shadow.json
uv run --no-sync python scripts/assert_no_order_shadow_report.py \
reports/runtime_isolation_shadow.json
uv run --no-sync python scripts/run_isolation_shadow_fixture.py \
--output reports/runtime_isolation_shadow.json \
--digest-output reports/runtime_isolation_shadow.sha256

- name: Upload redacted shadow report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: runtime-isolation-shadow-${{ github.run_id }}
path: reports/runtime_isolation_shadow.json
name: runtime-isolation-shadow-github-${{ github.run_id }}
path: |
reports/runtime_isolation_shadow.json
reports/runtime_isolation_shadow.sha256
if-no-files-found: error
retention-days: 7

current-runner-shadow:
if: ${{ inputs.include_current_runner }}
runs-on: self-hosted
timeout-minutes: 20
steps:
- name: Checkout BinancePlatform
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6

- name: Resolve pinned dependency refs
id: refs
shell: bash
run: |
set -euo pipefail
qpk_ref="$(grep -Eo 'QuantPlatformKit\.git@[0-9a-f]+' pyproject.toml | head -n1 | sed 's/.*@//')"
strategies_ref="$(grep -Eo 'CryptoStrategies\.git@[0-9a-f]+' pyproject.toml | head -n1 | sed 's/.*@//')"
test -n "$qpk_ref"
test -n "$strategies_ref"
echo "qpk_ref=$qpk_ref" >> "$GITHUB_OUTPUT"
echo "strategies_ref=$strategies_ref" >> "$GITHUB_OUTPUT"

- name: Checkout QuantPlatformKit
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
repository: QuantStrategyLab/QuantPlatformKit
ref: ${{ steps.refs.outputs.qpk_ref }}
path: external/QuantPlatformKit

- name: Checkout CryptoStrategies
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
repository: QuantStrategyLab/CryptoStrategies
ref: ${{ steps.refs.outputs.strategies_ref }}
path: external/CryptoStrategies

- name: Setup Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: "3.11"

- name: Install locked runtime in the job temp directory
env:
UV_PROJECT_ENVIRONMENT: ${{ runner.temp }}/binance-isolation-shadow-venv
run: |
set -euo pipefail
python -m pip install --disable-pip-version-check uv==0.11.6
uv sync --frozen --no-dev
uv pip install --no-deps -e external/QuantPlatformKit -e external/CryptoStrategies

- name: Run current-runner fixed-input no-order replay
env:
BINANCE_DRY_RUN: "true"
UV_PROJECT_ENVIRONMENT: ${{ runner.temp }}/binance-isolation-shadow-venv
run: |
set -euo pipefail
uv run --no-sync python scripts/run_isolation_shadow_fixture.py \
--output reports/runtime_isolation_shadow.json \
--digest-output reports/runtime_isolation_shadow.sha256

- name: Upload redacted current-runner shadow report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: runtime-isolation-shadow-current-runner-${{ github.run_id }}
path: |
reports/runtime_isolation_shadow.json
reports/runtime_isolation_shadow.sha256
if-no-files-found: error
retention-days: 7

compare-shadow-digests:
if: ${{ inputs.include_current_runner }}
needs: [fixed-input-shadow, current-runner-shadow]
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Download GitHub-hosted shadow evidence
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: runtime-isolation-shadow-github-${{ github.run_id }}
path: reports/github

- name: Download current-runner shadow evidence
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: runtime-isolation-shadow-current-runner-${{ github.run_id }}
path: reports/current-runner

- name: Compare semantic report digests
run: |
set -euo pipefail
cmp \
reports/github/runtime_isolation_shadow.sha256 \
reports/current-runner/runtime_isolation_shadow.sha256
echo "GitHub-hosted and current-runner no-order shadow digests match."
15 changes: 15 additions & 0 deletions docs/operator_runbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,21 @@ and rollback fence are documented in
informational until a separately reviewed live cutover is approved; the current
runtime remains authoritative.

Before selecting a replacement host, manually run `Runtime Isolation Host
Profile`. It has repository read permission only, receives no GitHub environment,
OIDC token, or secret, and writes a redacted artifact. Provider or network fields
that cannot be proven remain `UNVERIFIED`. To verify the current Binance
allowlisted egress without publishing the address, configure both
`BINANCE_RUNTIME_EGRESS_CHECK_URL` and `BINANCE_RUNTIME_EGRESS_SHA256`; the
workflow records only whether they match.

`Runtime Isolation Shadow Fixture` always runs the portable no-order fixture on
a clean GitHub-hosted runner. Set `include_current_runner=true` only outside the
live scheduling window to run the same fixture on the current self-hosted runner
and compare semantic report digests. Neither job references Binance credentials,
the `binance-runtime` environment, or Google OIDC. Passing proves fixture parity,
not live readiness or host ephemerality.

## Degraded Mode Ladder

Healthy mode:
Expand Down
Loading