Skip to content

Commit a2fdea7

Browse files
author
Duncan
committed
Merge remote-tracking branch 'origin/main' into wpfleger/desktop-admin-surface
* origin/main: fix(desktop): back split thread headers (#7137) add public descriptions to agent personas (#7126) feat(desktop): add protected-build Bestie experiment (#6902) fix(relay): reject a frame on its own acknowledgement channel (#6961) fix(acp): wake agents from workflow messages (#6953) feat: render agent avatars as squircles (#7106) fix(ci): salvage Codex review output on PTY-shutdown hang (#7042) fix: retrieving cold memories; add regression task (#6950) Enforce NIP-OA authorization time bounds (#7004) feat(db): configurable writer session timeouts (lock, idle-txn, statement) (#6229) feat(desktop): use segmented controls for channel creation (#6845) feat(buzz-agent): surface stop reason and silent-turn WARN in telemetry (#7038) fix(desktop): surface channel history load failures (#7013) fix(composer): polish automatic mentions (#6956) fix(desktop): resolve bundled sidecar on cheap path and bound login-shell spawns (#6904) perf(mobile): reduce cold startup and channel rendering delays (#6996) feat(mobile): push notifications MVP (#6269) Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
2 parents b522404 + b47b5a5 commit a2fdea7

470 files changed

Lines changed: 31922 additions & 2942 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.

.env.example

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,21 @@ REDIS_URL=redis://localhost:6379
3838
# READ_DATABASE_URL is set, reader (default 50).
3939
# BUZZ_DB_POOL_SIZE=50
4040

41+
# Writer-session Postgres timeouts for buzz-db-backed pools and the relay audit
42+
# pool, all in milliseconds; 0 disables. The separately deployed push gateway
43+
# owns its own database and session policy and does not consume these knobs.
44+
# lock_timeout: fail a statement that waits this long on any lock instead of
45+
# parking behind a wedged holder (default 5000).
46+
# BUZZ_DB_LOCK_TIMEOUT_MS=5000
47+
# idle_in_transaction_session_timeout: reap sessions idle inside an open
48+
# transaction — bounds how long a wedged client can hold locks (default 60000).
49+
# BUZZ_DB_IDLE_TXN_TIMEOUT_MS=60000
50+
# statement_timeout: cap any single statement's runtime. Off by default —
51+
# startup migrations/backfills legitimately run long statements. Warning: a
52+
# pathologically low value (e.g. 1) also times out connection setup and can
53+
# prevent any DB connection from establishing.
54+
# BUZZ_DB_STATEMENT_TIMEOUT_MS=0
55+
4156
# -----------------------------------------------------------------------------
4257
# Typesense (search)
4358
# -----------------------------------------------------------------------------
@@ -59,6 +74,12 @@ RELAY_URL=ws://localhost:3000
5974
# (use `just web` for Vite HMR instead).
6075
# BUZZ_WEB_DIR=./web/dist
6176

77+
# NIP-PL mobile push is an explicit deployment opt-in. A gateway URL alone
78+
# never enables it. When enabled and the URL is absent, the canonical
79+
# https://push.buzz.xyz/v1/deliveries/apns endpoint is used.
80+
BUZZ_PUSH_ENABLED=false
81+
# BUZZ_PUSH_GATEWAY_DELIVERY_URL=https://push.buzz.xyz/v1/deliveries/apns
82+
6283
# -----------------------------------------------------------------------------
6384
# Admin Dashboard (private moderation surface)
6485
# -----------------------------------------------------------------------------
@@ -253,6 +274,10 @@ RUST_LOG=buzz_relay=debug,buzz_datastore=info,buzz_db=debug,buzz_auth=debug,buzz
253274
# app launch while keeping the current identity and relay data.
254275
# VITE_BUZZ_FORCE_FRESH_ONBOARDING=true
255276

277+
# Protected internal builds only: selects the module graph that contains the
278+
# default-off Bestie experiment. Official OSS builds must leave this unset.
279+
# VITE_BUZZ_BESTIE=1
280+
256281
# ── Subscription & filtering ─────────────────────────────────────────────────
257282
# Subscribe mode: "mentions" (default), "all", or "config" (rule-based).
258283
# BUZZ_ACP_SUBSCRIBE=mentions

.github/workflows/ci.yml

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ jobs:
304304
name: Desktop
305305
runs-on: ubuntu-latest
306306
timeout-minutes: 5
307-
needs: [changes, desktop-core, desktop-smoke-e2e]
307+
needs: [changes, desktop-core, desktop-smoke-e2e, desktop-windows-build]
308308
if: always() && (github.event_name == 'push' || needs.changes.outputs.desktop == 'true' || needs.changes.outputs.desktop-rust == 'true' || needs.changes.outputs.rust == 'true')
309309
permissions:
310310
contents: read
@@ -319,6 +319,10 @@ jobs:
319319
echo "Desktop Smoke E2E shards finished with: ${{ needs.desktop-smoke-e2e.result }}"
320320
exit 1
321321
fi
322+
if [ "${{ needs.desktop-windows-build.result }}" != "success" ]; then
323+
echo "Desktop Windows Build finished with: ${{ needs.desktop-windows-build.result }}"
324+
exit 1
325+
fi
322326
echo "Desktop jobs passed"
323327
324328
desktop-e2e-relay:
@@ -380,6 +384,7 @@ jobs:
380384
-p buzz-relay \
381385
-p buzz-test-client \
382386
--lib \
387+
--bin buzz-relay \
383388
--test e2e_event_reminder \
384389
--archive-file target/ci/backend-integration-tests.tar.zst
385390
- name: Save relay artifacts cache
@@ -684,6 +689,18 @@ jobs:
684689
VALUES ('00000000-0000-4000-8000-00000000c0de', 'localhost:3000')
685690
ON CONFLICT (lower(host)) DO NOTHING
686691
;"
692+
- name: Workflow message provenance tests
693+
# The relay's workflow_sink suite is not selected by the infra-free
694+
# unit job. Run both its pure tests and ignored PostgreSQL tests here so
695+
# authored-template provenance cannot regress behind a green CI build.
696+
run: |
697+
cargo nextest run \
698+
--archive-file target/ci/backend-integration-tests.tar.zst \
699+
-E 'package(buzz-relay) and test(/workflow_sink/)' \
700+
--run-ignored all
701+
env:
702+
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
703+
TEST_DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
687704
- name: Replaceable persistence PostgreSQL tests
688705
# Transaction, concurrency, and mention-index coverage for the
689706
# replaceable-event store seam. These tests require real Postgres and
@@ -709,6 +726,31 @@ jobs:
709726
env:
710727
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
711728
TEST_DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
729+
- name: Writer session timeout guardrails
730+
run: |
731+
cargo nextest run \
732+
--archive-file target/ci/backend-integration-tests.tar.zst \
733+
-E 'package(buzz-db) and test(session_timeouts_install_through_db_new_and_bound_lock_waits)' \
734+
--run-ignored ignored-only
735+
env:
736+
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
737+
TEST_DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
738+
- name: Audit writer session timeout guardrails
739+
run: |
740+
cargo nextest run \
741+
--archive-file target/ci/backend-integration-tests.tar.zst \
742+
-E 'package(buzz-relay) and test(audit_writer_pool_installs_timeouts_and_bounds_advisory_lock_waits)' \
743+
--run-ignored ignored-only
744+
env:
745+
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
746+
- name: Audit worker lock-timeout recovery
747+
run: |
748+
cargo nextest run \
749+
--archive-file target/ci/backend-integration-tests.tar.zst \
750+
-E 'package(buzz-relay) and test(audit_worker_retries_lock_timeout_until_original_entry_is_appended_once)' \
751+
--run-ignored ignored-only
752+
env:
753+
DATABASE_URL: postgres://buzz:${{ env.BUZZ_TEST_POSTGRES_PASSWORD }}@localhost:5432/buzz
712754
- name: Start relay
713755
run: |
714756
chmod +x ./target/ci/buzz-relay
@@ -1007,6 +1049,20 @@ jobs:
10071049
- name: Build Android debug APK
10081050
run: just mobile-build-android
10091051

1052+
mobile-swift:
1053+
name: Mobile Swift
1054+
runs-on: macos-latest
1055+
timeout-minutes: 10
1056+
needs: [changes]
1057+
if: needs.changes.outputs.mobile == 'true'
1058+
steps:
1059+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
1060+
- name: Build
1061+
run: swift build --package-path mobile/ios/BuzzPushKit
1062+
- name: Build release
1063+
run: swift build -c release --package-path mobile/ios/BuzzPushKit
1064+
- name: Test
1065+
run: swift test --package-path mobile/ios/BuzzPushKit
10101066
security:
10111067
name: Security
10121068
runs-on: ubuntu-latest
@@ -1081,6 +1137,36 @@ jobs:
10811137
-p git-credential-nostr \
10821138
-p git-sign-nostr
10831139
1140+
desktop-windows-build:
1141+
name: Desktop Windows Build
1142+
runs-on: windows-latest
1143+
timeout-minutes: 20
1144+
needs: [changes]
1145+
if: github.event_name == 'push' || needs.changes.outputs.desktop == 'true' || needs.changes.outputs.desktop-rust == 'true' || needs.changes.outputs.rust == 'true'
1146+
permissions:
1147+
contents: read
1148+
steps:
1149+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
1150+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
1151+
with:
1152+
node-version: 24.14.1
1153+
package-manager-cache: false
1154+
- uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0
1155+
with:
1156+
version: 11.4.0
1157+
- name: Install desktop dependencies
1158+
shell: bash
1159+
run: pnpm install --frozen-lockfile
1160+
- name: Build both protected-feature selections
1161+
shell: pwsh
1162+
run: |
1163+
Remove-Item Env:VITE_BUZZ_BESTIE -ErrorAction SilentlyContinue
1164+
pnpm -C desktop build
1165+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
1166+
$env:VITE_BUZZ_BESTIE = "1"
1167+
pnpm -C desktop build
1168+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
1169+
10841170
windows-rust:
10851171
name: Windows Rust (x86_64-pc-windows-msvc)
10861172
runs-on: windows-latest

.github/workflows/codex-security-review.yml

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ jobs:
214214
if: needs.prepare-review.outputs.authorized == 'true'
215215
runs-on: ubuntu-latest
216216
environment: codex-review
217-
timeout-minutes: 30
217+
timeout-minutes: 40
218218
concurrency:
219219
group: codex-security-review-${{ needs.prepare-review.outputs.pr_number }}
220220
cancel-in-progress: true
@@ -228,7 +228,7 @@ jobs:
228228
REVIEW_REPOSITORY: review-target
229229
REVIEW_DIFF_FILE: .git/codex-review.diff
230230
outputs:
231-
review_json: ${{ steps.run_codex.outputs.final-message }}
231+
review_json: ${{ steps.salvage.outputs.review_json }}
232232
steps:
233233
- name: Checkout exact pull request head
234234
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -287,6 +287,12 @@ jobs:
287287
# action's local proxy rather than entering the Codex subprocess.
288288
- name: Review pull request
289289
id: run_codex
290+
# Codex CLI ≥0.149.x can leave a PTY descendant holding inherited stdio
291+
# after the turn completes, stalling the action indefinitely. The output
292+
# file is written before the hang, so a timeout here wastes at most 30
293+
# minutes instead of the full 40, and the salvage step recovers the result.
294+
timeout-minutes: 30
295+
continue-on-error: true
290296
uses: openai/codex-action@86365089eb2b84e0a8fb0717b304f8bdcb13b20e # v1.12
291297
env:
292298
# Checkout and fetch are complete. Remove runner credentials from the
@@ -306,6 +312,8 @@ jobs:
306312
safety-strategy: drop-sudo
307313
permission-profile: ':read-only'
308314
working-directory: ${{ github.workspace }}/${{ env.REVIEW_CONTEXT }}
315+
# Written before the hang; salvaged below if the step times out.
316+
output-file: ${{ runner.temp }}/codex-review.json
309317
output-schema: |
310318
{
311319
"type": "object",
@@ -442,6 +450,51 @@ jobs:
442450
assumptions. Review only the authorized PR range and ground every finding
443451
in a changed hunk and a plausible failure or abuse path.
444452
453+
# Salvage the finished review whether the Codex step completed cleanly or
454+
# timed out due to the PTY-shutdown hang. Prefer the action's final-message
455+
# output (set on a clean exit); fall back to the output file written by the
456+
# CLI before the hang. Fail the job only when neither source is available or
457+
# the recovered JSON is not a valid review shape.
458+
- name: Salvage review output
459+
id: salvage
460+
if: always()
461+
env:
462+
FINAL_MESSAGE: ${{ steps.run_codex.outputs.final-message }}
463+
CODEX_OUTPUT_FILE: ${{ runner.temp }}/codex-review.json
464+
run: |
465+
json=""
466+
467+
# Prefer the action output set on a clean exit.
468+
if [ -n "$FINAL_MESSAGE" ]; then
469+
json="$FINAL_MESSAGE"
470+
echo "source=action-output" >> "$GITHUB_STEP_SUMMARY"
471+
elif [ -s "$CODEX_OUTPUT_FILE" ]; then
472+
json="$(cat "$CODEX_OUTPUT_FILE")"
473+
echo "source=output-file" >> "$GITHUB_STEP_SUMMARY"
474+
else
475+
echo "No review output from action or output file." >&2
476+
exit 1
477+
fi
478+
479+
# Minimal shape validation: non-empty JSON object with overall_risk.
480+
if ! echo "$json" | python3 -c "
481+
import sys, json
482+
d = json.load(sys.stdin)
483+
assert isinstance(d, dict), 'not an object'
484+
assert 'overall_risk' in d, 'missing overall_risk'
485+
"; then
486+
echo "Review JSON failed shape validation." >&2
487+
exit 1
488+
fi
489+
490+
# Write as a multiline output (GitHub-safe delimiter).
491+
EOF=$(dd if=/dev/urandom bs=15 count=1 2>/dev/null | base64)
492+
{
493+
echo "review_json<<${EOF}"
494+
echo "$json"
495+
echo "${EOF}"
496+
} >> "$GITHUB_OUTPUT"
497+
445498
post-review:
446499
name: Post Codex Security Review
447500
needs: [prepare-review, security-review]

.intersect/sadscan.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,14 @@
22
exclude_rules_for_files:
33
sq.pii.cc.visa:
44
- Cargo.lock
5+
# Self-signed test fixture generated solely to exercise reqwest identity parsing.
6+
kingfisher.privkey.2:
7+
- "*apns-test-identity.pem"
8+
- "*apns-test-key-only.pem"
9+
- "*apns-test-encrypted-identity.pem"
10+
- "*apns-test-mismatched-identity.pem"
11+
np.pem.1:
12+
- "*apns-test-identity.pem"
13+
- "*apns-test-key-only.pem"
14+
- "*apns-test-encrypted-identity.pem"
15+
- "*apns-test-mismatched-identity.pem"

0 commit comments

Comments
 (0)