Update appwrite push ledger name by ArnabChatterjee20k · Pull Request #13848 · appwrite/appwrite · GitHub
Skip to content

Update appwrite push ledger name - #13848

Merged
ArnabChatterjee20k merged 3 commits into
mainfrom
update-appwrite-push-ledger-name
Sep 23, 2026
Merged

ArnabChatterjee20k merged 3 commits into
mainfrom
update-appwrite-push-ledger-name

Conversation

@ArnabChatterjee20k

Copy link
Copy Markdown
Member

What does this PR do?

(Provide a description of what this PR does and why it's needed.)

Test Plan

(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work. Screenshots may also be helpful.)

Related PRs and Issues

  • (Related PR or issue)

Checklist

  • Have you read the Contributing Guidelines on issues?
  • If the PR includes a change to an API's metadata (desc, label, params, etc.), does it also include updated API specs and example docs?

@greptile-apps

greptile-apps Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Comment on lines 175 to 182
foreach ($subscribe->filters() as $filter) {
Span::add('mqtt.topic', $filter->topic);

$document = $topicsById[$filter->topic] ?? null;
if (!isset($allowed[$filter->topic]) || $document === null) {
$suback->deny();
continue;
}
$document = $this->isWildcard($filter->topic) ? null : ($topicsByName[$filter->topic] ?? null);

if (!$this->authorizedForTopic($document->getAttribute('subscribe', []) ?? [], $roles)) {
$suback->deny();
continue;
}

$topicQos = $document->getAttribute('qos');
$topicQos = $document?->getAttribute('qos');
$grantedQos = min($filter->qos, $topicQos === null ? Packet::QOS_1 : (int) $topicQos);

$suback->grant($grantedQos);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Topic Authorization Is Removed

The handler now grants every subscription without checking the topic's configured subscribe roles. Any authenticated project user can therefore subscribe to a restricted topic by name or wildcard. No later delivery layer checks those roles, so unauthorized users can receive live messages and, for exact topics, backlog replays.

How this was verified: Topic subscribe roles are stored by the public topic API, while the changed handler grants every filter and delivery subsequently fans messages directly to matching subscribers without another authorization check.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/Appwrite/Mqtt/Handler.php
Line: 175-182

Comment:
**Topic Authorization Is Removed**

The handler now grants every subscription without checking the topic's configured `subscribe` roles. Any authenticated project user can therefore subscribe to a restricted topic by name or wildcard. No later delivery layer checks those roles, so unauthorized users can receive live messages and, for exact topics, backlog replays.

**How this was verified:** Topic subscribe roles are stored by the public topic API, while the changed handler grants every filter and delivery subsequently fans messages directly to matching subscribers without another authorization check.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@greptile it is intentional

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood. If topic subscriptions are intentionally open to every authenticated project connection, then the authorization-removal concern is not actionable for this PR. The updated comment in onSubscribe() documents that policy; no change is needed from my side.

Comment on lines 164 to +169
$documents = $authorization->skip(fn () => $projectDB->find('topics', [
Query::equal('$id', array_keys($allowed)),
Query::limit(\count($allowed)),
Query::equal('name', array_keys($names)),
Query::limit(\count($names)),
]));
foreach ($documents as $document) {
$topicsById[$document->getId()] = $document;
$topicsByName[$document->getAttribute('name')] ??= $document;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Duplicate Names Merge Topics

Topic names are not unique, but this lookup treats each name as a unique channel and keeps only the first matching document. Two supported topics with the same name will have their live publications merged onto one MQTT channel, while QoS and replay use an arbitrary topic document. Subscribers can consequently receive another topic's messages or the wrong backlog.

How this was verified: The topic schema and API permit duplicate names, while publishing maps IDs to names and subscription lookup retains only the first document for each name.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/Appwrite/Mqtt/Handler.php
Line: 164-169

Comment:
**Duplicate Names Merge Topics**

Topic names are not unique, but this lookup treats each name as a unique channel and keeps only the first matching document. Two supported topics with the same name will have their live publications merged onto one MQTT channel, while QoS and replay use an arbitrary topic document. Subscribers can consequently receive another topic's messages or the wrong backlog.

**How this was verified:** The topic schema and API permit duplicate names, while publishing maps IDs to names and subscription lookup retains only the first document for each name.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@greptile dont you think it make sense. A project can't have same topic name. If they are that is wrong. It should be merged to one only as the subscriber listening to topic name and not the topic id

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense as the intended product invariant: MQTT subscribers address the channel by name, not the topic document ID, so duplicate names should represent one logical channel.

My concern is that the current schema/API does not enforce this invariant. Create only treats the document ID as unique, and V24.php explicitly removes the existing _key_name index, so duplicate-name documents can currently exist.

If duplicate names are invalid, uniqueness should be enforced at the data layer/API, with existing duplicates cleaned up or otherwise handled. Until then, ??= remains lossy: it selects one arbitrary document for QoS and replay, so messages stored under another duplicate document ID will not be replayed.

private const BROKER_PORT = 1883;
private const BROKER_WS_PORT = 8083;

// The CONNACK/DISCONNECT Reason String the broker sends on an unauthorized connection — the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Test Mirrors Production Message

REASON_UNAUTHORIZED copies the production exception text verbatim, and the new assertions require that exact wording. This violates the repository directive to test observable behavior rather than mirror source strings, and it makes harmless copy changes break an end-to-end protocol test. This repository requirement must be satisfied before merging; test the rejection separately and assert only the reason's observable semantic properties.

Context Used: Call out and harshly judge implementation-coupled tests. We don't mirror source code, configuration, or version pins in assertions. We test observable behavior; use linters for syntax and schema checks. (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: tests/e2e/Services/Mqtt/MqttServerTest.php
Line: 46

Comment:
**Test Mirrors Production Message**

`REASON_UNAUTHORIZED` copies the production exception text verbatim, and the new assertions require that exact wording. This violates the repository directive to test observable behavior rather than mirror source strings, and it makes harmless copy changes break an end-to-end protocol test. This repository requirement must be satisfied before merging; test the rejection separately and assert only the reason's observable semantic properties.

**Context Used:** Call out and harshly judge implementation-coupled tests. We don't mirror source code, configuration, or version pins in assertions. We test observable behavior; use linters for syntax and schema checks. ([source](https://app.greptile.com/review/custom-context?memory=instruction-0))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code Fix in Codex

@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

✨ Benchmark results

Comparing main (before) → update-appwrite-push-ledger-name (after).

Metric Before After Change
🚀 Requests/sec 197.31 200.51 ⚪ +1.6%
⏱️ Latency P50 85.75 ms 87.39 ms ⚪ +1.9%
⏱️ Latency P95 208.77 ms 196.21 ms 🟢 -6%
Per-scenario breakdown & investigation details

Metrics below reflect the current branch (after). Δ P95 compares against the base.

Scenario P50 (ms) P95 (ms) Requests RPS Δ P95 (ms)
API total 87.39 196.21 12,540 200.51 -12.57
Account 159.15 312.57 660 11.03 -173.11
TablesDB 84.29 156.51 6,820 110.7 -6.9
Storage 81.13 175 3,300 55.71 +10
Functions 120.97 225.92 1,760 30.39 -23.44

Top API waits (after)

API request Max wait (ms)
account.name.update 432.52
storage.buckets.create 386.59
storage.files.create 384.29
functions.variables.create 381.9
account.prefs.update 376.51

@ArnabChatterjee20k
ArnabChatterjee20k merged commit 7731ff1 into main Sep 23, 2026
58 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants