mirror of
https://github.com/block/buzz.git
synced 2026-11-04 08:21:48 +00:00
Fixes all six HIGH findings from the buzz security report, one commit per finding. Independently reviewed to approval by Max at `0158ae542`, plus a deep isolated live pass (clean-room compose stack, weird ports, full product matrix) at the same head — see the buzz-security thread for evidence. `fe65c07c3` merges current `origin/main` on top (new commit, no rebase), inheriting the nostr 0.44.6 bump (#3135) and relay-admin ban gate (#3128). ## Findings and fixes | Finding | Commit | Fix | |---|---|---| | 003 — quinn-proto RUSTSEC-2026-0185 | `e5dcdec72` | Bump quinn-proto 0.11.14 → 0.11.16 (lockfile-only) | | 002/004 — linkify-it quadratic-parse DoS (GHSA-22p9-wv53-3rq4, GHSA-v245-v573-v5vm) | `923b3c20f` | pnpm override `linkify-it: ^5.0.2`; `pnpm why` confirms a single 5.0.2 copy | | 001 — media reads served unauthenticated by default | `0f277e3e2` | Helm `requireMediaGetAuth` defaults to `true` + rendered-chart test pinning the default | | 006 — removed workflow owners retain webhook-exfiltration authority | `4749bd56c` | Fail-closed per-fire authority gate (current owner/admin membership) on **all four** trigger doors (on_event, scheduler pre-claim, manual trigger, webhook — masked as generic 404), save-time gate for `call_webhook` defs, durable disable-on-removal wired to kinds 9001 + 9022 | | 005 — git Smart-HTTP reads ignore channel membership | `e648f2dba` + `0158ae542` | `authorize_git_read`: caller's **current active membership** in the repo's bound channel, checked before any hydration/subprocess on all three read doors (`info_refs` for both services + `upload_pack` POST). Uniform generic 404 denials (no membership probing), no repo-owner bypass, first-`buzz-channel`-tag binding semantics fail closed on ambiguous duplicates (mutation-verified test). Resolution follows the live kind:30617 announcement, so deleted/replaced announcements deny immediately. The committed `e2e-git-perms.sh` guest scenario previously asserted the vulnerability — now asserts denial. | ## Behavior changes to be aware of 1. **Unbound repos fail closed for git reads.** `buzz repos create` emits no `buzz-channel` tag, so CLI-created repos without a binding are unreadable via git HTTP. Correct per finding 005's fail-closed posture; a follow-up could bind CLI-created repos at creation time. 2. **006 is conservative:** a workflow disabled on owner removal does not auto-re-enable if the owner is re-added — explicit re-enable required. 3. Merge conflict resolution in `fe65c07c3`: kept main's `@radix-ui/react-dismissable-layer` 1.1.19 bump alongside the linkify-it security override (`pnpm-workspace.yaml` + lockfile). ## Verification at the merge head `fe65c07c3` (same shell) - buzz-relay `--lib`: 761 passed / 1 failed — the lone red is the known pre-existing `mesh_demo::demo_join_forwarded_arm_round_trips_echo` 504 flake, present on main - SEC-005 module incl. PG behavioral matrix: 8/8 (removed-member, never-member, owner-no-bypass, deleted-30617, malformed/ambiguous binding, owner-mismatch all denied) - buzz-workflow 153/0, buzz-db 84/0; `clippy --all-targets -D warnings` + `fmt --check` clean - Desktop JS 3637/3637, tsc clean, biome clean, file-size/px-text/pubkey-truncation gates clean - `helm lint` + `helm unittest` (40/40) on `deploy/charts/buzz` - All five pre-push hooks green (desktop-check, desktop-test, rust-tests, desktop-tauri-test, branch-skew) Prior review evidence at `0158ae542` (pre-merge): Max's independent exact-head approval + clean-room live regression pass (`WORK_LOGS/2026-07-27_SECURITY_HIGH_LIVE_TEST.md` in his workspace). Max will re-run the deep local pass at this post-merge head before merge. --------- Signed-off-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
168 lines
5.9 KiB
YAML
168 lines
5.9 KiB
YAML
suite: production render
|
|
# Multi-template scope: needed so $.Template.BasePath lookups in deployment.yaml
|
|
# (e.g. checksum/secret include of secret-chart.yaml) resolve at render time.
|
|
templates:
|
|
- templates/deployment.yaml
|
|
- templates/secret-chart.yaml
|
|
- templates/serviceaccount.yaml
|
|
- templates/service.yaml
|
|
- templates/pvc-git.yaml
|
|
tests:
|
|
- it: renders cleanly in production profile (external pg/redis)
|
|
set:
|
|
relayUrl: wss://buzz.example.com
|
|
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
|
externalPostgresql.url: postgres://u:p@h:5432/d
|
|
externalRedis.url: redis://h:6379
|
|
s3.endpoint: http://minio:9000
|
|
s3.accessKey: a
|
|
s3.secretKey: s
|
|
asserts:
|
|
- equal:
|
|
path: kind
|
|
value: Deployment
|
|
template: templates/deployment.yaml
|
|
- equal:
|
|
path: kind
|
|
value: ServiceAccount
|
|
template: templates/serviceaccount.yaml
|
|
- equal:
|
|
path: kind
|
|
value: Service
|
|
template: templates/service.yaml
|
|
- contains:
|
|
path: spec.template.spec.containers[0].env
|
|
content:
|
|
name: BUZZ_HUDDLE_AUDIO_AVAILABLE
|
|
value: "true"
|
|
template: templates/deployment.yaml
|
|
# Security default: media GET/HEAD reads must be auth-gated out of the
|
|
# box. A private attachment must never be publicly readable by URL/hash
|
|
# in an unmodified render. If this assertion fails, someone flipped the
|
|
# default — treat that as a security regression, not a config tweak.
|
|
- contains:
|
|
path: spec.template.spec.containers[0].env
|
|
content:
|
|
name: BUZZ_REQUIRE_MEDIA_GET_AUTH
|
|
value: "true"
|
|
template: templates/deployment.yaml
|
|
|
|
- it: lets an explicit value opt out of media read auth for dev/public deployments
|
|
set:
|
|
relayUrl: wss://buzz.example.com
|
|
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
|
externalPostgresql.url: postgres://u:p@h:5432/d
|
|
externalRedis.url: redis://h:6379
|
|
s3.endpoint: http://minio:9000
|
|
s3.accessKey: a
|
|
s3.secretKey: s
|
|
relay.requireMediaGetAuth: false
|
|
asserts:
|
|
- contains:
|
|
path: spec.template.spec.containers[0].env
|
|
content:
|
|
name: BUZZ_REQUIRE_MEDIA_GET_AUTH
|
|
value: "false"
|
|
template: templates/deployment.yaml
|
|
|
|
- it: lets an explicit value disable huddle audio in a single-replica render
|
|
set:
|
|
relayUrl: wss://buzz.example.com
|
|
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
|
externalPostgresql.url: postgres://u:p@h:5432/d
|
|
externalRedis.url: redis://h:6379
|
|
s3.endpoint: http://minio:9000
|
|
s3.accessKey: a
|
|
s3.secretKey: s
|
|
relay.huddleAudioAvailable: false
|
|
asserts:
|
|
- contains:
|
|
path: spec.template.spec.containers[0].env
|
|
content:
|
|
name: BUZZ_HUDDLE_AUDIO_AVAILABLE
|
|
value: "false"
|
|
template: templates/deployment.yaml
|
|
|
|
- it: lets an explicit value enable huddle audio in HA when the operator owns external audio behavior
|
|
set:
|
|
relayUrl: wss://buzz.example.com
|
|
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
|
externalPostgresql.url: postgres://u:p@h:5432/d
|
|
externalRedis.url: redis://h:6379
|
|
s3.endpoint: http://minio:9000
|
|
s3.accessKey: a
|
|
s3.secretKey: s
|
|
replicaCount: 3
|
|
persistence.git.accessMode: ReadWriteOnce
|
|
relay.huddleAudioAvailable: true
|
|
asserts:
|
|
- contains:
|
|
path: spec.template.spec.containers[0].env
|
|
content:
|
|
name: BUZZ_HUDDLE_AUDIO_AVAILABLE
|
|
value: "true"
|
|
template: templates/deployment.yaml
|
|
|
|
- it: renders HA cleanly with replicaCount=3 + RWO git + Redis (no RWM needed)
|
|
set:
|
|
relayUrl: wss://buzz.example.com
|
|
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
|
externalPostgresql.url: postgres://u:p@h:5432/d
|
|
externalRedis.url: redis://h:6379
|
|
s3.endpoint: http://minio:9000
|
|
s3.accessKey: a
|
|
s3.secretKey: s
|
|
replicaCount: 3
|
|
persistence.git.accessMode: ReadWriteOnce
|
|
asserts:
|
|
- equal:
|
|
path: spec.replicas
|
|
value: 3
|
|
template: templates/deployment.yaml
|
|
- equal:
|
|
path: spec.accessModes[0]
|
|
value: ReadWriteOnce
|
|
template: templates/pvc-git.yaml
|
|
- contains:
|
|
path: spec.template.spec.containers[0].env
|
|
content:
|
|
name: BUZZ_HUDDLE_AUDIO_AVAILABLE
|
|
value: "false"
|
|
template: templates/deployment.yaml
|
|
|
|
- it: mounts a per-pod emptyDir git scratch volume when persistence is disabled
|
|
set:
|
|
relayUrl: wss://buzz.example.com
|
|
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
|
externalPostgresql.url: postgres://u:p@h:5432/d
|
|
externalRedis.url: redis://h:6379
|
|
s3.endpoint: http://minio:9000
|
|
s3.accessKey: a
|
|
s3.secretKey: s
|
|
replicaCount: 5
|
|
persistence.git.enabled: false
|
|
asserts:
|
|
- equal:
|
|
path: spec.replicas
|
|
value: 5
|
|
template: templates/deployment.yaml
|
|
# git-repos is still mounted (BUZZ_GIT_REPO_PATH must be a real dir)…
|
|
- contains:
|
|
path: spec.template.spec.containers[0].volumeMounts
|
|
content:
|
|
name: git-repos
|
|
mountPath: /var/lib/buzz/git
|
|
template: templates/deployment.yaml
|
|
# …but as a per-pod emptyDir, not a shared PVC (no multi-attach).
|
|
- contains:
|
|
path: spec.template.spec.volumes
|
|
content:
|
|
name: git-repos
|
|
emptyDir:
|
|
sizeLimit: 10Gi
|
|
template: templates/deployment.yaml
|
|
# No PVC is rendered at all when persistence is disabled.
|
|
- hasDocuments:
|
|
count: 0
|
|
template: templates/pvc-git.yaml
|