From 820bda52eb0c7c6b4be4a5b491411097ff912643 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Thu, 10 Sep 2026 00:15:54 +0800 Subject: [PATCH] Allow manual SOXL job workflow identity Co-Authored-By: Codex --- .github/workflows/vps_codex_service_ops.yml | 2 +- scripts/deploy_codex_audit_service.sh | 2 +- tests/test_run_soxl_manual_learning.py | 21 ++++++++++++++++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.github/workflows/vps_codex_service_ops.yml b/.github/workflows/vps_codex_service_ops.yml index 1cab198f..12e4dc62 100644 --- a/.github/workflows/vps_codex_service_ops.yml +++ b/.github/workflows/vps_codex_service_ops.yml @@ -65,7 +65,7 @@ jobs: CODEX_AUDIT_SERVICE_ALLOWED_REFS: refs/heads/main # Exact canonical audit job plus immutable QPK `uses:` refs pinned by strategy drift callers. # Rotation tracked in #64; remove the old QPK SHA after final strategy-run verification. - CODEX_AUDIT_SERVICE_ALLOWED_JOB_WORKFLOW_REFS: QuantStrategyLab/AIAuditBridge/.github/workflows/codex_audit.yml@refs/heads/main,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@644cd9002ae92f2aaca6f7efb4afa4986fae05ea,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@d0a081ca5868faaf1a6dd870cf4b93643978cd11,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@fcddef20eea5deb876e739263042acdcb3e9cd1b,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@4f8465b28a6787d39d21e50f9d95a77841d6ad56,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@651c9ac4f37ce6e7fe1bac84dc7646cd5abc9e6e,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@bb91e4cad1a32d58dc0e4023f1cbe0c7ec150d81,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@6b887d9954eb656141597eac077ca22053a525ef,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@b939522701b527096e5d028346e777714466bcc5,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@8b8ce3543c04bf12920e38b0f45d2b32a8896580 + CODEX_AUDIT_SERVICE_ALLOWED_JOB_WORKFLOW_REFS: QuantStrategyLab/AIAuditBridge/.github/workflows/codex_audit.yml@refs/heads/main,QuantStrategyLab/AIAuditBridge/.github/workflows/research_input_readback.yml@refs/heads/main,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@644cd9002ae92f2aaca6f7efb4afa4986fae05ea,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@d0a081ca5868faaf1a6dd870cf4b93643978cd11,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@fcddef20eea5deb876e739263042acdcb3e9cd1b,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@4f8465b28a6787d39d21e50f9d95a77841d6ad56,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@651c9ac4f37ce6e7fe1bac84dc7646cd5abc9e6e,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@bb91e4cad1a32d58dc0e4023f1cbe0c7ec150d81,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@6b887d9954eb656141597eac077ca22053a525ef,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@b939522701b527096e5d028346e777714466bcc5,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@8b8ce3543c04bf12920e38b0f45d2b32a8896580 CODEX_AUDIT_SERVICE_ALLOWED_DIRECT_REPOSITORIES: QuantStrategyLab/AIAuditBridge CODEX_AUDIT_SERVICE_ALLOWED_SOURCE_REPOSITORIES: QuantStrategyLab/AIAuditBridge,QuantStrategyLab/BinancePlatform,QuantStrategyLab/CharlesSchwabPlatform,QuantStrategyLab/CnEquitySnapshotPipelines,QuantStrategyLab/CnEquityStrategies,QuantStrategyLab/CryptoLivePoolPipelines,QuantStrategyLab/CryptoStrategies,QuantStrategyLab/FirstradePlatform,QuantStrategyLab/HkEquitySnapshotPipelines,QuantStrategyLab/HkEquityStrategies,QuantStrategyLab/IBKRGatewayManager,QuantStrategyLab/InteractiveBrokersPlatform,QuantStrategyLab/LongBridgePlatform,QuantStrategyLab/MarketSignalSources,QuantStrategyLab/PoliticalEventTrackingResearch,QuantStrategyLab/QmtPlatform,QuantStrategyLab/QuantAdvisorResearch,QuantStrategyLab/QuantPlatformKit,QuantStrategyLab/QuantRuntimeSettings,QuantStrategyLab/QuantStrategyPlugins,QuantStrategyLab/ResearchSignalContextPipelines,QuantStrategyLab/SchwabTokenAutoRefresher,QuantStrategyLab/UsEquitySnapshotPipelines,QuantStrategyLab/UsEquityStrategies CODEX_AUDIT_SERVICE_MODEL: ${{ vars.CODEX_AUDIT_SERVICE_MODEL }} diff --git a/scripts/deploy_codex_audit_service.sh b/scripts/deploy_codex_audit_service.sh index f0a231f3..39d85c76 100644 --- a/scripts/deploy_codex_audit_service.sh +++ b/scripts/deploy_codex_audit_service.sh @@ -17,7 +17,7 @@ ALLOWED_REPOSITORY_VISIBILITIES="${CODEX_AUDIT_SERVICE_ALLOWED_REPOSITORY_VISIBI # Exact canonical audit job identity. Single source of truth for delegated drift code follows. # Rotation #64 removes the old SHA by 2026-07-18. # Rotate with the two-SHA procedure in docs/drift_oidc_rotation.md. -ALLOWED_JOB_WORKFLOW_REFS="${CODEX_AUDIT_SERVICE_ALLOWED_JOB_WORKFLOW_REFS:-QuantStrategyLab/AIAuditBridge/.github/workflows/codex_audit.yml@refs/heads/main,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@644cd9002ae92f2aaca6f7efb4afa4986fae05ea,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@d0a081ca5868faaf1a6dd870cf4b93643978cd11,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@fcddef20eea5deb876e739263042acdcb3e9cd1b,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@4f8465b28a6787d39d21e50f9d95a77841d6ad56,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@651c9ac4f37ce6e7fe1bac84dc7646cd5abc9e6e,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@bb91e4cad1a32d58dc0e4023f1cbe0c7ec150d81,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@6b887d9954eb656141597eac077ca22053a525ef,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@b939522701b527096e5d028346e777714466bcc5,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@8b8ce3543c04bf12920e38b0f45d2b32a8896580}" +ALLOWED_JOB_WORKFLOW_REFS="${CODEX_AUDIT_SERVICE_ALLOWED_JOB_WORKFLOW_REFS:-QuantStrategyLab/AIAuditBridge/.github/workflows/codex_audit.yml@refs/heads/main,QuantStrategyLab/AIAuditBridge/.github/workflows/research_input_readback.yml@refs/heads/main,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@644cd9002ae92f2aaca6f7efb4afa4986fae05ea,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@d0a081ca5868faaf1a6dd870cf4b93643978cd11,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@fcddef20eea5deb876e739263042acdcb3e9cd1b,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@4f8465b28a6787d39d21e50f9d95a77841d6ad56,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@651c9ac4f37ce6e7fe1bac84dc7646cd5abc9e6e,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@bb91e4cad1a32d58dc0e4023f1cbe0c7ec150d81,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@6b887d9954eb656141597eac077ca22053a525ef,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@b939522701b527096e5d028346e777714466bcc5,QuantStrategyLab/QuantPlatformKit/.github/workflows/reusable-drift-check.yml@8b8ce3543c04bf12920e38b0f45d2b32a8896580}" ALLOWED_DIRECT_REPOSITORIES="${CODEX_AUDIT_SERVICE_ALLOWED_DIRECT_REPOSITORIES:-QuantStrategyLab/AIAuditBridge}" ALLOWED_SOURCE_REPOSITORIES="${CODEX_AUDIT_SERVICE_ALLOWED_SOURCE_REPOSITORIES:-QuantStrategyLab/AIAuditBridge,QuantStrategyLab/BinancePlatform,QuantStrategyLab/CharlesSchwabPlatform,QuantStrategyLab/CnEquitySnapshotPipelines,QuantStrategyLab/CnEquityStrategies,QuantStrategyLab/CryptoLivePoolPipelines,QuantStrategyLab/CryptoStrategies,QuantStrategyLab/FirstradePlatform,QuantStrategyLab/HkEquitySnapshotPipelines,QuantStrategyLab/HkEquityStrategies,QuantStrategyLab/IBKRGatewayManager,QuantStrategyLab/InteractiveBrokersPlatform,QuantStrategyLab/LongBridgePlatform,QuantStrategyLab/MarketSignalSources,QuantStrategyLab/PoliticalEventTrackingResearch,QuantStrategyLab/QmtPlatform,QuantStrategyLab/QuantAdvisorResearch,QuantStrategyLab/QuantPlatformKit,QuantStrategyLab/QuantRuntimeSettings,QuantStrategyLab/QuantStrategyPlugins,QuantStrategyLab/ResearchSignalContextPipelines,QuantStrategyLab/SchwabTokenAutoRefresher,QuantStrategyLab/UsEquitySnapshotPipelines,QuantStrategyLab/UsEquityStrategies}" JOB_DIR="${CODEX_AUDIT_SERVICE_JOB_DIR:-/var/lib/codex-audit-bridge/jobs}" diff --git a/tests/test_run_soxl_manual_learning.py b/tests/test_run_soxl_manual_learning.py index ece08753..411d6e51 100644 --- a/tests/test_run_soxl_manual_learning.py +++ b/tests/test_run_soxl_manual_learning.py @@ -349,18 +349,31 @@ def test_gateway_auth_accepts_only_the_exact_manual_workflow_on_main() -> None: "QuantStrategyLab/AIAuditBridge/.github/workflows/" "research_input_readback.yml@refs/heads/main" ) + deploy_text = Path("scripts/deploy_codex_audit_service.sh").read_text() + ops_text = Path(".github/workflows/vps_codex_service_ops.yml").read_text() + deploy_prefix = ( + 'ALLOWED_JOB_WORKFLOW_REFS="${CODEX_AUDIT_SERVICE_ALLOWED_JOB_WORKFLOW_REFS:-' + ) + deploy_line = next(line for line in deploy_text.splitlines() if line.startswith(deploy_prefix)) + deployed_job_refs = deploy_line.removeprefix(deploy_prefix).removesuffix('}"') + ops_prefix = "CODEX_AUDIT_SERVICE_ALLOWED_JOB_WORKFLOW_REFS: " + ops_line = next(line.strip() for line in ops_text.splitlines() if line.strip().startswith(ops_prefix)) + assert deployed_job_refs == ops_line.removeprefix(ops_prefix) + payload = { "aud": "quant-codex-audit", "iss": codex_audit_service.GITHUB_OIDC_ISSUER, "exp": int(time.time()) + 300, "repository": "QuantStrategyLab/AIAuditBridge", "workflow_ref": workflow_ref, + "job_workflow_ref": workflow_ref, "ref": "refs/heads/main", "repository_visibility": "public", } env = { "CODEX_AUDIT_SERVICE_ALLOWED_REPOSITORIES": "QuantStrategyLab/AIAuditBridge", "CODEX_AUDIT_SERVICE_ALLOWED_WORKFLOW_REFS": workflow_ref, + "CODEX_AUDIT_SERVICE_ALLOWED_JOB_WORKFLOW_REFS": deployed_job_refs, "CODEX_AUDIT_SERVICE_ALLOWED_REFS": "refs/heads/main", "CODEX_AUDIT_SERVICE_ALLOWED_DIRECT_REPOSITORIES": "QuantStrategyLab/AIAuditBridge", "CODEX_AUDIT_SERVICE_ALLOWED_REPOSITORY_VISIBILITIES": "public", @@ -384,5 +397,11 @@ def verify(active: dict[str, object]) -> dict[str, object]: return codex_audit_service._verify_github_oidc("header.payload.signature") assert verify(payload)["workflow_ref"] == workflow_ref + assert verify({key: value for key, value in payload.items() if key != "job_workflow_ref"})[ + "workflow_ref" + ] == workflow_ref + with pytest.raises(PermissionError, match="job workflow ref .* not allowed"): + verify(payload | {"job_workflow_ref": workflow_ref.replace("refs/heads/main", "refs/heads/other")}) + other_ref = workflow_ref.replace("refs/heads/main", "refs/heads/other") with pytest.raises(PermissionError, match="workflow_ref .* not allowed"): - verify(payload | {"workflow_ref": workflow_ref.replace("refs/heads/main", "refs/heads/other")}) + verify(payload | {"workflow_ref": other_ref, "job_workflow_ref": other_ref, "ref": "refs/heads/other"})