Restore API startup by isolating Bird activation (#334)

Keep Bird activation outside the PHP-FPM/nginx startup path so Bird configuration failures cannot make the core API unavailable. Retain guarded explicit activation and regression coverage.
This commit is contained in:
Jeppe B
2026-07-29 22:41:19 +02:00
committed by GitHub
parent a442e70744
commit 4587bdfb06
3 changed files with 23 additions and 19 deletions
-3
View File
@@ -2,8 +2,5 @@
set -e
mkdir -p /run/nginx
if [ "${CONFIG_DB_TARGET:-live}" = "live" ]; then
php /var/www/html/scripts/bird-control-plane-auto-activate.php
fi
php-fpm -D
exec nginx -g "daemon off;"
+19 -12
View File
@@ -44,15 +44,14 @@ deletion, physical gate actions, arbitrary recipients, attachments, or a
generic proxy. Outbound references are durably reserved before a provider
request; an ambiguous outcome must be inspected through
`/bird/control-plane/v1/messages/by-reference` and is never blindly retried.
Credentials and write switches can only be changed by the guarded CLI startup
path or its explicit break-glass command, never by a web request.
Credentials and write switches can only be changed by the guarded CLI
activation command, never by a web request.
### Schema deployment and preflight
The durable webhook and outbound-action ledgers use checked-in schema version
`1`. Schema changes are never run from a web request or worker. Production
startup applies and verifies the schema automatically; these commands remain
available for manual preflight and break-glass recovery:
`1`. Schema changes are never run from a web request, worker, or core API
startup. Use these commands for deployment preflight and recovery:
```bash
php scripts/bird-control-plane-schema.php check
@@ -64,15 +63,21 @@ php scripts/bird-control-plane-schema.php check
publishes read-only `schema: {ready, version, expectedVersion, missing}` state.
Ledger-dependent reads, webhook ingestion, messages, and operational actions
fail closed with HTTP `503` and code `bird_schema_not_ready` until the preflight
is ready. Production auto-activation applies and verifies the schema before
enabling any Bird write switch; the manual command remains a diagnostic and
break-glass path.
is ready. Explicit activation applies and verifies the schema before enabling
any Bird write switch.
### Fail-closed production auto-activation
### Fail-closed production activation
The Coolify production container runs activation before PHP-FPM or nginx. It
first transactionally disables bootstrap readiness and all three write
switches. It then canonicalizes the existing legacy workspace/channel
Bird activation is deliberately separate from PHP-FPM and nginx startup, so a
Bird provider or configuration failure cannot make the core API unavailable.
Run the guarded activation explicitly in the deployed API container:
```bash
php /var/www/html/scripts/bird-control-plane-auto-activate.php
```
The command first transactionally disables bootstrap readiness and all three
write switches. It then canonicalizes the existing legacy workspace/channel
configuration, applies and checks schema version `1`, validates configured
channels and conversations, resolves the access-key participant, pins the
public webhook URL to
@@ -80,6 +85,8 @@ public webhook URL to
verifies webhooks while writes remain dark. Only then does one transaction
enable bootstrap readiness, the Control Plane, outbound messaging, and
operational-action switches, followed by final readiness checks.
Any failure returns a non-zero exit code and re-disables the Bird capabilities
without stopping or restarting the core API.
It preserves existing valid credentials; otherwise it generates distinct
48-byte random Control Plane and webhook secrets inside the container. The
webhook key remains backend-only.
@@ -398,16 +398,16 @@ it('accepts staged activation only while every write capability remains disabled
expect(bird_control_plane_auto_activation::stagedActivationReady($status))->toBeFalse();
});
it('wires fail-closed startup and a pinned local bootstrap without plaintext exposure', function (): void {
it('keeps Bird activation outside core API startup and pins local bootstrap without plaintext exposure', function (): void {
$repoRoot = getenv('PLENO_REPO_ROOT_FOR_TESTS');
expect($repoRoot)->toBeString()->not->toBe('');
$start = file_get_contents($repoRoot . '/services/coolify/api/start.sh');
$local = file_get_contents($repoRoot . '/scripts/bird-control-plane-bootstrap-local.sh');
$route = file_get_contents(app_path('routes/birdControlPlaneRoute.php'));
expect($start)->toContain('bird-control-plane-auto-activate.php')
->and(strpos($start, 'bird-control-plane-auto-activate.php'))
->toBeLessThan(strpos($start, 'php-fpm -D'))
expect($start)->not->toContain('bird-control-plane-auto-activate.php')
->and($start)->toContain('php-fpm -D')
->and($start)->toContain('exec nginx')
->and($local)->toContain(
"bootstrap_url='https://api.truckwash.io:4433/bird/control-plane/v1/bootstrap'"
)