fix: validate relationship document ID#11193
Conversation
Sync 1.8.x into main
…onsistent-dir-structure-in-contribution-docs docs: update the directory structure in CONTRIBUTING.md
|
Important Review skippedReview was skipped due to path filters ⛔ Files ignored due to path filters (1)
CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including You can disable this status message by setting the
📝 WalkthroughWalkthroughAdds Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Security Scan Results for PRDocker Image Scan Results
Source Code Scan Results🎉 No vulnerabilities found! |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In
`@src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php`:
- Around line 254-281: The validateRelationship method currently overwrites any
client-provided associative-array relation $id by always assigning ID::unique();
change this so that when $relation is an associative array you only assign
ID::unique() if $relation['$id'] is not set or empty, and if a $id is provided
validate it with CustomId() exactly like the string/Document path; ensure the
validation and potential Exception::GENERAL_BAD_REQUEST uses the
validator->getDescription(), and return the normalized Document (wrapping the
array in new Document($relation)) only after validation so custom IDs are not
silently replaced (references: validateRelationship, Document, CustomId,
Exception::GENERAL_BAD_REQUEST).
In `@tests/e2e/Services/Databases/TablesDB/DatabasesBase.php`:
- Around line 7682-7695: The test currently posts a relationship via
$this->client->call to '/tablesdb/.../columns/relationship' using
Database::RELATION_ONE_TO_MANY and then just sleep(1), which can cause false
negatives if the column/relationship isn't ready; modify the test to assert the
relationship creation response (e.g., check response code and returned
column/relationship id) immediately after the call and replace the blind sleep
with a short poll that calls the column list/get endpoint until the new column
id appears or a timeout elapses before proceeding to negative ID-validation
cases.
🧹 Nitpick comments (4)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php (1)
214-215: Unused$relationIdvariable extracted from destructuring.The
$relationIdvalue returned byvalidateRelationship()is never used after assignment. Use the ignore syntax to suppress the static analysis warning and clarify intent.Suggested fix
- [$relationId, $relation] = $this->validateRelationship($relation); + [, $relation] = $this->validateRelationship($relation);src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php (1)
312-313: Unused$relationIdvariable extracted from destructuring.Same issue as in Upsert.php—
$relationIdis never referenced after assignment.Suggested fix
- [$relationId, $relation] = $this->validateRelationship($relation); + [, $relation] = $this->validateRelationship($relation);src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php (1)
204-205: Unused$relationIdvariable extracted from destructuring.Same issue as in Upsert.php and Create.php—
$relationIdis never referenced after assignment.Suggested fix
- [$relationId, $relation] = $this->validateRelationship($relation); + [, $relation] = $this->validateRelationship($relation);tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (1)
7696-7878: Pin at least one error type/message to confirm the validator path.
Only checking400allows unrelated failures to pass. Adding a representative assertion onbody['type'](or message) strengthens the test’s intent.✅ Minimal example
$this->assertEquals(400, $response['headers']['status-code']); + $this->assertEquals(Exception::GENERAL_ARGUMENT_INVALID, $response['body']['type']);
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In
`@src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php`:
- Around line 311-319: The loop currently calls validateRelationship($relation)
before converting placeholder IDs, causing CustomId validation to reject
ID::unique() placeholders; move normalization so that you assign missing
$relation['$id'] = ID::unique() (and convert string "unique()" if your code uses
that placeholder) and wrap $relation into new Document($relation) prior to
calling validateRelationship, or alternatively update validateRelationship to
accept the placeholder (e.g., treat ID::unique() / "unique()" as valid) — adjust
the foreach around $relations, the validateRelationship method, and the Document
creation logic accordingly.
In
`@src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php`:
- Around line 203-211: The loop over $relations validates each relation before
normalizing the ID placeholder, causing inline relationship updates using
ID::unique() to fail; move the normalization step that replaces $relation['$id']
= ID::unique() (or otherwise resolves the "unique()" placeholder) to occur
before calling validateRelationship($relation), or update validateRelationship
to accept the placeholder; specifically adjust the foreach that currently calls
$this->validateRelationship($relation) prior to converting array relations into
Document instances so that normalization of '$id' (and conversion to Document)
happens first, then call validateRelationship on the normalized Document/array.
♻️ Duplicate comments (1)
tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (1)
7695-7708: Assert relationship column readiness after polling.If the column never appears, the test continues and failures can be misattributed to ID validation rather than schema readiness. Add an explicit assertion after the loop to fail fast. Line 7695 is the critical block.
🔧 Proposed fix
- $maxAttempts = 10; - for ($i = 0; $i < $maxAttempts; $i++) { + $maxAttempts = 10; + $columnReady = false; + for ($i = 0; $i < $maxAttempts; $i++) { $columns = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $parentTableId . '/columns', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'] ])); $columnKeys = array_column($columns['body']['columns'], 'key'); if (in_array('children', $columnKeys)) { - break; + $columnReady = true; + break; } usleep(200000); } + $this->assertTrue($columnReady, 'Relationship column "children" was not created in time.');
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.php
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.php
Show resolved
Hide resolved
d13fe04 to
e4dd435
Compare
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@tests/e2e/Services/Databases/TablesDB/DatabasesBase.php`:
- Around line 7695-7709: The loop that polls for the relationship column using
$maxAttempts and the for ($i = 0; $i < $maxAttempts; $i++) construct can
silently continue if the 'children' column never appears; add a boolean flag
(e.g., $found = false) before the loop, set $found = true and break when
in_array('children', $columnKeys) is true, and after the loop assert that $found
is true (or fail the test with a clear message including $databaseId and
$parentTableId); optionally include the last $columns response/status in the
failure message for debugging.
♻️ Duplicate comments (1)
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php (1)
253-275: ConfirmCustomIdaccepts theunique()placeholder for relationship IDs.
validateRelationship()now appliesCustomIdbefore later logic converts'unique()'to a generated ID in create/upsert flows. IfCustomIddoesn’t allow'unique()', nested relationship creation that relies on that placeholder will start failing.#!/bin/bash # Locate CustomId validator and inspect handling of the unique() placeholder. fd -a "CustomId.php" src fd -a "CustomId.php" src -x rg -n "unique\\(\\)" -C2 {} fd -a "CustomId.php" src -x rg -n "function isValid" -C3 {}
8f71186 to
233ed80
Compare
233ed80 to
63e6a51
Compare
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php`:
- Around line 253-275: The validateRelationship method currently ignores values
that are not Document, string, or associative array; update validateRelationship
to reject unsupported types by adding an else branch that throws an Exception
(use Exception::GENERAL_BAD_REQUEST) with a clear message (e.g. "Unsupported
relationship value type") so callers get a validation error for inputs like
integers/booleans; keep existing behavior for Document, string, and associative
array branches and reuse the same Exception class as used for CustomId
validation.
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php`:
- Around line 261-275: After extracting $relationId (from Document, string, or
associative array) add a strict type guard so non-string values never reach
CustomId::isValid(): before creating the CustomId validator in Action.php, check
is_string($relationId) and if not throw Exception::GENERAL_BAD_REQUEST with an
appropriate message; then call (new CustomId())->isValid($relationId) and use
getDescription() as before. This ensures relationId, CustomId::isValid, and the
Exception path are only executed for string IDs and prevents TypeError 500s.
🧹 Nitpick comments (1)
tests/e2e/Services/Databases/TablesDB/DatabasesBase.php (1)
7706-7888: Optional: table‑drive the invalid/valid ID cases to reduce repetition.
This block repeats the same request shape with only the$idand expected status changing. A small helper or data-driven loop would make the test easier to extend and maintain.
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php
Show resolved
Hide resolved
bab6026 to
cbe2d23
Compare
The base branch was changed.
What does this PR do?
Validates relationship document IDs using
CustomIdvalidator to prevent creating documents/rows with invalid IDs.Changes:
validateRelationship()helper method in baseAction.phpclass to avoid code duplication$idvalues (max 36 chars, valid characters: a-z, A-Z, 0-9, period, hyphen, underscore, can't start with special char)Files changed:
src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.phpsrc/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Create.phpsrc/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Update.phpsrc/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.phptests/e2e/Services/Databases/TablesDB/DatabasesBase.phpTest Plan
tests/e2e/Services/Databases/TablesDB/DatabasesBase.phpRelated PRs and Issues
Checklist