From 49abfce51754f4844479744bd3fa1f9d458ba533 Mon Sep 17 00:00:00 2001 From: "A. B. M. Mahmudul Hasan" Date: Sun, 16 Aug 2026 15:28:48 +0600 Subject: [PATCH] removing env keys --- README.md | 26 +++++++++++---------- docs/cache.rst | 28 ++++++++++++----------- docs/security.rst | 26 +++++++++++---------- src/Cache/CacheOptions.php | 12 ---------- tests/Cache/ArchitectureHardeningTest.php | 4 ++++ 5 files changed, 47 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 5446efa..d6a537e 100644 --- a/README.md +++ b/README.md @@ -129,24 +129,26 @@ A bulk read asks L1 for the full batch, asks later tiers only for remaining keys Payload and runtime policy is provided at construction and never stored globally: ```php +use Infocyph\CacheLayer\Cache\Cache; use Infocyph\CacheLayer\Cache\CacheOptions; -$options = new CacheOptions( - integrityKey: $_ENV['CACHE_INTEGRITY_KEY'], - maxPayloadBytes: 8_388_608, - compressionThreshold: 4096, - compressionLevel: 6, - allowClosures: false, - allowObjects: false, - failOpen: true, -); - -$cache = Cache::redis('app', options: $options); +function createCache(string $integrityKey): Cache +{ + return Cache::redis('app', options: new CacheOptions( + integrityKey: $integrityKey, + maxPayloadBytes: 8_388_608, + compressionThreshold: 4096, + compressionLevel: 6, + allowClosures: false, + allowObjects: false, + failOpen: true, + )); +} ``` Records use only the CacheLayer v2 markers `cl2:`, `cl2-gz:`, and `cl2-sig:`. Compression is threshold-based and retained only when smaller. HMAC verification, payload bounds, bounded decompression, and deserialization policy are isolated per cache instance. Corrupt payloads are safe misses. -Construction and configuration errors throw. Runtime backend failures default to fail-open: reads become misses, writes/deletes return `false`, and `backend_failure` is recorded. Set `failOpen: false` to propagate runtime failures. `CacheOptions::fromEnvironment()` explicitly reads `CACHELAYER_PAYLOAD_INTEGRITY_KEY` and `CACHELAYER_MAX_PAYLOAD_BYTES`; environment state is never read implicitly. +Construction and configuration errors throw. Runtime backend failures default to fail-open: reads become misses, writes/deletes return `false`, and `backend_failure` is recorded. Set `failOpen: false` to propagate runtime failures. Pass deploy-varying values from the application's composition root; CacheLayer never reads process environment state. ## Node Cache diff --git a/docs/cache.rst b/docs/cache.rst index 6174993..37c5b0a 100644 --- a/docs/cache.rst +++ b/docs/cache.rst @@ -66,19 +66,21 @@ Immutable options use Infocyph\CacheLayer\Cache\Cache; use Infocyph\CacheLayer\Cache\CacheOptions; - $cache = Cache::redis('app', options: new CacheOptions( - integrityKey: $_ENV['CACHE_INTEGRITY_KEY'], - maxPayloadBytes: 8_388_608, - compressionThreshold: 4096, - allowClosures: false, - allowObjects: false, - failOpen: true, - )); - -``CacheOptions::fromEnvironment()`` is the explicit opt-in for -``CACHELAYER_PAYLOAD_INTEGRITY_KEY`` and ``CACHELAYER_MAX_PAYLOAD_BYTES``. -Options are isolated per instance and cannot be changed after record processing -begins. + function createCache(string $integrityKey): Cache + { + return Cache::redis('app', options: new CacheOptions( + integrityKey: $integrityKey, + maxPayloadBytes: 8_388_608, + compressionThreshold: 4096, + allowClosures: false, + allowObjects: false, + failOpen: true, + )); + } + +Pass deploy-varying values from the application's composition root. CacheLayer +does not read process environment state. Options are isolated per instance and +cannot be changed after record processing begins. Runtime failure policy ---------------------- diff --git a/docs/security.rst b/docs/security.rst index de40690..cac1663 100644 --- a/docs/security.rst +++ b/docs/security.rst @@ -47,17 +47,18 @@ Per-instance construction API: use Infocyph\CacheLayer\Cache\Cache; use Infocyph\CacheLayer\Cache\CacheOptions; - $cache = Cache::redis('app', options: new CacheOptions( - integrityKey: 'replace-with-strong-secret', - maxPayloadBytes: 8_388_608, - allowClosures: false, - allowObjects: false, - )); - -``CacheOptions::fromEnvironment()`` explicitly reads: - -* ``CACHELAYER_PAYLOAD_INTEGRITY_KEY`` -* ``CACHELAYER_MAX_PAYLOAD_BYTES`` + function createCache(string $integrityKey): Cache + { + return Cache::redis('app', options: new CacheOptions( + integrityKey: $integrityKey, + maxPayloadBytes: 8_388_608, + allowClosures: false, + allowObjects: false, + )); + } + +Pass secret material from the application's composition root. CacheLayer does +not read process environment state. 2) ``phpFiles`` Adapter Guardrails ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -98,7 +99,8 @@ different timeout, TLS, retry, or socket-context settings. Recommended Production Profile ------------------------------ -1. Set ``CACHELAYER_PAYLOAD_INTEGRITY_KEY`` to a strong random secret. +1. Pass a strong random secret as ``CacheOptions::$integrityKey`` from the + application's composition root. 2. Disable closure/object payloads unless explicitly required. 3. Use explicit, private cache directories outside shared temp space. 4. Prefer non-executable file storage adapters over ``phpFiles`` where diff --git a/src/Cache/CacheOptions.php b/src/Cache/CacheOptions.php index 5e9282b..3f7b045 100644 --- a/src/Cache/CacheOptions.php +++ b/src/Cache/CacheOptions.php @@ -31,16 +31,4 @@ public function __construct( } } - public static function fromEnvironment(): self - { - $integrityKey = getenv('CACHELAYER_PAYLOAD_INTEGRITY_KEY'); - $maxPayloadBytes = getenv('CACHELAYER_MAX_PAYLOAD_BYTES'); - - return new self( - integrityKey: is_string($integrityKey) && $integrityKey !== '' ? $integrityKey : null, - maxPayloadBytes: is_string($maxPayloadBytes) && ctype_digit($maxPayloadBytes) - ? (int) $maxPayloadBytes - : 8_388_608, - ); - } } diff --git a/tests/Cache/ArchitectureHardeningTest.php b/tests/Cache/ArchitectureHardeningTest.php index 121094a..fd8737e 100644 --- a/tests/Cache/ArchitectureHardeningTest.php +++ b/tests/Cache/ArchitectureHardeningTest.php @@ -227,6 +227,10 @@ public function resetOperationCounts(): void ->and(Cache::memory('tenant-a.v1'))->toBeInstanceOf(Cache::class); }); +test('cache options do not load process environment state', function () { + expect(method_exists(CacheOptions::class, 'fromEnvironment'))->toBeFalse(); +}); + test('missing tag metadata cannot resurrect a tagged record', function () { $adapter = new \Infocyph\CacheLayer\Cache\Adapter\ArrayCacheAdapter('generation-loss'); $cache = new Cache($adapter);