feat: update deployment configuration and encrypted env loader
- Update Ansible playbooks and roles for application deployment - Add new Gitea/Traefik troubleshooting playbooks - Update Docker Compose configurations (base, local, staging, production) - Enhance EncryptedEnvLoader with improved error handling - Add deployment scripts (autossh setup, migration, secret testing) - Update CI/CD workflows and documentation - Add Semaphore stack configuration
This commit is contained in:
@@ -45,6 +45,15 @@ describe('EncryptedEnvLoader', function () {
|
||||
if (isset($this->envDevelopmentFile) && file_exists($this->envDevelopmentFile)) {
|
||||
unlink($this->envDevelopmentFile);
|
||||
}
|
||||
if (isset($this->envBaseFile) && file_exists($this->envBaseFile)) {
|
||||
unlink($this->envBaseFile);
|
||||
}
|
||||
if (isset($this->envLocalFile) && file_exists($this->envLocalFile)) {
|
||||
unlink($this->envLocalFile);
|
||||
}
|
||||
if (isset($this->envStagingFile) && file_exists($this->envStagingFile)) {
|
||||
unlink($this->envStagingFile);
|
||||
}
|
||||
});
|
||||
|
||||
describe('load()', function () {
|
||||
@@ -197,6 +206,197 @@ ENV);
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadEnvironment() - Base + Override Pattern', function () {
|
||||
it('loads .env.base first, then .env.local (local overrides base)', function () {
|
||||
$_ENV['APP_ENV'] = 'development';
|
||||
|
||||
// Base file with common variables
|
||||
$this->envBaseFile = $this->testDir . '/.env.base';
|
||||
file_put_contents($this->envBaseFile, <<<ENV
|
||||
APP_NAME=BaseApp
|
||||
DB_HOST=db
|
||||
DB_PORT=5432
|
||||
DB_DATABASE=michaelschiemer
|
||||
CACHE_PREFIX=app
|
||||
ENV);
|
||||
|
||||
// Local file with overrides
|
||||
$this->envLocalFile = $this->testDir . '/.env.local';
|
||||
file_put_contents($this->envLocalFile, <<<ENV
|
||||
APP_ENV=development
|
||||
APP_DEBUG=true
|
||||
DB_HOST=localhost
|
||||
DB_PORT=3307
|
||||
CACHE_PREFIX=local
|
||||
ENV);
|
||||
|
||||
$env = $this->loader->loadEnvironment($this->testDir);
|
||||
|
||||
// Base values
|
||||
expect($env->get('APP_NAME'))->toBe('BaseApp');
|
||||
expect($env->get('DB_DATABASE'))->toBe('michaelschiemer');
|
||||
|
||||
// Local overrides
|
||||
expect($env->get('APP_ENV'))->toBe('development');
|
||||
expect($env->getBool('APP_DEBUG'))->toBeTrue();
|
||||
expect($env->get('DB_HOST'))->toBe('localhost');
|
||||
expect($env->getInt('DB_PORT'))->toBe(3307);
|
||||
expect($env->get('CACHE_PREFIX'))->toBe('local');
|
||||
});
|
||||
|
||||
it('loads .env.local only if .env.base exists', function () {
|
||||
$_ENV['APP_ENV'] = 'development';
|
||||
|
||||
// Only .env.local (should fallback to legacy .env)
|
||||
$this->envLocalFile = $this->testDir . '/.env.local';
|
||||
file_put_contents($this->envLocalFile, <<<ENV
|
||||
APP_ENV=development
|
||||
DB_HOST=localhost
|
||||
ENV);
|
||||
|
||||
// Legacy .env file (fallback)
|
||||
$this->envFile = $this->testDir . '/.env';
|
||||
file_put_contents($this->envFile, <<<ENV
|
||||
APP_NAME=LegacyApp
|
||||
DB_PORT=3306
|
||||
ENV);
|
||||
|
||||
$env = $this->loader->loadEnvironment($this->testDir);
|
||||
|
||||
// Should load from legacy .env (fallback)
|
||||
expect($env->get('APP_NAME'))->toBe('LegacyApp');
|
||||
expect($env->getInt('DB_PORT'))->toBe(3306);
|
||||
|
||||
// .env.local should not be loaded if .env.base doesn't exist
|
||||
// (Fallback logic: only load .env.local if .env.base exists)
|
||||
});
|
||||
|
||||
it('falls back to legacy .env if .env.base and .env.local do not exist', function () {
|
||||
$_ENV['APP_ENV'] = 'development';
|
||||
|
||||
// Only legacy .env file
|
||||
$this->envFile = $this->testDir . '/.env';
|
||||
file_put_contents($this->envFile, <<<ENV
|
||||
APP_NAME=LegacyApp
|
||||
APP_ENV=development
|
||||
DB_HOST=localhost
|
||||
ENV);
|
||||
|
||||
$env = $this->loader->loadEnvironment($this->testDir);
|
||||
|
||||
// Should load from legacy .env
|
||||
expect($env->get('APP_NAME'))->toBe('LegacyApp');
|
||||
expect($env->get('APP_ENV'))->toBe('development');
|
||||
expect($env->get('DB_HOST'))->toBe('localhost');
|
||||
});
|
||||
|
||||
it('prioritizes system ENV over .env.base and .env.local', function () {
|
||||
$_ENV['APP_ENV'] = 'development';
|
||||
$_ENV['DB_HOST'] = 'system_host';
|
||||
|
||||
$this->envBaseFile = $this->testDir . '/.env.base';
|
||||
file_put_contents($this->envBaseFile, <<<ENV
|
||||
APP_NAME=BaseApp
|
||||
DB_HOST=db
|
||||
ENV);
|
||||
|
||||
$this->envLocalFile = $this->testDir . '/.env.local';
|
||||
file_put_contents($this->envLocalFile, <<<ENV
|
||||
DB_HOST=localhost
|
||||
ENV);
|
||||
|
||||
$env = $this->loader->loadEnvironment($this->testDir);
|
||||
|
||||
// System ENV should win
|
||||
expect($env->get('DB_HOST'))->toBe('system_host');
|
||||
|
||||
// Base values should be loaded
|
||||
expect($env->get('APP_NAME'))->toBe('BaseApp');
|
||||
});
|
||||
|
||||
it('merges .env.base, .env.local, and .env.secrets correctly', function () {
|
||||
$_ENV['APP_ENV'] = 'development';
|
||||
|
||||
$this->envBaseFile = $this->testDir . '/.env.base';
|
||||
file_put_contents($this->envBaseFile, <<<ENV
|
||||
APP_NAME=BaseApp
|
||||
DB_HOST=db
|
||||
ENV);
|
||||
|
||||
$this->envLocalFile = $this->testDir . '/.env.local';
|
||||
file_put_contents($this->envLocalFile, <<<ENV
|
||||
DB_HOST=localhost
|
||||
ENV);
|
||||
|
||||
$this->secretsFile = $this->testDir . '/.env.secrets';
|
||||
file_put_contents($this->secretsFile, <<<ENV
|
||||
SECRET_API_KEY=my_secret
|
||||
ENV);
|
||||
|
||||
$encryptionKey = 'test_encryption_key_32_chars_long';
|
||||
|
||||
$env = $this->loader->loadEnvironment($this->testDir, $encryptionKey);
|
||||
|
||||
// Base + Local + Secrets
|
||||
expect($env->get('APP_NAME'))->toBe('BaseApp');
|
||||
expect($env->get('DB_HOST'))->toBe('localhost');
|
||||
expect($env->get('SECRET_API_KEY'))->toBe('my_secret');
|
||||
});
|
||||
|
||||
it('loads .env.staging in staging environment', function () {
|
||||
$_ENV['APP_ENV'] = 'staging';
|
||||
|
||||
$this->envBaseFile = $this->testDir . '/.env.base';
|
||||
file_put_contents($this->envBaseFile, <<<ENV
|
||||
APP_NAME=BaseApp
|
||||
DB_HOST=db
|
||||
ENV);
|
||||
|
||||
$this->envStagingFile = $this->testDir . '/.env.staging';
|
||||
file_put_contents($this->envStagingFile, <<<ENV
|
||||
APP_ENV=staging
|
||||
APP_DEBUG=false
|
||||
DB_HOST=staging_db
|
||||
STAGING_FEATURE=enabled
|
||||
ENV);
|
||||
|
||||
$env = $this->loader->loadEnvironment($this->testDir);
|
||||
|
||||
// Base values
|
||||
expect($env->get('APP_NAME'))->toBe('BaseApp');
|
||||
|
||||
// Staging overrides
|
||||
expect($env->get('APP_ENV'))->toBe('staging');
|
||||
expect($env->getBool('APP_DEBUG'))->toBeFalse();
|
||||
expect($env->get('DB_HOST'))->toBe('staging_db');
|
||||
expect($env->get('STAGING_FEATURE'))->toBe('enabled');
|
||||
});
|
||||
|
||||
it('prioritizes .env.staging over .env.local in staging environment', function () {
|
||||
$_ENV['APP_ENV'] = 'staging';
|
||||
|
||||
$this->envBaseFile = $this->testDir . '/.env.base';
|
||||
file_put_contents($this->envBaseFile, <<<ENV
|
||||
DB_HOST=db
|
||||
ENV);
|
||||
|
||||
$this->envLocalFile = $this->testDir . '/.env.local';
|
||||
file_put_contents($this->envLocalFile, <<<ENV
|
||||
DB_HOST=localhost
|
||||
ENV);
|
||||
|
||||
$this->envStagingFile = $this->testDir . '/.env.staging';
|
||||
file_put_contents($this->envStagingFile, <<<ENV
|
||||
DB_HOST=staging_host
|
||||
ENV);
|
||||
|
||||
$env = $this->loader->loadEnvironment($this->testDir);
|
||||
|
||||
// Staging should win
|
||||
expect($env->get('DB_HOST'))->toBe('staging_host');
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadEnvironment() - Development Priority', function () {
|
||||
it('allows .env file to override system environment in development', function () {
|
||||
// Simulate system environment
|
||||
|
||||
Reference in New Issue
Block a user