Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
- Remove middleware reference from Gitea Traefik labels (caused routing issues) - Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s) - Add explicit service reference in Traefik labels - Fix intermittent 504 timeouts by improving PostgreSQL connection handling Fixes Gitea unreachability via git.michaelschiemer.de
198 lines
6.6 KiB
PHP
198 lines
6.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Framework\Config\Environment;
|
|
use App\Framework\Deployment\Ssl\HealthChecks\SslCertificateHealthCheck;
|
|
use App\Framework\Deployment\Ssl\Services\SslCertificateService;
|
|
use App\Framework\Deployment\Ssl\ValueObjects\CertificateStatus;
|
|
use App\Framework\Deployment\Ssl\ValueObjects\DomainName;
|
|
use App\Framework\Health\HealthCheckCategory;
|
|
use App\Framework\Health\HealthStatus;
|
|
|
|
describe('SslCertificateHealthCheck', function () {
|
|
beforeEach(function () {
|
|
$this->sslService = Mockery::mock(SslCertificateService::class);
|
|
$this->environment = Mockery::mock(Environment::class);
|
|
|
|
// Setup environment mock
|
|
$this->environment->shouldReceive('get')
|
|
->with('DOMAIN_NAME', 'michaelschiemer.de')
|
|
->andReturn('example.com');
|
|
$this->environment->shouldReceive('get')
|
|
->with('SSL_EMAIL', 'mail@michaelschiemer.de')
|
|
->andReturn('admin@example.com');
|
|
$this->environment->shouldReceive('get')
|
|
->with('LETSENCRYPT_STAGING', '0')
|
|
->andReturn('0');
|
|
|
|
$this->healthCheck = new SslCertificateHealthCheck(
|
|
$this->sslService,
|
|
$this->environment
|
|
);
|
|
});
|
|
|
|
afterEach(function () {
|
|
Mockery::close();
|
|
});
|
|
|
|
it('returns healthy status for valid certificate', function () {
|
|
$status = new CertificateStatus(
|
|
exists: true,
|
|
isValid: true,
|
|
notBefore: new DateTimeImmutable('-30 days'),
|
|
notAfter: new DateTimeImmutable('+60 days'),
|
|
issuer: 'Let\'s Encrypt Authority X3',
|
|
subject: 'example.com',
|
|
daysUntilExpiry: 60,
|
|
isExpiring: false,
|
|
isExpired: false
|
|
);
|
|
|
|
$this->sslService->shouldReceive('getStatus')
|
|
->once()
|
|
->andReturn($status);
|
|
|
|
$result = $this->healthCheck->check();
|
|
|
|
expect($result->status)->toBe(HealthStatus::HEALTHY);
|
|
expect($result->operation)->toBe('SSL Certificate Check');
|
|
expect($result->details['domain'])->toBe('example.com');
|
|
expect($result->details['days_until_expiry'])->toBe(60);
|
|
});
|
|
|
|
it('returns unhealthy status when certificate does not exist', function () {
|
|
$status = CertificateStatus::notFound();
|
|
|
|
$this->sslService->shouldReceive('getStatus')
|
|
->once()
|
|
->andReturn($status);
|
|
|
|
$result = $this->healthCheck->check();
|
|
|
|
expect($result->status)->toBe(HealthStatus::UNHEALTHY);
|
|
expect($result->reason)->toBe('Certificate not found');
|
|
});
|
|
|
|
it('returns unhealthy status for expired certificate', function () {
|
|
$status = new CertificateStatus(
|
|
exists: true,
|
|
isValid: false,
|
|
notBefore: new DateTimeImmutable('-180 days'),
|
|
notAfter: new DateTimeImmutable('-10 days'),
|
|
issuer: 'Let\'s Encrypt Authority X3',
|
|
subject: 'example.com',
|
|
daysUntilExpiry: -10,
|
|
isExpiring: false,
|
|
isExpired: true
|
|
);
|
|
|
|
$this->sslService->shouldReceive('getStatus')
|
|
->once()
|
|
->andReturn($status);
|
|
|
|
$result = $this->healthCheck->check();
|
|
|
|
expect($result->status)->toBe(HealthStatus::UNHEALTHY);
|
|
expect($result->reason)->toBe('Certificate has expired');
|
|
expect($result->details['days_since_expiry'])->toBe(10);
|
|
});
|
|
|
|
it('returns warning status for expiring certificate', function () {
|
|
$status = new CertificateStatus(
|
|
exists: true,
|
|
isValid: true,
|
|
notBefore: new DateTimeImmutable('-60 days'),
|
|
notAfter: new DateTimeImmutable('+20 days'),
|
|
issuer: 'Let\'s Encrypt Authority X3',
|
|
subject: 'example.com',
|
|
daysUntilExpiry: 20,
|
|
isExpiring: true,
|
|
isExpired: false
|
|
);
|
|
|
|
$this->sslService->shouldReceive('getStatus')
|
|
->once()
|
|
->andReturn($status);
|
|
|
|
$result = $this->healthCheck->check();
|
|
|
|
expect($result->status)->toBe(HealthStatus::WARNING);
|
|
expect($result->reason)->toBe('Certificate expires in 20 days');
|
|
expect($result->details['days_until_expiry'])->toBe(20);
|
|
});
|
|
|
|
it('returns unhealthy status for invalid certificate', function () {
|
|
$status = new CertificateStatus(
|
|
exists: true,
|
|
isValid: false,
|
|
notBefore: new DateTimeImmutable('-30 days'),
|
|
notAfter: new DateTimeImmutable('+60 days'),
|
|
issuer: null,
|
|
subject: null,
|
|
daysUntilExpiry: 60,
|
|
isExpiring: false,
|
|
isExpired: false,
|
|
errors: ['Certificate verification failed']
|
|
);
|
|
|
|
$this->sslService->shouldReceive('getStatus')
|
|
->once()
|
|
->andReturn($status);
|
|
|
|
$result = $this->healthCheck->check();
|
|
|
|
expect($result->status)->toBe(HealthStatus::UNHEALTHY);
|
|
expect($result->reason)->toBe('Certificate is invalid');
|
|
expect($result->details['errors'])->toContain('Certificate verification failed');
|
|
});
|
|
|
|
it('returns unhealthy status on exception', function () {
|
|
$this->sslService->shouldReceive('getStatus')
|
|
->once()
|
|
->andThrow(new \RuntimeException('Connection failed'));
|
|
|
|
$result = $this->healthCheck->check();
|
|
|
|
expect($result->status)->toBe(HealthStatus::UNHEALTHY);
|
|
expect($result->reason)->toBe('Health check failed');
|
|
expect($result->exception)->toBeInstanceOf(\RuntimeException::class);
|
|
});
|
|
|
|
it('has correct name and category', function () {
|
|
expect($this->healthCheck->name)->toBe('SSL Certificate');
|
|
expect($this->healthCheck->getCategory())->toBe(HealthCheckCategory::SECURITY);
|
|
});
|
|
|
|
it('has reasonable timeout', function () {
|
|
$timeout = $this->healthCheck->timeout;
|
|
|
|
expect($timeout)->toBeInt();
|
|
expect($timeout)->toBeGreaterThan(0);
|
|
expect($timeout)->toBeLessThanOrEqual(10000); // Max 10 seconds
|
|
});
|
|
|
|
it('measures response time', function () {
|
|
$status = new CertificateStatus(
|
|
exists: true,
|
|
isValid: true,
|
|
notBefore: null,
|
|
notAfter: null,
|
|
issuer: null,
|
|
subject: null,
|
|
daysUntilExpiry: 60,
|
|
isExpiring: false,
|
|
isExpired: false
|
|
);
|
|
|
|
$this->sslService->shouldReceive('getStatus')
|
|
->once()
|
|
->andReturn($status);
|
|
|
|
$result = $this->healthCheck->check();
|
|
|
|
expect($result->responseTimeMs)->toBeFloat();
|
|
expect($result->responseTimeMs)->toBeGreaterThanOrEqual(0);
|
|
});
|
|
});
|