name: Formal models (informational conformance) on: pull_request: concurrency: group: formal-conformance-${{ github.event.pull_request.number || github.ref_name }} cancel-in-progress: true jobs: formal_conformance: runs-on: ubuntu-latest timeout-minutes: 20 permissions: contents: read pull-requests: write steps: - name: Checkout openclaw (PR) uses: actions/checkout@v4 with: path: openclaw - name: Checkout formal models uses: actions/checkout@v4 with: repository: vignesh07/clawdbot-formal-models ref: main path: clawdbot-formal-models - name: Setup Node uses: actions/setup-node@v4 with: node-version: "22" - name: Regenerate extracted constants from openclaw run: | set -euo pipefail cd clawdbot-formal-models export OPENCLAW_REPO_DIR="${GITHUB_WORKSPACE}/openclaw" node scripts/extract-tool-groups.mjs node scripts/check-tool-group-alias.mjs # Drift is about extracted artifacts only; compute it before model checking # to avoid any incidental file touches affecting the result. - name: Compute drift (generated/*) id: drift run: | set -euo pipefail cd clawdbot-formal-models if git diff --quiet -- generated; then echo "drift=false" >> "$GITHUB_OUTPUT" exit 0 fi echo "drift=true" >> "$GITHUB_OUTPUT" git diff -- generated > "${GITHUB_WORKSPACE}/formal-models-drift.diff" - name: Model check (green suite) run: | set -euo pipefail cd clawdbot-formal-models make \ precedence groups elevated nodes-policy \ attacker approvals approvals-token nodes-pipeline \ gateway-exposure gateway-exposure-v2 gateway-exposure-v2-protected \ gateway-auth-conformance gateway-auth-tailscale gateway-auth-proxy \ pairing pairing-cap pairing-idempotency pairing-refresh pairing-refresh-race \ ingress-gating ingress-idempotency ingress-dedupe-fallback ingress-trace ingress-trace2 \ routing-isolation routing-precedence routing-identitylinks routing-identity-transitive routing-identity-symmetry routing-identity-channel-override \ routing-thread-parent discord-pluralkit \ ingress-retry session-key-stability session-explosion-bound config-normalization \ queue-drain delivery-route-stability delivery-pipeline retry-termination retry-eventual-success \ no-cross-stream multi-event-eventual-emission \ dedupe-collision-fallback crash-restart-dedupe two-worker-dedupe openclaw-session-key-conformance \ routing-thread-parent-channel-override routing-trirule gateway-auth-proxy-header-spoof \ group-alias-check - name: Model check (negative suite, expected violations) continue-on-error: true run: | set -euo pipefail cd clawdbot-formal-models make -k \ precedence-negative groups-negative elevated-negative nodes-policy-negative \ attacker-negative attacker-nodes-negative attacker-nodes-allowlist-negative attacker-nodes-allowlist-negative \ approvals-negative approvals-token-negative nodes-pipeline-negative \ gateway-exposure-negative gateway-exposure-v2-negative gateway-exposure-v2-protected-negative \ gateway-exposure-v2-unsafe-custom gateway-exposure-v2-unsafe-tailnet gateway-exposure-v2-unsafe-auto \ gateway-auth-conformance-negative gateway-auth-tailscale-negative gateway-auth-proxy-negative \ pairing-negative pairing-cap-negative pairing-idempotency-negative pairing-refresh-negative pairing-refresh-race-negative \ ingress-gating-negative ingress-idempotency-negative ingress-dedupe-fallback-negative ingress-trace-negative ingress-trace2-negative \ routing-isolation-negative routing-precedence-negative routing-identitylinks-negative routing-identity-transitive-negative routing-identity-symmetry-negative routing-identity-channel-override-negative \ routing-thread-parent-negative discord-pluralkit-negative \ ingress-retry-negative session-key-stability-negative config-normalization-negative \ queue-drain delivery-route-stability-negative delivery-pipeline-negative retry-termination-negative retry-eventual-success-negative \ no-cross-stream-negative multi-event-eventual-emission-negative \ dedupe-collision-fallback-negative crash-restart-dedupe-negative two-worker-dedupe-negative openclaw-session-key-conformance-negative \ routing-thread-parent-channel-override-negative routing-trirule-negative gateway-auth-proxy-header-spoof-negative - name: Upload drift diff artifact if: steps.drift.outputs.drift == 'true' uses: actions/upload-artifact@v4 with: name: formal-models-conformance-drift path: formal-models-drift.diff - name: Comment on PR (informational) if: steps.drift.outputs.drift == 'true' uses: actions/github-script@v7 with: script: | const body = [ '⚠️ **Formal models conformance drift detected**', '', 'The formal models extracted constants (`generated/*`) do not match this openclaw PR.', '', 'This check is **informational** (not blocking merges yet).', 'See the `formal-models-conformance-drift` artifact for the diff.', '', 'If this change is intentional, follow up by updating the formal models repo or regenerating the extracted artifacts there.', ].join('\n'); await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number, body, }); - name: Summary run: | if [ "${{ steps.drift.outputs.drift }}" = "true" ]; then echo "Formal conformance drift detected (informational)." else echo "Formal conformance: no drift." fi