Skip to content

Commit aca1f3d

Browse files
authored
Merge branch 'main' into fix-provider-timeout-overlay-83201
2 parents 7c85812 + b86435f commit aca1f3d

371 files changed

Lines changed: 10349 additions & 1410 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
name: openclaw-mac-release
3+
description: "Run or recover OpenClaw macOS release signing, notarization, appcast, and asset promotion."
4+
---
5+
6+
# OpenClaw Mac Release
7+
8+
Use with `$openclaw-release-maintainer`, `$openclaw-release-ci`, and `$one-password` when stable macOS assets, private mac preflight, notarization, appcast promotion, or mac release recovery is involved.
9+
10+
## Credentials
11+
12+
- Canonical ASC item: vault `Molty`, title `API Key - App Store Connect - Personal - Release`.
13+
- Fields: `private_key_p8`, `key_id`, `issuer_id`.
14+
- Current known good key id: `AKVLXW849T`.
15+
- Legacy mirror: vault `Private`, title `API Key - App Store Connect - Personal`; keep it synced for older refs.
16+
- Stale/revoked key symptom: `xcrun notarytool submit` fails with `HTTP status code: 401. Unauthenticated`.
17+
- Validate candidate ASC credentials with `xcrun notarytool history` before setting GitHub secrets.
18+
19+
## 1Password
20+
21+
- Use `$one-password`: all `op` work inside one persistent tmux session, no secret output.
22+
- Prefer `OP_SERVICE_ACCOUNT_TOKEN` from `~/.profile` for Molty reads.
23+
- Do not assume `MOLTY_OP_SERVICE_ACCOUNT_TOKEN` is alive; it has previously pointed at a deleted service account.
24+
- If a service token fails, run status-only checks: token present/length and `op whoami`; never print token values.
25+
- If desktop app auth is needed but Touch ID is unavailable, set `OP_BIOMETRIC_UNLOCK_ENABLED=false` for the manual `op account add --signin` path.
26+
27+
## GitHub Secrets
28+
29+
Target private repo environment: `openclaw/releases-private`, env `mac-release`.
30+
31+
Set only after local notary auth validation:
32+
33+
- `APP_STORE_CONNECT_API_KEY_P8`
34+
- `APP_STORE_CONNECT_KEY_ID`
35+
- `APP_STORE_CONNECT_ISSUER_ID`
36+
37+
Do not update these from mixed sources. All three ASC fields must come from the same 1Password item.
38+
39+
## Workflow Shape
40+
41+
- Public release branch may carry mac-only packaging fixes after the stable tag/npm are already live.
42+
- Use `source_ref=release/YYYY.M.D` for private mac preflight/validation when building that branch variation.
43+
- Keep `tag=vYYYY.M.D` pointing at the original stable release commit.
44+
- Real mac publish must reuse:
45+
- a successful private mac preflight run for the same tag/source SHA
46+
- a successful private mac validation run for the same tag/source SHA
47+
- If preflight source SHA differs from tag SHA, validation must also use the same `source_ref`; promotion rejects mismatched proof.
48+
49+
## Notarization
50+
51+
- OpenClaw uses `scripts/notarize-mac-artifact.sh`.
52+
- `xcrun notarytool submit` should use `--no-s3-acceleration`; accelerated upload can surface misleading 401s even when `notarytool history` succeeds.
53+
- If signing succeeds but notarization fails immediately with 401, check ASC key freshness first.
54+
- If notarization stays in progress for several minutes after key-file write, that is normal Apple wait time; do not edit blindly.
55+
56+
## Dispatch
57+
58+
Private preflight:
59+
60+
```bash
61+
gh workflow run openclaw-macos-publish.yml --repo openclaw/releases-private --ref main \
62+
-f tag=vYYYY.M.D \
63+
-f source_ref=release/YYYY.M.D \
64+
-f preflight_only=true \
65+
-f smoke_test_only=false \
66+
-f allow_late_calver_recovery=false \
67+
-f public_release_branch=release/YYYY.M.D
68+
```
69+
70+
Private validation for a branch-variation preflight:
71+
72+
```bash
73+
gh workflow run openclaw-macos-validate.yml --repo openclaw/releases-private --ref main \
74+
-f tag=vYYYY.M.D \
75+
-f source_ref=release/YYYY.M.D
76+
```
77+
78+
Real publish:
79+
80+
```bash
81+
gh workflow run openclaw-macos-publish.yml --repo openclaw/releases-private --ref main \
82+
-f tag=vYYYY.M.D \
83+
-f preflight_only=false \
84+
-f smoke_test_only=false \
85+
-f preflight_run_id=<successful-preflight-run> \
86+
-f validate_run_id=<successful-validation-run> \
87+
-f allow_late_calver_recovery=false \
88+
-f public_release_branch=release/YYYY.M.D
89+
```
90+
91+
## Verify
92+
93+
- `gh release view vYYYY.M.D --repo openclaw/openclaw` shows zip, dmg, dSYM zip, not draft, not prerelease.
94+
- Public `main` `appcast.xml` points at `OpenClaw-YYYY.M.D.zip`.
95+
- Appcast entry has `sparkle:version`, `sparkle:shortVersionString`, length, and `sparkle:edSignature`.

.github/codex/prompts/mantis-telegram-desktop-proof.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,10 @@ than Telegram-visible behavior`. Use this manifest shape and do not create
119119
`$OPENCLAW_TELEGRAM_USER_DRIVER_SCRIPT`, the workflow-provided `crabbox`
120120
binary, and the workflow-provided local `ffmpeg`/`ffprobe`; do not generate,
121121
install, or patch replacement proof tooling during the run. Use the same
122-
proof idea for baseline and candidate. You may iterate and rerun if the
123-
visual result is not convincing.
122+
proof idea for baseline and candidate. Let `start` return or fail on its
123+
own; do not kill it while Crabbox is still waiting for bootstrap. Use a long
124+
command timeout for `start`, `send`, `view`, and `finish`. You may iterate
125+
and rerun if the visual result is not convincing.
124126
7. Open Telegram Desktop directly to the newest relevant message with the
125127
runner `view` command before finishing each recording. Keep the chat scrolled
126128
to the bottom so new proof messages appear in-frame.

.github/workflows/mantis-telegram-desktop-proof.yml

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -308,16 +308,36 @@ jobs:
308308
run: |
309309
set -euo pipefail
310310
current_created="$(gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" --jq .created_at)"
311+
stale_before="$(date -u -d '8 hours ago' +%Y-%m-%dT%H:%M:%SZ)"
312+
run_has_active_jobs() {
313+
local run_id="$1"
314+
local run_state="$2"
315+
if [[ "$run_state" != "in_progress" ]]; then
316+
return 0
317+
fi
318+
local active_jobs
319+
active_jobs="$(gh run view "$run_id" --repo "$GITHUB_REPOSITORY" --json jobs --jq '[.jobs[] | select(.status == "queued" or .status == "in_progress" or .status == "waiting" or .status == "pending" or .status == "requested")] | length')"
320+
[[ "$active_jobs" != "0" ]]
321+
}
311322
while true; do
312-
blockers="$(
323+
candidates="$(
313324
for workflow in mantis-telegram-desktop-proof.yml mantis-telegram-live.yml; do
314-
gh run list --repo "$GITHUB_REPOSITORY" --workflow "$workflow" --limit 100 --json databaseId,status,createdAt,url \
315-
| jq -r \
316-
--argjson current_id "$GITHUB_RUN_ID" \
317-
--arg current_created "$current_created" \
318-
'.[] | select(.databaseId != $current_id) | select(.createdAt < $current_created or (.createdAt == $current_created and .databaseId < $current_id)) | select(.status == "queued" or .status == "in_progress" or .status == "waiting" or .status == "pending" or .status == "requested") | "\(.createdAt)\t#\(.databaseId)\t\(.status)\t\(.url)"'
325+
for status in queued in_progress waiting pending requested; do
326+
gh run list --repo "$GITHUB_REPOSITORY" --workflow "$workflow" --status "$status" --limit 100 --json databaseId,status,createdAt,url \
327+
| jq -r \
328+
--argjson current_id "$GITHUB_RUN_ID" \
329+
--arg current_created "$current_created" \
330+
--arg stale_before "$stale_before" \
331+
'.[] | select(.databaseId != $current_id) | select(.createdAt >= $stale_before) | select(.createdAt < $current_created or (.createdAt == $current_created and .databaseId < $current_id)) | "\(.createdAt)\t#\(.databaseId)\t\(.status)\t\(.url)"'
332+
done
319333
done | sort -u
320334
)"
335+
blockers=""
336+
while IFS=$'\t' read -r created run_id run_state url; do
337+
if [[ -n "$run_id" ]] && run_has_active_jobs "${run_id#\#}" "$run_state"; then
338+
blockers+="${created}"$'\t'"${run_id}"$'\t'"${run_state}"$'\t'"${url}"$'\n'
339+
fi
340+
done <<<"$candidates"
321341
if [[ -z "$blockers" ]]; then
322342
break
323343
fi

.github/workflows/mantis-telegram-live.yml

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -272,16 +272,36 @@ jobs:
272272
run: |
273273
set -euo pipefail
274274
current_created="$(gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" --jq .created_at)"
275+
stale_before="$(date -u -d '8 hours ago' +%Y-%m-%dT%H:%M:%SZ)"
276+
run_has_active_jobs() {
277+
local run_id="$1"
278+
local run_state="$2"
279+
if [[ "$run_state" != "in_progress" ]]; then
280+
return 0
281+
fi
282+
local active_jobs
283+
active_jobs="$(gh run view "$run_id" --repo "$GITHUB_REPOSITORY" --json jobs --jq '[.jobs[] | select(.status == "queued" or .status == "in_progress" or .status == "waiting" or .status == "pending" or .status == "requested")] | length')"
284+
[[ "$active_jobs" != "0" ]]
285+
}
275286
while true; do
276-
blockers="$(
287+
candidates="$(
277288
for workflow in mantis-telegram-desktop-proof.yml mantis-telegram-live.yml; do
278-
gh run list --repo "$GITHUB_REPOSITORY" --workflow "$workflow" --limit 100 --json databaseId,status,createdAt,url \
279-
| jq -r \
280-
--argjson current_id "$GITHUB_RUN_ID" \
281-
--arg current_created "$current_created" \
282-
'.[] | select(.databaseId != $current_id) | select(.createdAt < $current_created or (.createdAt == $current_created and .databaseId < $current_id)) | select(.status == "queued" or .status == "in_progress" or .status == "waiting" or .status == "pending" or .status == "requested") | "\(.createdAt)\t#\(.databaseId)\t\(.status)\t\(.url)"'
289+
for status in queued in_progress waiting pending requested; do
290+
gh run list --repo "$GITHUB_REPOSITORY" --workflow "$workflow" --status "$status" --limit 100 --json databaseId,status,createdAt,url \
291+
| jq -r \
292+
--argjson current_id "$GITHUB_RUN_ID" \
293+
--arg current_created "$current_created" \
294+
--arg stale_before "$stale_before" \
295+
'.[] | select(.databaseId != $current_id) | select(.createdAt >= $stale_before) | select(.createdAt < $current_created or (.createdAt == $current_created and .databaseId < $current_id)) | "\(.createdAt)\t#\(.databaseId)\t\(.status)\t\(.url)"'
296+
done
283297
done | sort -u
284298
)"
299+
blockers=""
300+
while IFS=$'\t' read -r created run_id run_state url; do
301+
if [[ -n "$run_id" ]] && run_has_active_jobs "${run_id#\#}" "$run_state"; then
302+
blockers+="${created}"$'\t'"${run_id}"$'\t'"${run_state}"$'\t'"${url}"$'\n'
303+
fi
304+
done <<<"$candidates"
285305
if [[ -z "$blockers" ]]; then
286306
break
287307
fi

.github/workflows/openclaw-live-and-e2e-checks-reusable.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,9 +321,6 @@ jobs:
321321
set -euo pipefail
322322
trusted_reason=""
323323
324-
git fetch --no-tags origin '+refs/heads/*:refs/remotes/origin/*'
325-
git fetch --tags origin '+refs/tags/*:refs/tags/*'
326-
327324
# Resolve here instead of in actions/checkout so short SHAs work too.
328325
if ! selected_sha="$(git rev-parse --verify "${INPUT_REF}^{commit}")"; then
329326
echo "Ref '${INPUT_REF}' could not be resolved to a commit." >&2

0 commit comments

Comments
 (0)