mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge pull request #12307 from appwrite/codex/delete-orphaned-rules-1-9
[codex] Delete orphaned proxy rules on create
This commit is contained in:
@@ -5,7 +5,11 @@ namespace Appwrite\Platform\Modules\Proxy;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\DNS as ValidatorDNS;
|
||||
use Appwrite\Platform\Action as PlatformAction;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\DNS\Message\Record;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Logger\Log;
|
||||
@@ -20,6 +24,57 @@ class Action extends PlatformAction
|
||||
{
|
||||
}
|
||||
|
||||
protected function createRule(Document $rule, Database $dbForPlatform, Authorization $authorization): Document
|
||||
{
|
||||
try {
|
||||
return $authorization->skip(fn () => $dbForPlatform->createDocument('rules', $rule));
|
||||
} catch (Duplicate) {
|
||||
if (!$this->deleteOrphanedRule($rule, $dbForPlatform, $authorization)) {
|
||||
throw new Exception(Exception::RULE_ALREADY_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return $authorization->skip(fn () => $dbForPlatform->createDocument('rules', $rule));
|
||||
} catch (Duplicate) {
|
||||
throw new Exception(Exception::RULE_ALREADY_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
private function deleteOrphanedRule(Document $rule, Database $dbForPlatform, Authorization $authorization): bool
|
||||
{
|
||||
$existingRule = $authorization->skip(function () use ($rule, $dbForPlatform) {
|
||||
$existingRule = $dbForPlatform->findOne('rules', [
|
||||
Query::equal('domain', [$rule->getAttribute('domain', '')]),
|
||||
]);
|
||||
if (!$existingRule->isEmpty()) {
|
||||
return $existingRule;
|
||||
}
|
||||
|
||||
return $dbForPlatform->getDocument('rules', $rule->getId());
|
||||
});
|
||||
|
||||
if (
|
||||
$existingRule->isEmpty() ||
|
||||
$existingRule->getAttribute('domain', '') !== $rule->getAttribute('domain', '')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$projectId = $existingRule->getAttribute('projectId', '');
|
||||
if (empty($projectId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$project = $authorization->skip(fn () => $dbForPlatform->getDocument('projects', $projectId));
|
||||
if (!$project->isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$authorization->skip(fn () => $dbForPlatform->deleteDocument('rules', $existingRule->getId()));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures domain is not in the deny list and is a valid domain
|
||||
*
|
||||
|
||||
@@ -12,7 +12,6 @@ use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Logger\Log;
|
||||
@@ -120,11 +119,7 @@ class Create extends Action
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$rule = $authorization->skip(fn () => $dbForPlatform->createDocument('rules', $rule));
|
||||
} catch (Duplicate $e) {
|
||||
throw new Exception(Exception::RULE_ALREADY_EXISTS);
|
||||
}
|
||||
$rule = $this->createRule($rule, $dbForPlatform, $authorization);
|
||||
|
||||
if ($rule->getAttribute('status', '') === RULE_STATUS_CERTIFICATE_GENERATING) {
|
||||
$publisherForCertificates->enqueue(new \Appwrite\Event\Message\Certificate(
|
||||
|
||||
@@ -12,7 +12,6 @@ use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\UID;
|
||||
@@ -142,11 +141,7 @@ class Create extends Action
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$rule = $authorization->skip(fn () => $dbForPlatform->createDocument('rules', $rule));
|
||||
} catch (Duplicate $e) {
|
||||
throw new Exception(Exception::RULE_ALREADY_EXISTS);
|
||||
}
|
||||
$rule = $this->createRule($rule, $dbForPlatform, $authorization);
|
||||
|
||||
if ($rule->getAttribute('status', '') === RULE_STATUS_CERTIFICATE_GENERATING) {
|
||||
$publisherForCertificates->enqueue(new \Appwrite\Event\Message\Certificate(
|
||||
|
||||
@@ -12,7 +12,6 @@ use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\UID;
|
||||
@@ -149,11 +148,7 @@ class Create extends Action
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$rule = $authorization->skip(fn () => $dbForPlatform->createDocument('rules', $rule));
|
||||
} catch (Duplicate $e) {
|
||||
throw new Exception(Exception::RULE_ALREADY_EXISTS);
|
||||
}
|
||||
$rule = $this->createRule($rule, $dbForPlatform, $authorization);
|
||||
|
||||
if ($rule->getAttribute('status', '') === RULE_STATUS_CERTIFICATE_GENERATING) {
|
||||
$publisherForCertificates->enqueue(new \Appwrite\Event\Message\Certificate(
|
||||
|
||||
@@ -12,7 +12,6 @@ use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\UID;
|
||||
@@ -142,11 +141,7 @@ class Create extends Action
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$rule = $authorization->skip(fn () => $dbForPlatform->createDocument('rules', $rule));
|
||||
} catch (Duplicate $e) {
|
||||
throw new Exception(Exception::RULE_ALREADY_EXISTS);
|
||||
}
|
||||
$rule = $this->createRule($rule, $dbForPlatform, $authorization);
|
||||
|
||||
if ($rule->getAttribute('status', '') === RULE_STATUS_CERTIFICATE_GENERATING) {
|
||||
$publisherForCertificates->enqueue(new \Appwrite\Event\Message\Certificate(
|
||||
|
||||
@@ -70,6 +70,53 @@ trait ProxyBase
|
||||
$this->assertEquals(204, $rule['headers']['status-code']);
|
||||
}
|
||||
|
||||
public function testCreateRuleDeletesOrphanedRule(): void
|
||||
{
|
||||
$domain = \uniqid() . '-orphan-api.custom.localhost';
|
||||
$orphanProject = $this->getProject(true);
|
||||
|
||||
$orphanRule = $this->client->call(Client::METHOD_POST, '/proxy/rules/api', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $orphanProject['$id'],
|
||||
'x-appwrite-key' => $orphanProject['apiKey'],
|
||||
], [
|
||||
'domain' => $domain,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $orphanRule['headers']['status-code']);
|
||||
$this->assertEquals($domain, $orphanRule['body']['domain']);
|
||||
|
||||
$duplicateRule = $this->createAPIRule($domain);
|
||||
$this->assertEquals(409, $duplicateRule['headers']['status-code']);
|
||||
|
||||
$deleteProject = $this->client->call(Client::METHOD_DELETE, '/projects/' . $orphanProject['$id'], [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $orphanProject['$id'],
|
||||
'x-appwrite-key' => $orphanProject['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(204, $deleteProject['headers']['status-code']);
|
||||
|
||||
// Project deletion removes the project document synchronously, while rule cleanup is queued.
|
||||
// Creating the same domain now should clean up that orphaned rule before retrying.
|
||||
$rule = $this->createAPIRule($domain);
|
||||
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
$this->assertEquals($domain, $rule['body']['domain']);
|
||||
|
||||
$rules = $this->listRules([
|
||||
'queries' => [
|
||||
Query::equal('domain', [$domain])->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $rules['headers']['status-code']);
|
||||
$this->assertEquals(1, $rules['body']['total']);
|
||||
$this->assertEquals($rule['body']['$id'], $rules['body']['rules'][0]['$id']);
|
||||
|
||||
$this->cleanupRule($rule['body']['$id']);
|
||||
}
|
||||
|
||||
public function testCreateRuleSetup(): void
|
||||
{
|
||||
$ruleId = $this->setupAPIRule(\uniqid() . '-api2.myapp.com');
|
||||
|
||||
Reference in New Issue
Block a user