fix: preserve canonical restart sentinel routes#64391
Conversation
Greptile SummaryThis PR hardens the restart-sentinel notice path for case-sensitive channels like Matrix by (1) making Confidence Score: 5/5Safe to merge — the fix is tightly scoped to the restart-sentinel notice path and is fully covered by new targeted tests. All four changed files contain only correct, well-tested logic. The sole observation (redundant threadId fallback) is unreachable dead code and carries no behavioral risk. No P0 or P1 issues found. No files require special attention. Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/config/sessions/delivery-info.ts
Line: 32-33
Comment:
**Redundant threadId fallback**
`deliveryContextFromSession` already synthesizes `threadId` from `lastThreadId ?? deliveryContext?.threadId ?? origin?.threadId` internally, so the `?? entry?.lastThreadId ?? entry?.origin?.threadId` portion of the fallback chain here is unreachable in practice. The behavior is correct but the extra chain adds noise.
```suggestion
storedDeliveryContext.threadId;
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix: preserve canonical restart sentinel..." | Re-trigger Greptile |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3dcbefdde0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
Hardens restart-sentinel notice routing to avoid reconstructing outbound targets from lossy session keys (notably for case-sensitive channels like Matrix), and instead relies on canonical stored delivery route metadata when available.
Changes:
- Remove restart-sentinel fallback routing via
resolveAnnounceTargetFromKey(...), skipping outbound notice delivery when canonical route data is unavailable. - Update
extractDeliveryInfo()to derive delivery context usingdeliveryContextFromSession(...)(leveraging stored last-route metadata whendeliveryContextis missing). - Add/adjust tests for restart-sentinel behavior and delivery-info route derivation.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/gateway/server-restart-sentinel.ts | Stops reconstructing notice targets from session keys; only routes when canonical context is present. |
| src/gateway/server-restart-sentinel.test.ts | Adds coverage for “skip outbound notice when no canonical context”; updates mocks. |
| src/config/sessions/delivery-info.ts | Uses deliveryContextFromSession() to synthesize delivery context from stored session metadata. |
| src/config/sessions/delivery-info.test.ts | Adds a test intended to cover deriving delivery info from stored last-route metadata. |
16c8fac to
be97d69
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1acabb421c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
🔒 Aisle Security AnalysisWe found 2 potential security issue(s) in this PR:
1. 🟡 Partial restart-sentinel deliveryContext can override canonical route, causing misrouted outbound notice
DescriptionIn
Vulnerable flow:
Vulnerable code: const sentinelContext = payload.deliveryContext;
let sessionDeliveryContext = deliveryContextFromSession(entry);
...
const origin = mergeDeliveryContext(sentinelContext, sessionDeliveryContext);
const channelRaw = origin?.channel;
const channel = channelRaw ? normalizeChannelId(channelRaw) : null;
const to = origin?.to;
if (!channel || !to) {
return;
}RecommendationEnsure the sentinel context is only preferred when it is routable as a pair (has both One safe approach: const sentinelContext = payload.deliveryContext;
const sessionContext = sessionDeliveryContext;
const origin = hasRoutableDeliveryContext(sentinelContext)
? mergeDeliveryContext(sentinelContext, sessionContext)
: sessionContext;Alternatively, harden 2. 🟡 Restart sentinel JSON file lacks integrity and secure permissions, enabling tampering to trigger outbound messages
DescriptionThe restart sentinel mechanism persists routing metadata to a JSON file in the state directory and later consumes it to send a restart notice. The persisted file is written and read without any integrity protection (signature/MAC) and without enforcing restrictive filesystem permissions. If an attacker can write to the configured state directory (e.g., via a misconfigured Vulnerable behavior:
Vulnerable code: await fs.mkdir(path.dirname(filePath), { recursive: true });
const data: RestartSentinel = { version: 1, payload };
await fs.writeFile(filePath, `${JSON.stringify(data, null, 2)}\n`, "utf-8");RecommendationHarden the sentinel persistence against tampering:
await fs.mkdir(path.dirname(filePath), { recursive: true, mode: 0o700 });
await fs.writeFile(filePath, content, { encoding: "utf-8", mode: 0o600, flag: "w" });
Analyzed PR: #64391 at commit Last updated on: 2026-04-10T16:53:04Z |
126d103 to
e5ff872
Compare
e5ff872 to
0183c17
Compare
|
Merged via squash.
Thanks @gumadeiras! |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0183c1782f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Merged via squash. Prepared head SHA: 0183c17 Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
Merged via squash. Prepared head SHA: 0183c17 Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
Merged via squash. Prepared head SHA: 0183c17 Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
Merged via squash. Prepared head SHA: 0183c17 Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
Merged via squash. Prepared head SHA: 0183c17 Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
Summary
extractDeliveryInfo()now synthesizes canonical stored delivery routes viadeliveryContextFromSession(...), and restart-sentinel notice delivery no longer falls back to session-key target reconstruction.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Root Cause (if applicable)
resolveAnnounceTargetFromKey(...)when canonical route data was missing. That fallback reconstructs a destination from session-key identity, which is unsafe for case-sensitive channels.Regression Test Plan (if applicable)
src/gateway/server-restart-sentinel.test.ts,src/config/sessions/delivery-info.test.tsdeliveryContextis absent.src/infra/outbound/delivery-queue.recovery.test.tsalready covers the permanent-failure recovery side, but not restart-sentinel fallback.User-visible / Behavior Changes
Diagram (if applicable)
Security Impact (required)
Yes, explain risk + mitigation:Repro + Verification
Environment
lastTo/origin.toSteps
Expected
Actual
Evidence
Attach at least one:
Human Verification (required)
deliveryContext; restart-sentinel with no surviving canonical route; existing permanent Matrix 403 recovery coverage still green.Review Conversations
Compatibility / Migration
Risks and Mitigations