feat: PHP SDK proof-of-concept (Laravel + Symfony)#409
Draft
jkbennemann wants to merge 9 commits intodmno-dev:mainfrom
Draft
feat: PHP SDK proof-of-concept (Laravel + Symfony)#409jkbennemann wants to merge 9 commits intodmno-dev:mainfrom
jkbennemann wants to merge 9 commits intodmno-dev:mainfrom
Conversation
added 9 commits
March 14, 2026 08:57
Framework-agnostic core library for the compiled manifest approach. Reads .varlock/manifest.json at boot, validates env vars against schema rules, coerces string values to PHP types, and provides log redaction. Key components: - ManifestLoader: parses the JSON manifest - Validator: checks required fields and type constraints - TypeCoercer: converts strings to bool/int/float based on schema - VarlockState: static singleton holding resolved values and sensitive map - RedactionHelper: replaces sensitive values with [REDACTED] - SecretResolverFactory: registry dispatching to plugin resolvers - HttpSecretResolver: calls any HTTP secrets API with response caching - EnvSecretResolver: reads from process env (Docker/K8s injection) - CallbackSecretResolver: wraps user-provided closures - ChainSecretResolver: tries resolvers in order with fallback No framework dependencies — requires only PHP 8.2.
Laravel integration that hooks into the framework boot sequence via afterBootstrapping(LoadEnvironmentVariables::class). This ensures secrets resolved from external APIs are available BEFORE config files call env(), solving the timing problem where config is parsed once at boot with whatever values are in $_ENV at that moment. - VarlockBootstrap: resolves secrets, validates, coerces types, populates env - VarlockServiceProvider: registers artisan command and Monolog processor - StatusCommand: `php artisan varlock:status` shows loaded vars with redaction - RedactSensitiveProcessor: Monolog processor replacing secrets with [REDACTED] Handles Laravel config caching gracefully — skips resolution when bootstrap/cache/config.php exists since env vars are not read at runtime.
Symfony integration that bootstraps inside the runtime closure in public/index.php, after Dotenv has loaded but before the kernel boots. Unlike the Laravel integration, values are stored as strings only — Symfony's env processors (%env(bool:APP_DEBUG)%) handle type casting in config files. - VarlockBootstrap: resolves secrets, validates, populates env - VarlockBundle: registers Monolog processor via dependency injection - RedactSensitiveProcessor: Monolog processor replacing secrets with [REDACTED]
The manifest demonstrates the compiled manifest format with resolve blocks pointing sensitive items at an HTTP secrets API. Non-sensitive items use defaults. No secret values appear in the manifest. The mock server (mock-secret-server.php) simulates what 1Password Connect, HashiCorp Vault, or any secrets HTTP API would return. Serves on localhost:9777 for local development and demo purposes.
Demonstrates the full flow: empty .env (no secrets on filesystem), secrets resolved from mock HTTP API at boot, log redaction working. Integration points: - bootstrap/app.php: afterBootstrapping hook for early env injection - composer.json: path repositories pointing to local SDK packages - .varlock/manifest.json: schema with resolve blocks for sensitive items - routes/web.php: /varlock/status, /varlock/log-test, /varlock/validation-test The .env file has APP_KEY= and DB_PASSWORD= (empty). These are resolved from the mock secret server at runtime via HttpSecretResolver.
Demonstrates varlock in Symfony's boot model: secrets resolved inside the runtime closure after Dotenv has loaded, before the kernel boots. Integration points: - public/index.php: VarlockBootstrap::load() in the runtime closure - config/bundles.php: VarlockBundle registered for Monolog processor - .varlock/manifest.json: schema with resolve blocks for sensitive items - src/Controller/VarlockController.php: /varlock/status, /varlock/log-test The .env follows Symfony convention (committed with empty placeholders). Secrets are resolved from the mock HTTP API, never stored in .env files.
README.md covers the full PoC for a JS-focused audience: - How .env works in PHP vs Node.js (Laravel and Symfony boot sequences) - The compiled manifest approach and why PHP needs it - Secret resolution architecture (HTTP, env, callback, chain resolvers) - The AI agent safety argument (no secrets on filesystem) - Running the demo end-to-end - What varlock compile would need to generate - Design decisions and extending to other languages Gitignore additions: vendor/, composer.lock, framework-specific .env rules following each framework's convention (Laravel .env gitignored, Symfony .env committed with empty placeholders).
VarlockBootstrap::load() runs inside afterBootstrapping() — before Laravel's config service, logger, or exception handler exist. Previously, any failure (e.g. secret server unreachable) threw an exception that Laravel tried to log, cascading into "Target class [config] does not exist". Now the bootstrap: - Catches all exceptions itself and writes to STDERR with color codes - Collects per-key resolution errors and shows them as warnings - Still fails fast on validation (required vars missing) but with a clean message instead of a framework crash - Shows a minimal HTML error for browser requests during development
|
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #359
What
PoC for bringing varlock to PHP via a compiled manifest approach.
varlock compileproduces.varlock/manifest.jsoncontaining schema rules and resolver references (zero secrets). PHP SDKs read this at boot, validate env, resolve secrets via HTTP, and redact logs.No
exec(), no Node.js at runtime, no sidecar.Packages
varlock/php-corepackages/sdks/php-core/varlock/laravelpackages/sdks/php-laravel/varlock/symfony-bundlepackages/sdks/php-symfony/Quick start
The
.envfiles have empty values for all secrets. They're resolved from the HTTP API at boot.How it works (short version)
.envinto$_ENV(secrets are empty)VarlockBootstrap::load()reads the manifest, calls the secrets API for items with aresolveblock, writes values back into$_ENVenv('DB_PASSWORD')now returns the resolved secretThe tricky part is boot timing — this must happen after Dotenv but before config parsing. The README (
packages/sdks/README.md) explains how this works in both Laravel and Symfony, written for a JS audience.What this needs from varlock core
A
varlock compilecommand that emitsmanifest.json. The README has a TypeScript interface for the expected schema. Everything else is self-contained.Why
AI coding agents can read
.envfiles. With this approach,.envcontains zero secrets — the manifest tells the SDK how to resolve them at runtime, not what they are. Secrets only exist in process memory.