ci(mantis): allow fork telegram proof

This commit is contained in:
Ayaan Zaidi
2026-05-11 17:27:32 +05:30
parent e6b0b37e3f
commit d4c7519989
4 changed files with 104 additions and 5 deletions

View File

@@ -24,6 +24,7 @@ Inputs are provided as environment variables:
- `BASELINE_SHA`
- `CANDIDATE_REF`
- `CANDIDATE_SHA`
- `MANTIS_CANDIDATE_TRUST`
- `MANTIS_OUTPUT_DIR`
- `MANTIS_INSTRUCTIONS`
- `CRABBOX_PROVIDER`
@@ -44,6 +45,12 @@ Required workflow:
`.artifacts/qa-e2e/mantis/telegram-desktop-proof-worktrees/baseline` and
`.artifacts/qa-e2e/mantis/telegram-desktop-proof-worktrees/candidate`, then
install and build each worktree with the repo's normal `pnpm` commands.
If `MANTIS_CANDIDATE_TRUST` is `maintainer-approved-fork-pr-head`, treat the
candidate worktree as untrusted fork code: do not pass GitHub, OpenAI,
Crabbox, Convex, or other workflow secrets into candidate install, build, or
runtime commands. The candidate SUT may receive only the proof runner's
short-lived Telegram bot token, generated local config/state paths, and mock
model key needed for this isolated proof.
5. In each worktree, run the real-user Telegram Crabbox proof flow from the
skill with `$OPENCLAW_TELEGRAM_USER_PROOF_CMD`; do not run
`pnpm qa:telegram-user:crabbox` directly. The proof command comes from the

View File

@@ -35,6 +35,11 @@ on:
description: Optional existing Crabbox desktop lease id or slug to reuse
required: false
type: string
allow_fork_candidate:
description: Allow a fork PR head candidate when pr_number points at that PR
required: false
default: false
type: boolean
permissions:
contents: write
@@ -95,6 +100,7 @@ jobs:
needs: authorize_actor
runs-on: ubuntu-24.04
outputs:
allow_fork_candidate: ${{ steps.resolve.outputs.allow_fork_candidate }}
baseline_ref: ${{ steps.resolve.outputs.baseline_ref }}
candidate_ref: ${{ steps.resolve.outputs.candidate_ref }}
crabbox_provider: ${{ steps.resolve.outputs.crabbox_provider }}
@@ -119,6 +125,10 @@ jobs:
if (eventName === "workflow_dispatch") {
const inputs = context.payload.inputs ?? {};
setOutput("should_run", "true");
setOutput(
"allow_fork_candidate",
String(inputs.allow_fork_candidate) === "true" ? "true" : "false",
);
setOutput("baseline_ref", inputs.baseline_ref || "main");
setOutput("candidate_ref", inputs.candidate_ref || "main");
setOutput("pr_number", inputs.pr_number || "");
@@ -150,6 +160,7 @@ jobs:
if (!requested) {
core.notice("Comment mentioned Mantis but did not request Telegram desktop proof.");
setOutput("should_run", "false");
setOutput("allow_fork_candidate", "false");
setOutput("baseline_ref", "");
setOutput("candidate_ref", "");
setOutput("pr_number", "");
@@ -192,8 +203,10 @@ jobs:
rawCandidate && !["head", "pr", "pr-head"].includes(rawCandidate.toLowerCase())
? rawCandidate
: mergedCandidate || pr.head.sha;
const allowForkCandidate = /\bfork[-_]ok\b/i.test(body);
setOutput("should_run", "true");
setOutput("allow_fork_candidate", allowForkCandidate ? "true" : "false");
setOutput("baseline_ref", baselineMatch?.[1] || mergedBaseline || "main");
setOutput("candidate_ref", candidate);
setOutput("pr_number", String(issue.number));
@@ -217,6 +230,7 @@ jobs:
outputs:
baseline_revision: ${{ steps.validate.outputs.baseline_revision }}
candidate_revision: ${{ steps.validate.outputs.candidate_revision }}
candidate_trust: ${{ steps.validate.outputs.candidate_trust }}
steps:
- name: Checkout harness ref
uses: actions/checkout@v6
@@ -227,6 +241,7 @@ jobs:
- name: Validate refs are trusted
id: validate
env:
ALLOW_FORK_CANDIDATE: ${{ needs.resolve_request.outputs.allow_fork_candidate }}
BASELINE_REF: ${{ needs.resolve_request.outputs.baseline_ref }}
CANDIDATE_REF: ${{ needs.resolve_request.outputs.candidate_ref }}
GH_TOKEN: ${{ github.token }}
@@ -264,25 +279,43 @@ jobs:
)"
if [[ "$pr_head_count" != "0" ]]; then
reason="open-pr-head"
elif [[ "$label" == "candidate" && "${ALLOW_FORK_CANDIDATE:-false}" == "true" && -n "${PR_NUMBER:-}" ]]; then
local fork_pr_head_count
fork_pr_head_count="$(
gh api \
-H "Accept: application/vnd.github+json" \
"repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}" \
--jq 'if .state == "open" and .head.repo.full_name != "'"${GITHUB_REPOSITORY}"'" and .head.sha == "'"${revision}"'" then 1 else 0 end'
)"
if [[ "$fork_pr_head_count" == "1" ]]; then
reason="maintainer-approved-fork-pr-head"
fi
fi
fi
if [[ -z "$reason" ]]; then
echo "${label} ref '${input_ref}' resolved to ${revision}, which is not trusted for this secret-bearing Mantis run." >&2
echo "${label} ref '${input_ref}' resolved to ${revision}, which is not trusted for this secret-bearing Mantis run. Add fork-ok only for a maintainer-approved fork PR head." >&2
exit 1
fi
printf '%s\n' "$revision"
printf '%s\t%s\n' "$revision" "$reason"
}
baseline_revision="$(validate_ref baseline "$BASELINE_REF")"
baseline_trust="${baseline_revision#*$'\t'}"
baseline_revision="${baseline_revision%%$'\t'*}"
candidate_revision="$(validate_ref candidate "$CANDIDATE_REF")"
candidate_trust="${candidate_revision#*$'\t'}"
candidate_revision="${candidate_revision%%$'\t'*}"
echo "baseline_revision=${baseline_revision}" >> "$GITHUB_OUTPUT"
echo "candidate_revision=${candidate_revision}" >> "$GITHUB_OUTPUT"
echo "candidate_trust=${candidate_trust}" >> "$GITHUB_OUTPUT"
{
echo "baseline: \`${BASELINE_REF}\`"
echo "baseline SHA: \`${baseline_revision}\`"
echo "baseline trust: \`${baseline_trust}\`"
echo "candidate: \`${CANDIDATE_REF}\`"
echo "candidate SHA: \`${candidate_revision}\`"
echo "candidate trust: \`${candidate_trust}\`"
} >> "$GITHUB_STEP_SUMMARY"
run_telegram_desktop_proof:
@@ -375,7 +408,7 @@ jobs:
printf '%s\n' 'Defaults env_keep += "CODEX_HOME CODEX_INTERNAL_ORIGINATOR_OVERRIDE"'
printf '%s\n' 'Defaults env_keep += "BASELINE_REF BASELINE_SHA CANDIDATE_REF CANDIDATE_SHA"'
printf '%s\n' 'Defaults env_keep += "CRABBOX_ACCESS_CLIENT_ID CRABBOX_ACCESS_CLIENT_SECRET CRABBOX_COORDINATOR CRABBOX_COORDINATOR_TOKEN CRABBOX_LEASE_ID CRABBOX_PROVIDER"'
printf '%s\n' 'Defaults env_keep += "GH_TOKEN MANTIS_INSTRUCTIONS MANTIS_OUTPUT_DIR MANTIS_PR_NUMBER"'
printf '%s\n' 'Defaults env_keep += "GH_TOKEN MANTIS_CANDIDATE_TRUST MANTIS_INSTRUCTIONS MANTIS_OUTPUT_DIR MANTIS_PR_NUMBER"'
printf '%s\n' 'Defaults env_keep += "OPENCLAW_BUILD_PRIVATE_QA OPENCLAW_ENABLE_PRIVATE_QA_CLI OPENCLAW_QA_CONVEX_SECRET_CI OPENCLAW_QA_CONVEX_SITE_URL OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR_TOKEN"'
printf '%s\n' 'Defaults env_keep += "OPENCLAW_TELEGRAM_USER_CRABBOX_BIN OPENCLAW_TELEGRAM_USER_CRABBOX_PROVIDER OPENCLAW_TELEGRAM_USER_DRIVER_SCRIPT OPENCLAW_TELEGRAM_USER_PROOF_CMD"'
} | sudo tee /etc/sudoers.d/mantis-codex-env >/dev/null
@@ -406,6 +439,7 @@ jobs:
CRABBOX_LEASE_ID: ${{ needs.resolve_request.outputs.lease_id }}
CRABBOX_PROVIDER: ${{ needs.resolve_request.outputs.crabbox_provider }}
GH_TOKEN: ${{ github.token }}
MANTIS_CANDIDATE_TRUST: ${{ needs.validate_refs.outputs.candidate_trust }}
MANTIS_INSTRUCTIONS: ${{ needs.resolve_request.outputs.instructions }}
MANTIS_OUTPUT_DIR: ${{ env.MANTIS_OUTPUT_DIR }}
MANTIS_PR_NUMBER: ${{ needs.resolve_request.outputs.pr_number }}