From 9a2c6a4c4baa1fc238d4930fb8fbb5ff5c7e29db Mon Sep 17 00:00:00 2001 From: Luciano Righetti Date: Tue, 8 Mar 2022 15:51:07 +0100 Subject: [PATCH] new: add api tests for MetaTemplates and openapi spec, fix minor issues. --- composer.json | 7 +- src/Controller/MetaTemplatesController.php | 7 +- src/Model/Table/MetaTemplatesTable.php | 2 +- tests/Fixture/MetaTemplateFieldsFixture.php | 29 +++ tests/Fixture/MetaTemplatesFixture.php | 77 +++++++ .../CreateMetaTemplateApiTest.php | 53 +++++ .../ToggleEnableMetaTemplateApiTest.php | 68 ++++++ .../UpdateAllMetaTemplatesApiTest.php | 46 ++++ .../UpdateMetaTemplateByIdApiTest.php | 58 +++++ webroot/docs/openapi.yaml | 199 ++++++++++++++++++ 10 files changed, 543 insertions(+), 3 deletions(-) create mode 100644 tests/Fixture/MetaTemplateFieldsFixture.php create mode 100644 tests/Fixture/MetaTemplatesFixture.php create mode 100644 tests/TestCase/Api/MetaTemplates/CreateMetaTemplateApiTest.php create mode 100644 tests/TestCase/Api/MetaTemplates/ToggleEnableMetaTemplateApiTest.php create mode 100644 tests/TestCase/Api/MetaTemplates/UpdateAllMetaTemplatesApiTest.php create mode 100644 tests/TestCase/Api/MetaTemplates/UpdateMetaTemplateByIdApiTest.php diff --git a/composer.json b/composer.json index 7e0ae69..1b826a2 100644 --- a/composer.json +++ b/composer.json @@ -59,6 +59,11 @@ "nohup sh ./tests/Helper/wiremock/start.sh >/dev/null 2>&1 &", "phpunit", "sh ./tests/Helper/wiremock/stop.sh" + ], + "migrate": [ + "./bin/cake migrations migrate", + "./bin/cake migrations migrate -p tags", + "./bin/cake migrations migrate -p ADmad/SocialAuth" ] }, "prefer-stable": true, @@ -66,4 +71,4 @@ "sort-packages": true }, "minimum-stability": "dev" -} +} \ No newline at end of file diff --git a/src/Controller/MetaTemplatesController.php b/src/Controller/MetaTemplatesController.php index dc5607b..992279c 100644 --- a/src/Controller/MetaTemplatesController.php +++ b/src/Controller/MetaTemplatesController.php @@ -60,7 +60,12 @@ class MetaTemplatesController extends AppController if (!is_numeric($template_id)) { throw new NotFoundException(__('Invalid {0} for provided ID.', $this->MetaTemplates->getAlias(), $template_id)); } - $metaTemplate = $this->MetaTemplates->get($template_id); + // $metaTemplate = $this->MetaTemplates->get($template_id); + $metaTemplate = $this->MetaTemplates->find()->where([ + 'id' => $template_id, + 'enabled' => 1 + ])->contain(['MetaTemplateFields'])->first(); + if (empty($metaTemplate)) { throw new NotFoundException(__('Invalid {0} {1}.', $this->MetaTemplates->getAlias(), $template_id)); } diff --git a/src/Model/Table/MetaTemplatesTable.php b/src/Model/Table/MetaTemplatesTable.php index 1d029ec..91c5f49 100644 --- a/src/Model/Table/MetaTemplatesTable.php +++ b/src/Model/Table/MetaTemplatesTable.php @@ -114,7 +114,7 @@ class MetaTemplatesTable extends AppTable if ($updateStatus['up-to-date']) { $errors['message'] = __('Meta-template already up-to-date'); $success = true; - } else if ($this->isStrategyAllowed(MetaTemplatesTable::UPDATE_STRATEGY_CREATE_NEW) && $updateStatus['new']) { + } else if ($this->isStrategyAllowed(MetaTemplatesTable::UPDATE_STRATEGY_CREATE_NEW) && $updateStatus['is-new']) { $success = $this->saveNewMetaTemplate($templateOnDisk, $errors); } else if ($this->isStrategyAllowed(MetaTemplatesTable::UPDATE_STRATEGY_UPDATE_EXISTING) && $updateStatus['automatically-updateable']) { $success = $this->updateMetaTemplate($metaTemplate, $templateOnDisk, $errors); diff --git a/tests/Fixture/MetaTemplateFieldsFixture.php b/tests/Fixture/MetaTemplateFieldsFixture.php new file mode 100644 index 0000000..141a7aa --- /dev/null +++ b/tests/Fixture/MetaTemplateFieldsFixture.php @@ -0,0 +1,29 @@ +records = [ + [ + 'field' => 'test_field_1', + 'type' => 'text', + 'meta_template_id' => MetaTemplatesFixture::ENABLED_TEST_ORG_META_TEMPLATE_ID, + 'regex' => null, + 'multiple' => 1, + 'enabled' => 1, + 'counter' => 0 + ] + ]; + + parent::init(); + } +} diff --git a/tests/Fixture/MetaTemplatesFixture.php b/tests/Fixture/MetaTemplatesFixture.php new file mode 100644 index 0000000..cbe96a2 --- /dev/null +++ b/tests/Fixture/MetaTemplatesFixture.php @@ -0,0 +1,77 @@ + self::ENABLED_TEST_ORG_META_TEMPLATE_UUID, + 'name' => 'Test Org Meta Template (enabled)', + 'description' => 'Test Org Meta Template Description (enabled)', + 'version' => 2, + 'scope' => 'organisation', + 'namespace' => 'test', + 'source' => 'Cerebrate', + 'metaFields' => [ + [ + "field" => "test_field_1", + "type" => "text", + "multiple" => true + ], + [ + "field" => "test_field_2", + "type" => "text", + "multiple" => true + ] + ], + ]; + + public function init(): void + { + $faker = \Faker\Factory::create(); + + $this->records = [ + [ + 'id' => self::ENABLED_TEST_ORG_META_TEMPLATE_ID, + 'scope' => 'organisation', + 'name' => 'Test Meta Template (enabled)', + 'namespace' => 'cerebrate', + 'description' => 'Test Meta Template Description (enabled)', + 'version' => '1', + 'uuid' => self::ENABLED_TEST_ORG_META_TEMPLATE_UUID, + 'source' => 'Cerebrate', + 'enabled' => true, + 'is_default' => false, + 'created' => $faker->dateTime()->getTimestamp(), + 'modified' => $faker->dateTime()->getTimestamp() + ], + [ + 'id' => self::DISABLED_TEST_ORG_META_TEMPLATE_ID, + 'scope' => 'organisation', + 'name' => 'Test Meta Template (disabled)', + 'namespace' => 'cerebrate', + 'description' => 'Test Meta Template Description (disabled)', + 'version' => '1', + 'uuid' => self::DISABLED_TEST_ORG_META_TEMPLATE_UUID, + 'source' => 'Cerebrate', + 'enabled' => false, + 'is_default' => false, + 'created' => $faker->dateTime()->getTimestamp(), + 'modified' => $faker->dateTime()->getTimestamp() + ] + ]; + + parent::init(); + } +} diff --git a/tests/TestCase/Api/MetaTemplates/CreateMetaTemplateApiTest.php b/tests/TestCase/Api/MetaTemplates/CreateMetaTemplateApiTest.php new file mode 100644 index 0000000..bad92c3 --- /dev/null +++ b/tests/TestCase/Api/MetaTemplates/CreateMetaTemplateApiTest.php @@ -0,0 +1,53 @@ +setAuthToken(AuthKeysFixture::ADMIN_API_KEY); + + $url = sprintf('%s/%s', self::ENDPOINT, self::CSIRT_META_TEMPLATE_UUID); + $this->post($url); + + $this->assertResponseOk(); + $this->assertDbRecordExists('MetaTemplates', [ + 'uuid' => self::CSIRT_META_TEMPLATE_UUID, + ]); + } + + public function testLoadMetaTemplateNotAllowedAsRegularUser(): void + { + $this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY); + + $url = sprintf('%s/%s', self::ENDPOINT, self::CSIRT_META_TEMPLATE_UUID); + $this->post($url); + + $this->assertResponseCode(405); + $this->assertDbRecordNotExists('MetaTemplates', [ + 'uuid' => self::CSIRT_META_TEMPLATE_UUID, + ]); + } +} diff --git a/tests/TestCase/Api/MetaTemplates/ToggleEnableMetaTemplateApiTest.php b/tests/TestCase/Api/MetaTemplates/ToggleEnableMetaTemplateApiTest.php new file mode 100644 index 0000000..89ab511 --- /dev/null +++ b/tests/TestCase/Api/MetaTemplates/ToggleEnableMetaTemplateApiTest.php @@ -0,0 +1,68 @@ +setAuthToken(AuthKeysFixture::ADMIN_API_KEY); + + $url = sprintf(self::ENDPOINT, MetaTemplatesFixture::DISABLED_TEST_ORG_META_TEMPLATE_ID); + $this->post($url); + + $this->assertResponseOk(); + $this->assertDbRecordExists('MetaTemplates', [ + 'id' => MetaTemplatesFixture::DISABLED_TEST_ORG_META_TEMPLATE_ID, + 'enabled' => true + ]); + } + + public function testToggleDisabledMetaTemplate(): void + { + $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY); + + $url = sprintf(self::ENDPOINT, MetaTemplatesFixture::ENABLED_TEST_ORG_META_TEMPLATE_ID); + $this->post($url); + + $this->assertResponseOk(); + $this->assertDbRecordExists('MetaTemplates', [ + 'id' => MetaTemplatesFixture::ENABLED_TEST_ORG_META_TEMPLATE_ID, + 'enabled' => false + ]); + } + + public function testEnableMetaTemplateNotAllowedAsRegularUser(): void + { + $this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY); + + $url = sprintf(self::ENDPOINT, MetaTemplatesFixture::DISABLED_TEST_ORG_META_TEMPLATE_ID); + $this->post($url); + + $this->assertResponseCode(405); + $this->assertDbRecordExists('MetaTemplates', [ + 'id' => MetaTemplatesFixture::DISABLED_TEST_ORG_META_TEMPLATE_ID, + 'enabled' => false + ]); + } +} diff --git a/tests/TestCase/Api/MetaTemplates/UpdateAllMetaTemplatesApiTest.php b/tests/TestCase/Api/MetaTemplates/UpdateAllMetaTemplatesApiTest.php new file mode 100644 index 0000000..47b5295 --- /dev/null +++ b/tests/TestCase/Api/MetaTemplates/UpdateAllMetaTemplatesApiTest.php @@ -0,0 +1,46 @@ +setAuthToken(AuthKeysFixture::ADMIN_API_KEY); + + $this->post(self::ENDPOINT); + + $this->assertResponseOk(); + + $response = $this->getJsonResponseAsArray(); + $this->assertEmpty($response['update_errors']); + $this->assertNotEmpty($response['files_processed']); + $this->assertTrue($response['success']); + + $this->assertDbRecordExists('MetaTemplates', [ + 'id' => 3 // id 1 and 2 are loaded via MetaTemplatesFixture + ]); + } +} diff --git a/tests/TestCase/Api/MetaTemplates/UpdateMetaTemplateByIdApiTest.php b/tests/TestCase/Api/MetaTemplates/UpdateMetaTemplateByIdApiTest.php new file mode 100644 index 0000000..026c14d --- /dev/null +++ b/tests/TestCase/Api/MetaTemplates/UpdateMetaTemplateByIdApiTest.php @@ -0,0 +1,58 @@ +setAuthToken(AuthKeysFixture::ADMIN_API_KEY); + + // Dump MetaTemplate json file to disk + file_put_contents( + ROOT . '/libraries/default/meta_fields/test.json', + json_encode(MetaTemplatesFixture::ENABLED_TEST_ORG_META_TEMPLATE_SPEC) + ); + + $url = sprintf(self::ENDPOINT, MetaTemplatesFixture::ENABLED_TEST_ORG_META_TEMPLATE_ID); + $this->post($url, [ + 'update_strategy' => MetaTemplatesTable::UPDATE_STRATEGY_CREATE_NEW + ]); + + $this->assertResponseOk(); + + $response = $this->getJsonResponseAsArray(); + $this->assertEmpty($response['update_errors']); + $this->assertNotEmpty($response['files_processed']); + $this->assertTrue($response['success']); + + $this->assertDbRecordExists('MetaTemplateFields', [ + 'field' => 'test_field_2' + ]); + + // Delete MetaTemplate json file from disk + unlink(ROOT . '/libraries/default/meta_fields/test.json'); + } +} diff --git a/webroot/docs/openapi.yaml b/webroot/docs/openapi.yaml index dea0026..5a834f7 100644 --- a/webroot/docs/openapi.yaml +++ b/webroot/docs/openapi.yaml @@ -29,6 +29,8 @@ tags: description: "Authkeys are used for API access. A user can have more than one authkey, so if you would like to use separate keys per tool that queries Cerebrate, add additional keys. Use the comment field to make identifying your keys easier." - name: LocalTools description: "Cerebrate can connect to local tools via individual connectors, built to expose the various functionalities of the given tool via Cerebrate. Simply view the connectors' details and the accompanying instance list to manage the connections using the given connector." + - name: MetaTemplates + description: "" paths: /individuals/index: @@ -878,6 +880,77 @@ paths: default: $ref: "#/components/responses/ApiErrorResponse" + # MetaTemplates + /metaTemplates/createNewTemplate/{metaTemplateUuid}: + post: + summary: "Load a MetaTemplate" + operationId: loadMetaTemplate + tags: + - MetaTemplates + parameters: + - $ref: "#/components/parameters/metaTemplateUuid" + responses: + "200": + $ref: "#/components/responses/LoadMetaTemplateResponse" + "403": + $ref: "#/components/responses/UnauthorizedApiErrorResponse" + "405": + $ref: "#/components/responses/MethodNotAllowedApiErrorResponse" + default: + $ref: "#/components/responses/ApiErrorResponse" + + /metaTemplates/toggle/{metaTemplateId}/enabled: + post: + summary: "Toggle MetaTemplate enabled/disabled" + operationId: toggleEnableMetaTemplate + tags: + - MetaTemplates + parameters: + - $ref: "#/components/parameters/metaTemplateId" + responses: + "200": + $ref: "#/components/responses/MetaTemplateResponse" + "403": + $ref: "#/components/responses/UnauthorizedApiErrorResponse" + "405": + $ref: "#/components/responses/MethodNotAllowedApiErrorResponse" + default: + $ref: "#/components/responses/ApiErrorResponse" + + /metaTemplates/update/{metaTemplateId}: + post: + summary: "Update MetaTemplate by ID" + operationId: updateMetaTemplateById + tags: + - MetaTemplates + parameters: + - $ref: "#/components/parameters/metaTemplateId" + responses: + "200": + $ref: "#/components/responses/UpdateMetaTemplateResponse" + "403": + $ref: "#/components/responses/UnauthorizedApiErrorResponse" + "405": + $ref: "#/components/responses/MethodNotAllowedApiErrorResponse" + default: + $ref: "#/components/responses/ApiErrorResponse" + + /metaTemplates/updateAllTemplates: + post: + summary: "Update all MetaTemplates" + operationId: updateAllMetaTemplates + tags: + - MetaTemplates + responses: + "200": + $ref: "#/components/responses/UpdateMetaTemplateResponse" + "403": + $ref: "#/components/responses/UnauthorizedApiErrorResponse" + "405": + $ref: "#/components/responses/MethodNotAllowedApiErrorResponse" + default: + $ref: "#/components/responses/ApiErrorResponse" + components: schemas: # General @@ -1524,6 +1597,65 @@ components: items: $ref: "#/components/schemas/LocalTool" + # MetaTemplates + + MetaTemplateScope: + type: string + enum: + - "organisation" + + MetaTemplateName: + type: string + + MetaTemplateNamespace: + type: string + example: "cerebrate" + + MetaTemplateDescription: + type: string + + MetaTemplateVersion: + type: string + example: "1.0" + + MetaTemplateSource: + type: string + example: "Cerebrate" + + MetaTemplateIsEnabled: + type: boolean + + MetaTemplateIsDefault: + type: boolean + + MetaTemplate: + type: object + properties: + id: + $ref: "#/components/schemas/ID" + scope: + $ref: "#/components/schemas/MetaTemplateScope" + name: + $ref: "#/components/schemas/MetaTemplateName" + namespace: + $ref: "#/components/schemas/MetaTemplateNamespace" + description: + $ref: "#/components/schemas/MetaTemplateDescription" + version: + $ref: "#/components/schemas/MetaTemplateVersion" + uuid: + $ref: "#/components/schemas/UUID" + source: + $ref: "#/components/schemas/MetaTemplateSource" + enabled: + $ref: "#/components/schemas/MetaTemplateIsEnabled" + is_default: + $ref: "#/components/schemas/MetaTemplateIsDefault" + created: + $ref: "#/components/schemas/DateTime" + modified: + $ref: "#/components/schemas/DateTime" + # Errors ApiError: type: object @@ -1673,6 +1805,22 @@ components: type: string example: "user@example.com" + metaTemplateUuid: + name: metaTemplateUuid + in: path + description: "UUID of the MetaTemplate" + required: true + schema: + $ref: "#/components/schemas/UUID" + + metaTemplateId: + name: metaTemplateId + in: path + description: "Numeric ID of the MetaTemplate" + required: true + schema: + $ref: "#/components/schemas/ID" + securitySchemes: ApiKeyAuth: type: apiKey @@ -2329,6 +2477,57 @@ components: schema: $ref: "#/components/schemas/LocalToolList" + # MetaTemplates + MetaTemplateResponse: + description: "MetaTemplate response" + content: + application/json: + schema: + $ref: "#/components/schemas/MetaTemplate" + + LoadMetaTemplateResponse: + description: "Load MetaTemplate response" + content: + application/json: + schema: + type: object + properties: + update_errors: + type: array + items: + type: object + properties: + message: + type: string + example: "Cannot update meta-template, update strategy not provided or not allowed" + files_processed: + type: array + items: + $ref: "#/components/schemas/UUID" + success: + type: boolean + + UpdateMetaTemplateResponse: + description: "Update MetaTemplate response" + content: + application/json: + schema: + type: object + properties: + update_errors: + type: array + items: + type: object + properties: + message: + type: string + example: "Cannot update meta-template, update strategy not provided or not allowed" + files_processed: + type: array + items: + $ref: "#/components/schemas/UUID" + success: + type: boolean # Errors ApiErrorResponse: description: "Unexpected API error"