Deploys matrix-bridge build.1791062345 (REN-587, parent REN-569) next to Synapse in matrix:
apps/matrix/bridge.yaml (new): ESO Password generator + ExternalSecret matrix-bridge-tokens (CreatedOnce: as_token, hs_token and the rendered registration), ExternalSecret matrix-bridge (paperclip_api_key from OpenBao homelab/apps/matrix-bridge), Deployment (1 replica, Recreate, uid 1000, read-only root FS, no volume), Service matrix-bridge:8080, CNP egress bridge → paperclip:3100.
apps/matrix/synapse.yaml: app_service_config_files now loads /appservices/matrix-bridge/registration.yaml, mounted from matrix-bridge-tokens. Reloader also watches it.
apps/paperclip/network-policy.yaml: lets the bridge pod in to paperclip:3100.
The tokens are generated in-cluster by ESO, so no one seeds them by hand; they never exist outside the cluster. Synapse and the bridge read the same Secret, so they cannot drift. Deleting the Secret regenerates both and Reloader restarts both. The user regex is @agent_.*:matrix\.renner\.uno (server_name is matrix.renner.uno, not renner.uno). MATRIX_OWNER=@k.renner:matrix.renner.uno. No ingress.
Why
REN-565: the owner chats with each agent in Element.
Merge gate
Merge after OpenBao homelab/apps/matrix-bridge has paperclip_api_key (metadata 404 at time of writing; Hermes REN-649 sets up the route, no owner step). Synapse no longer depends on it; without it only the bridge pod stays unready and the matrix KS reports not-ready.
Impact
Synapse restarts once (Recreate, about 1 min chat outage). Not Home Assistant, not cluster-wide: the policy changes are additive allow rules in matrix and paperclip. No window needed.
Synapse with MAS accepts appservice /register only with inhibit_login: true; the bridge sends it (src/matrix.ts).
Verified
Lint only, nothing on the cluster yet: kustomize build + kubeconform -strict pass for apps/matrix (25 resources) and apps/paperclip (37). The rendered registration parses; the regex matches @agent_atlas:matrix.renner.uno and rejects @agent_atlas:matrixXrenner.uno. Image tag resolves in the registry (anonymous pull 200).
After merge (Atlas): ExternalSecret Ready, Synapse and bridge Ready, GET /health 200, owner sees one room per agent.
Revert
Revert this commit. Synapse restarts without the registration; the bridge objects are pruned. The bridge's Matrix users and rooms stay on Synapse (harmless).
## What
Deploys matrix-bridge `build.1791062345` (REN-587, parent REN-569) next to Synapse in `matrix`:
- `apps/matrix/bridge.yaml` (new): ESO Password generator + ExternalSecret `matrix-bridge-tokens` (CreatedOnce: `as_token`, `hs_token` and the rendered registration), ExternalSecret `matrix-bridge` (`paperclip_api_key` from OpenBao `homelab/apps/matrix-bridge`), Deployment (1 replica, Recreate, uid 1000, read-only root FS, no volume), Service `matrix-bridge:8080`, CNP egress bridge → `paperclip:3100`.
- `apps/matrix/synapse.yaml`: `app_service_config_files` now loads `/appservices/matrix-bridge/registration.yaml`, mounted from `matrix-bridge-tokens`. Reloader also watches it.
- `apps/paperclip/network-policy.yaml`: lets the bridge pod in to `paperclip:3100`.
The tokens are generated in-cluster by ESO, so no one seeds them by hand; they never exist outside the cluster. Synapse and the bridge read the same Secret, so they cannot drift. Deleting the Secret regenerates both and Reloader restarts both. The user regex is `@agent_.*:matrix\.renner\.uno` (server_name is `matrix.renner.uno`, not `renner.uno`). `MATRIX_OWNER=@k.renner:matrix.renner.uno`. No ingress.
## Why
REN-565: the owner chats with each agent in Element.
## Merge gate
**Merge after OpenBao `homelab/apps/matrix-bridge` has `paperclip_api_key`** (metadata 404 at time of writing; Hermes REN-649 sets up the route, no owner step). Synapse no longer depends on it; without it only the bridge pod stays unready and the `matrix` KS reports not-ready.
## Impact
- Synapse restarts once (Recreate, about 1 min chat outage). Not Home Assistant, not cluster-wide: the policy changes are additive allow rules in `matrix` and `paperclip`. No window needed.
- Synapse with MAS accepts appservice `/register` only with `inhibit_login: true`; the bridge sends it (`src/matrix.ts`).
## Verified
Lint only, nothing on the cluster yet: `kustomize build` + `kubeconform -strict` pass for `apps/matrix` (25 resources) and `apps/paperclip` (37). The rendered registration parses; the regex matches `@agent_atlas:matrix.renner.uno` and rejects `@agent_atlas:matrixXrenner.uno`. Image tag resolves in the registry (anonymous pull 200).
After merge (Atlas): ExternalSecret Ready, Synapse and bridge Ready, `GET /health` 200, owner sees one room per agent.
## Revert
Revert this commit. Synapse restarts without the registration; the bridge objects are pruned. The bridge's Matrix users and rooms stay on Synapse (harmless).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Adds the matrix-bridge Deployment, Service and ExternalSecret in the
matrix namespace, loads its appservice registration in Synapse, and opens
the bridge -> Paperclip API path (:3100) in both namespaces' policies.
Tokens and the board key come from OpenBao homelab/apps/matrix-bridge.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Approved on 9093b52e008597e853166ef5ea236d8fbe8c7073. Checked: registration template renders the regex @agent_.*:matrix\\.renner\\.uno and both tokens from the same OpenBao keys the pod gets; bridge→paperclip:3100 egress (matrix) matches the live paperclip Service selector app.kubernetes.io/name=paperclip and the new ingress rule in apps/paperclip; Synapse↔bridge are covered by default-deny-ingress intra-ns and matrix-app-egress (bridge is part-of: matrix); readiness /health, liveness TCP; non-root, RO rootfs, no SA token. Merge gate not met: OpenBao homelab/metadata/apps/matrix-bridge = 404. Merge waits for the owner seed (REN-587).
Approved on `9093b52e008597e853166ef5ea236d8fbe8c7073`. Checked: registration template renders the regex `@agent_.*:matrix\\.renner\\.uno` and both tokens from the same OpenBao keys the pod gets; bridge→paperclip:3100 egress (matrix) matches the live paperclip Service selector `app.kubernetes.io/name=paperclip` and the new ingress rule in apps/paperclip; Synapse↔bridge are covered by default-deny-ingress intra-ns and matrix-app-egress (bridge is part-of: matrix); readiness /health, liveness TCP; non-root, RO rootfs, no SA token. **Merge gate not met:** OpenBao `homelab/metadata/apps/matrix-bridge` = 404. Merge waits for the owner seed (REN-587).
as_token and hs_token come from an ESO Password generator (CreatedOnce)
instead of OpenBao, so no one has to seed them by hand. Synapse mounts
only the generated Secret and no longer depends on the OpenBao path;
OpenBao homelab/apps/matrix-bridge now holds only paperclip_api_key.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Approved on b052fc2576fdde6e476c89524f0017a8a55238b5 (re-review of b052fc25 vs 9093b52e). Checked: Password generator generators.external-secrets.io/v1alpha1 is served in-cluster (ESO v2.11.0, namespaced); ExternalSecret v1 refreshPolicy enum includes CreatedOnce; tokens are alnum (YAML-safe in the registration); Synapse mounts only matrix-bridge-tokens (generator), so no OpenBao dependency for Synapse; bridge reads both Secrets, Reloader on both. OpenBao homelab/metadata/apps/matrix-bridge = 200 (v1, 2026-10-04T21:45:52Z). Earlier checks on policies/probes/regex still hold (unchanged).
Approved on `b052fc2576fdde6e476c89524f0017a8a55238b5` (re-review of b052fc25 vs 9093b52e). Checked: Password generator `generators.external-secrets.io/v1alpha1` is served in-cluster (ESO v2.11.0, namespaced); ExternalSecret v1 `refreshPolicy` enum includes CreatedOnce; tokens are alnum (YAML-safe in the registration); Synapse mounts only `matrix-bridge-tokens` (generator), so no OpenBao dependency for Synapse; bridge reads both Secrets, Reloader on both. OpenBao `homelab/metadata/apps/matrix-bridge` = 200 (v1, 2026-10-04T21:45:52Z). Earlier checks on policies/probes/regex still hold (unchanged).
Ghost
merged commit f1e987bdf5 into master2026-10-04 21:46:22 +00:00
🤖Automated review — model CLI default (complexity: complex), commit b052fc2576fdde6e476c89524f0017a8a55238b5.
Advisory review by the review-bot pipeline. It never approves; a human merges. Push new commits to get a fresh review.
Summary
Adds matrix-bridge (REN-587) next to Synapse: a Password-generator-backed ExternalSecret for the appservice as_token/hs_token and registration, an OpenBao-backed ExternalSecret for the Paperclip API key, the bridge Deployment/Service, and the matching CNP egress/ingress rules in matrix and paperclip. Namespace/label wiring, network policy, and secret-store conventions all match the rest of the repo. There is one likely functional defect in how the two tokens are generated that is worth confirming before merge.
🔴 Blocking
kubernetes/apps/matrix/bridge.yaml:27-39 + :53-76: the Password generator (generators.external-secrets.io/v1alpha1) is invoked once, and the ExternalSecret template reads {{ .as_token }} and {{ .hs_token }} from its output (bridge.yaml:54-55,61-62), with secretKeys: [as_token, hs_token] set on the generator spec (bridge.yaml:37-39). As far as I can tell from the upstream PasswordSpec (length, digits, symbols, symbolCharacters, noUpper, allowRepeat), this generator produces a single string under the key password, not a map of named keys — secretKeys is not a field I recognize on that spec. If that's right, .as_token and .hs_token would both resolve to the zero value (empty string) in the template, so matrix-bridge-tokens would end up with as_token/hs_token both empty — defeating the two-sided-trust design the comment at bridge.yaml:16-20 describes, and likely leaving the appservice registration non-functional (Synapse would reject/ignore a registration with an empty as_token/hs_token, or the bridge's own calls to Synapse would fail auth).
I could not verify this against the actual CRD in this sandbox (no network access to pull the external-secrets v2.7+ CRD schema, and kubeconform/kustomize aren't installed here either). The check that settles it: after this ExternalSecret reconciles, run kubectl -n matrix get secret matrix-bridge-tokens -o jsonpath='{.data.as_token}' | base64 -d and the same for hs_token/registration.yaml, and confirm they're non-empty and different from each other. If they come back empty or identical, the generator spec needs fixing (e.g. two separate Password generators, one per token, each referenced by its own sourceRef).
🟡 Suggestions
kubernetes/apps/matrix/bridge.yaml:174-184: livenessProbe is a bare tcpSocket check on the same port the app's HTTP server listens on. The comment explains why httpGet /health is reserved for readiness (a Paperclip outage must not restart the bridge), but a tcpSocket probe will also pass if the Node event loop wedges while the listener socket stays open, so liveness won't catch an actual application hang. Not blocking — just worth knowing readiness is effectively the only real health signal here.
Tests
No tests included or expected — this is a pure Kubernetes manifest change (new Deployment/Service/ExternalSecret/NetworkPolicy), consistent with how the rest of kubernetes/apps/matrix and kubernetes/apps/paperclip are structured (no test suite in this directory tree). The PR body's own verification (kustomize build + kubeconform -strict) is the right kind of check for this change, but kubeconform typically doesn't vendor CRD schemas for generators.external-secrets.io, so it would not have caught the token-generation issue above — that needs a live-cluster check (see Blocking).
Recommendation
Request changes — 1 blocking issue (verify the Password generator actually yields two distinct, non-empty as_token/hs_token values before merging).
🤖 **Automated review** — model `CLI default` (complexity: complex), commit `b052fc2576fdde6e476c89524f0017a8a55238b5`.
> Advisory review by the `review-bot` pipeline. It never approves; a human merges. Push new commits to get a fresh review.
---
## Summary
Adds `matrix-bridge` (REN-587) next to Synapse: a Password-generator-backed `ExternalSecret` for the appservice `as_token`/`hs_token` and registration, an OpenBao-backed `ExternalSecret` for the Paperclip API key, the bridge Deployment/Service, and the matching CNP egress/ingress rules in `matrix` and `paperclip`. Namespace/label wiring, network policy, and secret-store conventions all match the rest of the repo. There is one likely functional defect in how the two tokens are generated that is worth confirming before merge.
## 🔴 Blocking
- `kubernetes/apps/matrix/bridge.yaml:27-39` + `:53-76`: the `Password` generator (`generators.external-secrets.io/v1alpha1`) is invoked once, and the `ExternalSecret` template reads `{{ .as_token }}` and `{{ .hs_token }}` from its output (`bridge.yaml:54-55,61-62`), with `secretKeys: [as_token, hs_token]` set on the generator spec (`bridge.yaml:37-39`). As far as I can tell from the upstream `PasswordSpec` (`length`, `digits`, `symbols`, `symbolCharacters`, `noUpper`, `allowRepeat`), this generator produces a single string under the key `password`, not a map of named keys — `secretKeys` is not a field I recognize on that spec. If that's right, `.as_token` and `.hs_token` would both resolve to the zero value (empty string) in the template, so `matrix-bridge-tokens` would end up with `as_token`/`hs_token` both empty — defeating the two-sided-trust design the comment at `bridge.yaml:16-20` describes, and likely leaving the appservice registration non-functional (Synapse would reject/ignore a registration with an empty `as_token`/`hs_token`, or the bridge's own calls to Synapse would fail auth).
I could not verify this against the actual CRD in this sandbox (no network access to pull the `external-secrets` v2.7+ CRD schema, and `kubeconform`/`kustomize` aren't installed here either). The check that settles it: after this `ExternalSecret` reconciles, run `kubectl -n matrix get secret matrix-bridge-tokens -o jsonpath='{.data.as_token}' | base64 -d` and the same for `hs_token`/`registration.yaml`, and confirm they're non-empty and different from each other. If they come back empty or identical, the generator spec needs fixing (e.g. two separate `Password` generators, one per token, each referenced by its own `sourceRef`).
## 🟡 Suggestions
- `kubernetes/apps/matrix/bridge.yaml:174-184`: `livenessProbe` is a bare `tcpSocket` check on the same port the app's HTTP server listens on. The comment explains why `httpGet /health` is reserved for readiness (a Paperclip outage must not restart the bridge), but a `tcpSocket` probe will also pass if the Node event loop wedges while the listener socket stays open, so liveness won't catch an actual application hang. Not blocking — just worth knowing readiness is effectively the only real health signal here.
## Tests
No tests included or expected — this is a pure Kubernetes manifest change (new Deployment/Service/ExternalSecret/NetworkPolicy), consistent with how the rest of `kubernetes/apps/matrix` and `kubernetes/apps/paperclip` are structured (no test suite in this directory tree). The PR body's own verification (`kustomize build` + `kubeconform -strict`) is the right kind of check for this change, but `kubeconform` typically doesn't vendor CRD schemas for `generators.external-secrets.io`, so it would not have caught the token-generation issue above — that needs a live-cluster check (see Blocking).
## Recommendation
Request changes — 1 blocking issue (verify the `Password` generator actually yields two distinct, non-empty `as_token`/`hs_token` values before merging).
<!-- pr-review:sha=b052fc2576fdde6e476c89524f0017a8a55238b5 -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What
Deploys matrix-bridge
build.1791062345(REN-587, parent REN-569) next to Synapse inmatrix:apps/matrix/bridge.yaml(new): ESO Password generator + ExternalSecretmatrix-bridge-tokens(CreatedOnce:as_token,hs_tokenand the rendered registration), ExternalSecretmatrix-bridge(paperclip_api_keyfrom OpenBaohomelab/apps/matrix-bridge), Deployment (1 replica, Recreate, uid 1000, read-only root FS, no volume), Servicematrix-bridge:8080, CNP egress bridge →paperclip:3100.apps/matrix/synapse.yaml:app_service_config_filesnow loads/appservices/matrix-bridge/registration.yaml, mounted frommatrix-bridge-tokens. Reloader also watches it.apps/paperclip/network-policy.yaml: lets the bridge pod in topaperclip:3100.The tokens are generated in-cluster by ESO, so no one seeds them by hand; they never exist outside the cluster. Synapse and the bridge read the same Secret, so they cannot drift. Deleting the Secret regenerates both and Reloader restarts both. The user regex is
@agent_.*:matrix\.renner\.uno(server_name ismatrix.renner.uno, notrenner.uno).MATRIX_OWNER=@k.renner:matrix.renner.uno. No ingress.Why
REN-565: the owner chats with each agent in Element.
Merge gate
Merge after OpenBao
homelab/apps/matrix-bridgehaspaperclip_api_key(metadata 404 at time of writing; Hermes REN-649 sets up the route, no owner step). Synapse no longer depends on it; without it only the bridge pod stays unready and thematrixKS reports not-ready.Impact
matrixandpaperclip. No window needed./registeronly withinhibit_login: true; the bridge sends it (src/matrix.ts).Verified
Lint only, nothing on the cluster yet:
kustomize build+kubeconform -strictpass forapps/matrix(25 resources) andapps/paperclip(37). The rendered registration parses; the regex matches@agent_atlas:matrix.renner.unoand rejects@agent_atlas:matrixXrenner.uno. Image tag resolves in the registry (anonymous pull 200).After merge (Atlas): ExternalSecret Ready, Synapse and bridge Ready,
GET /health200, owner sees one room per agent.Revert
Revert this commit. Synapse restarts without the registration; the bridge objects are pruned. The bridge's Matrix users and rooms stay on Synapse (harmless).
🤖 Generated with Claude Code
Approved on
9093b52e008597e853166ef5ea236d8fbe8c7073. Checked: registration template renders the regex@agent_.*:matrix\\.renner\\.unoand both tokens from the same OpenBao keys the pod gets; bridge→paperclip:3100 egress (matrix) matches the live paperclip Service selectorapp.kubernetes.io/name=paperclipand the new ingress rule in apps/paperclip; Synapse↔bridge are covered by default-deny-ingress intra-ns and matrix-app-egress (bridge is part-of: matrix); readiness /health, liveness TCP; non-root, RO rootfs, no SA token. Merge gate not met: OpenBaohomelab/metadata/apps/matrix-bridge= 404. Merge waits for the owner seed (REN-587).New commits pushed, approval review dismissed automatically according to repository settings
Approved on
b052fc2576fdde6e476c89524f0017a8a55238b5(re-review ofb052fc25vs9093b52e). Checked: Password generatorgenerators.external-secrets.io/v1alpha1is served in-cluster (ESO v2.11.0, namespaced); ExternalSecret v1refreshPolicyenum includes CreatedOnce; tokens are alnum (YAML-safe in the registration); Synapse mounts onlymatrix-bridge-tokens(generator), so no OpenBao dependency for Synapse; bridge reads both Secrets, Reloader on both. OpenBaohomelab/metadata/apps/matrix-bridge= 200 (v1, 2026-10-04T21:45:52Z). Earlier checks on policies/probes/regex still hold (unchanged).🤖 Automated review — model
CLI default(complexity: complex), commitb052fc2576fdde6e476c89524f0017a8a55238b5.Summary
Adds
matrix-bridge(REN-587) next to Synapse: a Password-generator-backedExternalSecretfor the appserviceas_token/hs_tokenand registration, an OpenBao-backedExternalSecretfor the Paperclip API key, the bridge Deployment/Service, and the matching CNP egress/ingress rules inmatrixandpaperclip. Namespace/label wiring, network policy, and secret-store conventions all match the rest of the repo. There is one likely functional defect in how the two tokens are generated that is worth confirming before merge.🔴 Blocking
kubernetes/apps/matrix/bridge.yaml:27-39+:53-76: thePasswordgenerator (generators.external-secrets.io/v1alpha1) is invoked once, and theExternalSecrettemplate reads{{ .as_token }}and{{ .hs_token }}from its output (bridge.yaml:54-55,61-62), withsecretKeys: [as_token, hs_token]set on the generator spec (bridge.yaml:37-39). As far as I can tell from the upstreamPasswordSpec(length,digits,symbols,symbolCharacters,noUpper,allowRepeat), this generator produces a single string under the keypassword, not a map of named keys —secretKeysis not a field I recognize on that spec. If that's right,.as_tokenand.hs_tokenwould both resolve to the zero value (empty string) in the template, somatrix-bridge-tokenswould end up withas_token/hs_tokenboth empty — defeating the two-sided-trust design the comment atbridge.yaml:16-20describes, and likely leaving the appservice registration non-functional (Synapse would reject/ignore a registration with an emptyas_token/hs_token, or the bridge's own calls to Synapse would fail auth).I could not verify this against the actual CRD in this sandbox (no network access to pull the
external-secretsv2.7+ CRD schema, andkubeconform/kustomizearen't installed here either). The check that settles it: after thisExternalSecretreconciles, runkubectl -n matrix get secret matrix-bridge-tokens -o jsonpath='{.data.as_token}' | base64 -dand the same forhs_token/registration.yaml, and confirm they're non-empty and different from each other. If they come back empty or identical, the generator spec needs fixing (e.g. two separatePasswordgenerators, one per token, each referenced by its ownsourceRef).🟡 Suggestions
kubernetes/apps/matrix/bridge.yaml:174-184:livenessProbeis a baretcpSocketcheck on the same port the app's HTTP server listens on. The comment explains whyhttpGet /healthis reserved for readiness (a Paperclip outage must not restart the bridge), but atcpSocketprobe will also pass if the Node event loop wedges while the listener socket stays open, so liveness won't catch an actual application hang. Not blocking — just worth knowing readiness is effectively the only real health signal here.Tests
No tests included or expected — this is a pure Kubernetes manifest change (new Deployment/Service/ExternalSecret/NetworkPolicy), consistent with how the rest of
kubernetes/apps/matrixandkubernetes/apps/paperclipare structured (no test suite in this directory tree). The PR body's own verification (kustomize build+kubeconform -strict) is the right kind of check for this change, butkubeconformtypically doesn't vendor CRD schemas forgenerators.external-secrets.io, so it would not have caught the token-generation issue above — that needs a live-cluster check (see Blocking).Recommendation
Request changes — 1 blocking issue (verify the
Passwordgenerator actually yields two distinct, non-emptyas_token/hs_tokenvalues before merging).