Merge pull request #9322 from appwrite/feat-add-secret-to-update-variable

Add secret param to update variable endpoint
This commit is contained in:
Matej Bačo 2025-02-11 14:50:49 +01:00 committed by GitHub
commit 1c1f9aee2c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 454 additions and 14 deletions

View file

@ -868,6 +868,11 @@ return [
'description' => 'Variable with the same ID already exists in this project. Try again with a different ID.',
'code' => 409,
],
Exception::VARIABLE_CANNOT_UNSET_SECRET => [
'name' => Exception::VARIABLE_CANNOT_UNSET_SECRET,
'description' => 'Secret variables cannot be marked as non-secret. Please re-create the variable if this is your intention.',
'code' => 400,
],
Exception::GRAPHQL_NO_QUERY => [
'name' => Exception::GRAPHQL_NO_QUERY,
'description' => 'Param "query" is not optional.',

View file

@ -1585,7 +1585,7 @@ App::post('/v1/functions/:functionId/variables')
->param('functionId', '', new UID(), 'Function unique ID.', false)
->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false)
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false)
->param('secret', false, new Boolean(), 'Is secret? Secret variables can only be updated or deleted, they cannot be read.', true)
->param('secret', true, new Boolean(), 'Secret variables can be updated or deleted, but only functions can read them during build and runtime.', true)
->inject('response')
->inject('dbForProject')
->inject('dbForPlatform')
@ -1729,10 +1729,11 @@ App::put('/v1/functions/:functionId/variables/:variableId')
->param('variableId', '', new UID(), 'Variable unique ID.', false)
->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false)
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', true)
->param('secret', null, new Boolean(), 'Secret variables can be updated or deleted, but only functions can read them during build and runtime.', true)
->inject('response')
->inject('dbForProject')
->inject('dbForPlatform')
->action(function (string $functionId, string $variableId, string $key, ?string $value, Response $response, Database $dbForProject, Database $dbForPlatform) {
->action(function (string $functionId, string $variableId, string $key, ?string $value, ?bool $secret, Response $response, Database $dbForProject, Database $dbForPlatform) {
$function = $dbForProject->getDocument('functions', $functionId);
@ -1749,9 +1750,14 @@ App::put('/v1/functions/:functionId/variables/:variableId')
throw new Exception(Exception::VARIABLE_NOT_FOUND);
}
if ($variable->getAttribute('secret') === true && $secret === false) {
throw new Exception(Exception::VARIABLE_CANNOT_UNSET_SECRET);
}
$variable
->setAttribute('key', $key)
->setAttribute('value', $value ?? $variable->getAttribute('value'))
->setAttribute('secret', $secret ?? $variable->getAttribute('secret'))
->setAttribute('search', implode(' ', [$variableId, $function->getId(), $key, 'function']));
try {

View file

@ -388,7 +388,7 @@ App::post('/v1/project/variables')
))
->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false)
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false)
->param('secret', false, new Boolean(), 'Is secret? Secret variables can only be updated or deleted, they cannot be read.', true)
->param('secret', true, new Boolean(), 'Secret variables can be updated or deleted, but only projects can read them during build and runtime.', true)
->inject('project')
->inject('response')
->inject('dbForProject')
@ -509,19 +509,25 @@ App::put('/v1/project/variables/:variableId')
->param('variableId', '', new UID(), 'Variable unique ID.', false)
->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false)
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', true)
->param('secret', null, new Boolean(), 'Secret variables can be updated or deleted, but only projects can read them during build and runtime.', true)
->inject('project')
->inject('response')
->inject('dbForProject')
->inject('dbForPlatform')
->action(function (string $variableId, string $key, ?string $value, Document $project, Response $response, Database $dbForProject, Database $dbForPlatform) {
->action(function (string $variableId, string $key, ?string $value, ?bool $secret, Document $project, Response $response, Database $dbForProject, Database $dbForPlatform) {
$variable = $dbForProject->getDocument('variables', $variableId);
if ($variable === false || $variable->isEmpty() || $variable->getAttribute('resourceType') !== 'project') {
throw new Exception(Exception::VARIABLE_NOT_FOUND);
}
if ($variable->getAttribute('secret') === true && $secret === false) {
throw new Exception(Exception::VARIABLE_CANNOT_UNSET_SECRET);
}
$variable
->setAttribute('key', $key)
->setAttribute('value', $value ?? $variable->getAttribute('value'))
->setAttribute('secret', $secret ?? $variable->getAttribute('secret'))
->setAttribute('search', implode(' ', [$variableId, $key, 'project']));
try {

View file

@ -255,6 +255,7 @@ class Exception extends \Exception
/** Variables */
public const VARIABLE_NOT_FOUND = 'variable_not_found';
public const VARIABLE_ALREADY_EXISTS = 'variable_already_exists';
public const VARIABLE_CANNOT_UNSET_SECRET = 'variable_cannot_unset_secret';
/** Platform */
public const PLATFORM_NOT_FOUND = 'platform_not_found';

View file

@ -56,14 +56,13 @@ class Create extends Base
->param('siteId', '', new UID(), 'Site unique ID.', false)
->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false)
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false)
->param('secret', false, new Boolean(), 'Is secret? Secret variables can only be updated or deleted, they cannot be read.', true)
->param('secret', true, new Boolean(), 'Secret variables can be updated or deleted, but only sites can read them during build and runtime.', true)
->inject('response')
->inject('dbForProject')
->inject('dbForPlatform')
->callback([$this, 'action']);
}
public function action(string $siteId, string $key, string $value, bool $secret, Response $response, Database $dbForProject, Database $dbForPlatform)
public function action(string $siteId, string $key, string $value, bool $secret, Response $response, Database $dbForProject)
{
$site = $dbForProject->getDocument('sites', $siteId);

View file

@ -13,6 +13,7 @@ use Utopia\Database\Exception\Duplicate as DuplicateException;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Boolean;
use Utopia\Validator\Text;
class Update extends Base
@ -52,12 +53,13 @@ class Update extends Base
->param('variableId', '', new UID(), 'Variable unique ID.', false)
->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false)
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', true)
->param('secret', null, new Boolean(), 'Secret variables can be updated or deleted, but only sites can read them during build and runtime.', true)
->inject('response')
->inject('dbForProject')
->callback([$this, 'action']);
}
public function action(string $siteId, string $variableId, string $key, ?string $value, Response $response, Database $dbForProject)
public function action(string $siteId, string $variableId, string $key, ?string $value, ?bool $secret, Response $response, Database $dbForProject)
{
$site = $dbForProject->getDocument('sites', $siteId);
@ -74,9 +76,14 @@ class Update extends Base
throw new Exception(Exception::VARIABLE_NOT_FOUND);
}
if ($variable->getAttribute('secret') === true && $secret === false) {
throw new Exception(Exception::VARIABLE_CANNOT_UNSET_SECRET);
}
$variable
->setAttribute('key', $key)
->setAttribute('value', $value ?? $variable->getAttribute('value'))
->setAttribute('secret', $secret ?? $variable->getAttribute('secret'))
->setAttribute('search', implode(' ', [$variableId, $site->getId(), $key, 'site']));
try {

View file

@ -82,6 +82,46 @@ trait FunctionsBase
return $variable;
}
protected function getVariable(string $functionId, string $variableId): mixed
{
$variable = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/variables/' . $variableId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
return $variable;
}
protected function updateVariable(string $functionId, string $variableId, mixed $params): mixed
{
$variable = $this->client->call(Client::METHOD_PUT, '/functions/' . $functionId . '/variables/' . $variableId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), $params);
return $variable;
}
protected function listVariables(string $functionId, mixed $params = []): mixed
{
$variables = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/variables', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), $params);
return $variables;
}
protected function deleteVariable(string $functionId, string $variableId): mixed
{
$variable = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId . '/variables/' . $variableId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
return $variable;
}
protected function getFunction(string $functionId): mixed
{
$function = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId, array_merge([

View file

@ -110,7 +110,8 @@ class FunctionsConsoleClientTest extends Scope
$data['functionId'],
[
'key' => 'APP_TEST',
'value' => 'TESTINGVALUE'
'value' => 'TESTINGVALUE',
'secret' => false
]
);
@ -131,6 +132,7 @@ class FunctionsConsoleClientTest extends Scope
$this->assertEquals(201, $variable['headers']['status-code']);
$this->assertEquals('APP_TEST_1', $variable['body']['key']);
$this->assertEmpty($variable['body']['value']);
$this->assertTrue($variable['body']['secret']);
$secretVariableId = $variable['body']['$id'];
@ -142,7 +144,8 @@ class FunctionsConsoleClientTest extends Scope
$data['functionId'],
[
'key' => 'APP_TEST',
'value' => 'ANOTHERTESTINGVALUE'
'value' => 'ANOTHERTESTINGVALUE',
'secret' => false
]
);
@ -320,6 +323,41 @@ class FunctionsConsoleClientTest extends Scope
$this->assertEquals("APP_TEST_UPDATE_2", $variable['body']['key']);
$this->assertEquals("TESTINGVALUEUPDATED", $variable['body']['value']);
// convert non-secret variable to secret
$response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'key' => 'APP_TEST_UPDATE_2',
'secret' => true
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals("APP_TEST_UPDATE_2", $response['body']['key']);
$this->assertEmpty($response['body']['value']);
$this->assertTrue($response['body']['secret']);
$variable = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertEquals(200, $variable['headers']['status-code']);
$this->assertEquals("APP_TEST_UPDATE_2", $variable['body']['key']);
$this->assertEmpty($variable['body']['value']);
$this->assertTrue($variable['body']['secret']);
// convert secret variable to non-secret
$response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'key' => 'APP_TEST_UPDATE',
'secret' => false
]);
$this->assertEquals(400, $response['headers']['status-code']);
/**
* Test for FAILURE
*/
@ -410,4 +448,53 @@ class FunctionsConsoleClientTest extends Scope
return $data;
}
public function testVariableE2E(): void
{
$function = $this->createFunction([
'functionId' => ID::unique(),
'runtime' => 'node-18.0',
'name' => 'Variable E2E Test',
'entrypoint' => 'index.js',
'logging' => false,
'execute' => ['any']
]);
$this->assertEquals(201, $function['headers']['status-code']);
$this->assertFalse($function['body']['logging']);
$this->assertNotEmpty($function['body']['$id']);
$functionId = $function['body']['$id'] ?? '';
// create variable
$variable = $this->createVariable($functionId, [
'key' => 'CUSTOM_VARIABLE',
'value' => 'a_secret_value',
'secret' => true,
]);
$this->assertEquals(201, $variable['headers']['status-code']);
$this->assertNotEmpty($variable['body']['$id']);
$this->assertEquals('CUSTOM_VARIABLE', $variable['body']['key']);
$this->assertEquals('', $variable['body']['value']);
$this->assertEquals(true, $variable['body']['secret']);
$deploymentId = $this->setupDeployment($functionId, [
'entrypoint' => 'index.js',
'code' => $this->packageFunction('node'),
'activate' => true
]);
$this->assertNotEmpty($deploymentId);
$execution = $this->createExecution($functionId);
$this->assertEquals(201, $execution['headers']['status-code']);
$this->assertEmpty($execution['body']['logs']);
$this->assertEmpty($execution['body']['errors']);
$body = json_decode($execution['body']['responseBody']);
$this->assertEquals('a_secret_value', $body->CUSTOM_VARIABLE);
$this->cleanupFunction($functionId);
}
}

View file

@ -38,7 +38,7 @@ class FunctionsCustomServerTest extends Scope
'timeout' => 10,
]);
$functionId = $functionId = $function['body']['$id'] ?? '';
$functionId = $function['body']['$id'] ?? '';
$dateValidator = new DatetimeValidator();
$this->assertEquals(201, $function['headers']['status-code']);
@ -356,7 +356,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(201, $function['headers']['status-code']);
$this->assertNotEmpty($function['body']['$id']);
$functionId = $functionId = $function['body']['$id'] ?? '';
$functionId = $function['body']['$id'] ?? '';
$deployments = $this->listDeployments($functionId);
@ -1898,7 +1898,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertFalse($function['body']['logging']);
$this->assertNotEmpty($function['body']['$id']);
$functionId = $functionId = $function['body']['$id'] ?? '';
$functionId = $function['body']['$id'] ?? '';
$this->setupDeployment($functionId, [
'code' => $this->packageFunction('node'),

View file

@ -3923,10 +3923,14 @@ class ProjectsConsoleClientTest extends Scope
'x-appwrite-mode' => 'admin',
], $this->getHeaders()), [
'key' => 'APP_TEST',
'value' => 'TESTINGVALUE'
'value' => 'TESTINGVALUE',
'secret' => false
]);
$this->assertEquals(201, $variable['headers']['status-code']);
$this->assertEquals('APP_TEST', $variable['body']['key']);
$this->assertEquals('TESTINGVALUE', $variable['body']['value']);
$this->assertFalse($variable['body']['secret']);
$variableId = $variable['body']['$id'];
// test for secret variable
@ -4047,6 +4051,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals("APP_TEST_1", $response['body']['key']);
$this->assertEmpty($response['body']['value']);
$this->assertTrue($response['body']['secret']);
/**
* Test for FAILURE
@ -4118,6 +4123,17 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals("APP_TEST_UPDATE_1", $variable['body']['key']);
$this->assertEmpty($variable['body']['value']);
$response = $this->client->call(Client::METHOD_PUT, '/project/variables/' . $data['secretVariableId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $data['projectId'],
'x-appwrite-mode' => 'admin',
], $this->getHeaders()), [
'key' => 'APP_TEST_UPDATE_1',
'secret' => false,
]);
$this->assertEquals(400, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_GET, '/project/variables', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $data['projectId'],

View file

@ -104,6 +104,46 @@ trait SitesBase
return $variable;
}
protected function getVariable(string $siteId, string $variableId): mixed
{
$variable = $this->client->call(Client::METHOD_GET, '/sites/' . $siteId . '/variables/' . $variableId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
return $variable;
}
protected function listVariables(string $siteId, mixed $params = []): mixed
{
$variables = $this->client->call(Client::METHOD_GET, '/sites/' . $siteId . '/variables', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), $params);
return $variables;
}
protected function updateVariable(string $siteId, string $variableId, mixed $params): mixed
{
$variable = $this->client->call(Client::METHOD_PUT, '/sites/' . $siteId . '/variables/' . $variableId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), $params);
return $variable;
}
protected function deleteVariable(string $siteId, string $variableId): mixed
{
$variable = $this->client->call(Client::METHOD_DELETE, '/sites/' . $siteId . '/variables/' . $variableId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
return $variable;
}
protected function getSite(string $siteId): mixed
{
$site = $this->client->call(Client::METHOD_GET, '/sites/' . $siteId, array_merge([

View file

@ -65,6 +65,193 @@ class SitesCustomServerTest extends Scope
$this->cleanupSite($siteId);
}
public function testVariables(): void
{
$site = $this->createSite([
'buildRuntime' => 'ssr-22',
'fallbackFile' => null,
'framework' => 'other',
'name' => 'Test Site',
'outputDirectory' => './',
'siteId' => ID::unique()
]);
$siteId = $site['body']['$id'] ?? '';
$this->assertEquals(201, $site['headers']['status-code']);
$this->assertNotEmpty($site['body']['$id']);
$this->assertEquals('Test Site', $site['body']['name']);
$variable = $this->createVariable($siteId, [
'key' => 'siteKey1',
'value' => 'siteValue1',
'secret' => false,
]);
$this->assertEquals(201, $variable['headers']['status-code']);
$this->assertNotEmpty($variable['body']['$id']);
$this->assertEquals('siteKey1', $variable['body']['key']);
$this->assertEquals('siteValue1', $variable['body']['value']);
$this->assertEquals(false, $variable['body']['secret']);
$variable2 = $this->createVariable($siteId, [
'key' => 'siteKey2',
'value' => 'siteValue2',
'secret' => false,
]);
$this->assertEquals(201, $variable2['headers']['status-code']);
$this->assertNotEmpty($variable2['body']['$id']);
$this->assertEquals('siteKey2', $variable2['body']['key']);
$this->assertEquals('siteValue2', $variable2['body']['value']);
$this->assertEquals(false, $variable2['body']['secret']);
$secretVariable = $this->createVariable($siteId, [
'key' => 'siteKey3',
'value' => 'siteValue3',
'secret' => true,
]);
$this->assertEquals(201, $secretVariable['headers']['status-code']);
$this->assertNotEmpty($secretVariable['body']['$id']);
$this->assertEquals('siteKey3', $secretVariable['body']['key']);
$this->assertEquals('', $secretVariable['body']['value']);
$this->assertEquals(true, $secretVariable['body']['secret']);
$variable = $this->getVariable($siteId, $variable['body']['$id']);
$this->assertEquals(200, $variable['headers']['status-code']);
$this->assertNotEmpty($variable['body']['$id']);
$this->assertEquals('siteKey1', $variable['body']['key']);
$this->assertEquals('siteValue1', $variable['body']['value']);
$this->assertEquals(false, $variable['body']['secret']);
$secretVariable = $this->getVariable($siteId, $secretVariable['body']['$id']);
$this->assertEquals(200, $secretVariable['headers']['status-code']);
$this->assertNotEmpty($secretVariable['body']['$id']);
$this->assertEquals('siteKey3', $secretVariable['body']['key']);
$this->assertEquals('', $secretVariable['body']['value']);
$this->assertEquals(true, $secretVariable['body']['secret']);
$variable = $this->updateVariable($siteId, $variable['body']['$id'], [
'key' => 'siteKey1Updated',
'value' => 'siteValue1Updated',
]);
$this->assertEquals(200, $variable['headers']['status-code']);
$this->assertNotEmpty($variable['body']['$id']);
$this->assertEquals('siteKey1Updated', $variable['body']['key']);
$this->assertEquals('siteValue1Updated', $variable['body']['value']);
$this->assertEquals(false, $variable['body']['secret']);
$variable = $this->updateVariable($siteId, $variable['body']['$id'], [
'key' => 'siteKey1Updated',
'secret' => true,
]);
$this->assertEquals(200, $variable['headers']['status-code']);
$this->assertNotEmpty($variable['body']['$id']);
$this->assertEquals('siteKey1Updated', $variable['body']['key']);
$this->assertEquals('', $variable['body']['value']);
$this->assertEquals(true, $variable['body']['secret']);
$secretVariable = $this->updateVariable($siteId, $secretVariable['body']['$id'], [
'key' => 'siteKey3',
'value' => 'siteValue3Updated',
]);
$this->assertEquals(200, $secretVariable['headers']['status-code']);
$this->assertNotEmpty($secretVariable['body']['$id']);
$this->assertEquals('siteKey3', $secretVariable['body']['key']);
$this->assertEquals('', $secretVariable['body']['value']);
$this->assertEquals(true, $secretVariable['body']['secret']);
$response = $this->updateVariable($siteId, $secretVariable['body']['$id'], [
'key' => 'siteKey3',
'secret' => false,
]);
$this->assertEquals(400, $response['headers']['status-code']);
$secretVariable = $this->getVariable($siteId, $secretVariable['body']['$id']);
$this->assertEquals(200, $secretVariable['headers']['status-code']);
$this->assertNotEmpty($secretVariable['body']['$id']);
$this->assertEquals('siteKey3', $secretVariable['body']['key']);
$this->assertEquals('', $secretVariable['body']['value']);
$this->assertEquals(true, $secretVariable['body']['secret']);
$variables = $this->listVariables($siteId);
$this->assertEquals(200, $variables['headers']['status-code']);
$this->assertCount(3, $variables['body']['variables']);
$response = $this->deleteVariable($siteId, $variable['body']['$id']);
$this->assertEquals(204, $response['headers']['status-code']);
$response = $this->deleteVariable($siteId, $variable2['body']['$id']);
$this->assertEquals(204, $response['headers']['status-code']);
$response = $this->deleteVariable($siteId, $secretVariable['body']['$id']);
$this->assertEquals(204, $response['headers']['status-code']);
$variables = $this->listVariables($siteId);
$this->assertEquals(200, $variables['headers']['status-code']);
$this->assertCount(0, $variables['body']['variables']);
$this->cleanupSite($siteId);
}
public function testVariablesE2E(): void
{
$siteId = $this->setupSite([
'siteId' => ID::unique(),
'name' => 'Astro site',
'framework' => 'astro',
'adapter' => 'ssr',
'buildRuntime' => 'ssr-22',
'outputDirectory' => './dist',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'fallbackFile' => '',
]);
$this->assertNotEmpty($siteId);
$secretVariable = $this->createVariable($siteId, [
'key' => 'name',
'value' => 'Appwrite',
]);
$this->assertEquals(201, $secretVariable['headers']['status-code']);
$this->assertNotEmpty($secretVariable['body']['$id']);
$this->assertEquals('name', $secretVariable['body']['key']);
$this->assertEquals('', $secretVariable['body']['value']);
$this->assertEquals(true, $secretVariable['body']['secret']);
$deploymentId = $this->setupDeployment($siteId, [
'code' => $this->packageSite('astro'),
'activate' => 'true'
]);
$this->assertNotEmpty($deploymentId);
$domain = $this->getSiteDomain($siteId);
$proxyClient = new Client();
$proxyClient->setEndpoint('http://' . $domain);
$response = $proxyClient->call(Client::METHOD_GET, '/', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
]));
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertStringContainsString("Env variable is Appwrite", $response['body']);
$this->assertStringNotContainsString("Variable not found", $response['body']);
$this->cleanupSite($siteId);
}
public function testListSites(): void
{
/**

View file

@ -0,0 +1,10 @@
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';
import 'dotenv/config';
export default defineConfig({
output: 'server',
adapter: node({
mode: 'standalone'
}),
});

View file

@ -0,0 +1,16 @@
{
"name": "my-astro-app",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/node": "^9.0.2",
"astro": "^5.2.5",
"dotenv": "^16.4.7"
}
}

View file

@ -0,0 +1,15 @@
---
const value = import.meta.env.name || 'Variable not found';
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Astro SSR</title>
</head>
<body>
<p>Env variable is {value}</p>
</body>
</html>

View file

@ -0,0 +1,5 @@
{
"extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}