padosoft/laravel-settings
Laravel Settings gives your application a simple, persistent key-value store for configuration. Define settings in the database, read and update them through a clean API, and rely on caching so values load fast without extra queries. Settings stay editable at runtime, keeping configuration out of co...
Architecture fit
padosoft/laravel-settings is a key/value settings store with a per-key encrypted_keys allowlist. Release 7.0.0 is a ground-up rewrite of that encryption path, and it changes the package's architectural posture in three ways a TPM should note:
SettingsManager::set()), with created/updated hooks re-encrypting an already-decrypted accessor value. That produced divergent on-disk shapes (one layer vs. two), wrong reads on cold cache, and plaintext written into Redis. 7.0.0 consolidates into one component (Encryption\SettingsCipher) used by both the Model and the Manager. This is a genuine correctness fix, not a cosmetic refactor.pdsenc:v1:<kid>:<payload> with cryptographic binding to the setting key and to a deployment context. The version prefix and key id make rotation and future format evolution tractable; the key/context binding means a ciphertext copied from another row or another environment will not decrypt — useful against copy-paste and cross-environment restore mistakes.APP_KEY. A dedicated keyring with previous keys supports two-phase rotation without re-encrypting everything at once. This is the right shape for a production secret lifecycle, but it introduces a new secret to provision, distribute, and rotate.The net architectural effect: the package moves from "convenience store with an optional encryption feature that didn't work" to "settings store with a managed secret lifecycle." That is a materially larger operational footprint than the version number alone suggests.
Integration feasibility
Feasible for most Laravel applications, with a defined sequence:
encrypted_keys is functionally unaffected apart from the schema widening and the toArray()/toJson() redaction.encryption-migrate command is the intended remediation; treat it as mandatory, not optional, and rehearse it on a production-shaped copy.settings.value → TEXT) is the main infrastructure dependency. Envelopes do not fit in VARCHAR(255), so the migration is unavoidable.Technical risk
| Risk | Severity | Notes |
|---|---|---|
VARCHAR(255) → TEXT migration on a large settings table |
Medium–High | Depends on MySQL version/row format; may be a table copy rather than in-place. Also: a TEXT column cannot be indexed without a prefix length — if any existing index or unique constraint covers value, the migration either fails or silently changes semantics. Verify before scheduling. |
| Stale cache after cutover | High | 6.x wrote plaintext to Redis on cold-cache paths. Old cache entries can outlive the deploy. Cache flush/versioning must be part of the runbook, not an afterthought. |
| Fail-closed on plaintext-in-storage | High (availability) | Any allowlisted key found in plaintext raises. On a 6.x database this is a predictable state, so an un-audited deploy can take down reads of settings. encryption-audit must gate the rollout. |
| Deployment-context binding | Medium | If context is derived from environment/host/app URL, staging and production sharing a database (or a DR region with a different context value) will fail to decrypt. Needs explicit confirmation of how context is configured and how it behaves during regional failover. |
| Keyring provisioning and distribution | Medium | New secret with no dependency on APP_KEY. Where it lives (env, Vault, KMS, sealed secret) and how it reaches every node — including queue workers, scheduler, and Octane/long-lived processes that may cache it in memory — must be decided up front. |
| Config caching | Medium | If the keyring is read from config, config:cache bakes it into bootstrap/cache. Rotation then requires a config rebuild plus a rolling restart, and ordering against the two-phase previous key window matters. |
Behavior removal (echo in accessors) |
Low | Anyone who relied on accessor output for debugging loses it. Intentional and correct. |
Redacted logs/toArray() |
Low | Good for compliance; means the on-call story now depends entirely on the audit commands and exception types. |
Key questions
TEXT migration preserve or drop any existing index on settings.value, and what is the expected lock profile on MySQL 5.7 vs. 8.0 and on PostgreSQL?encryption-migrate safe to run while 7.0.0 application nodes are serving traffic (dual-read tolerance), or does it require a maintenance window?kid in the envelope is not present in the keyring — hard exception, or fallback? Is there a read-only degraded mode?encryption-migrate has run? Is the new format readable by 6.x at all?config:cache?Stack fit
Standard Laravel: Eloquent model, service provider, config file, artisan commands, migrations. No new runtime dependencies are implied by the release notes — the envelope uses encryptString(), so no unserialize() on stored data, which is a modest hardening win. Fits Laravel 10/11-era conventions; PHP 8.2 is the tested baseline.
Migration path
Treat this as a three-phase cutover rather than a single deploy:
value column and the keyring secret to every environment. Run encryption-audit in dry-run against production to enumerate allowlisted keys that are currently plaintext, single-layer, or double-layer. This produces the migration scope and the blast radius.encryption-migrate (dry-run first, then apply) in a controlled window. Invalidate or version the settings cache as part of the same step — the plan must not assume old Redis entries are self-invalidating. Re-run the audit to confirm zero plaintext remains in allowlisted keys.previous key slot is for later rotation, not for this cutover.Compatibility
Exceptions\DecryptException, so existing catch blocks continue to work. This is the single most important compatibility guarantee in the release and materially lowers risk for teams that already handle decryption failures.encrypted_keys list get the schema change and the redaction behavior change, and nothing else.encrypted_keys on 6.x should assume their stored data is in an indeterminate state (the release notes say as much) and plan accordingly.Sequencing and ownership
Order of operations is constraint-driven: schema → cache handling → audit → migrate → deploy → verify. The TPM-owned decision is the freeze window: cache invalidation and keyring rollout must not straddle a settings-heavy deployment, and config:cache rebuilds must be coordinated with the rolling restart if the keyring is config-sourced. Assign a single owner for the keyring secret provisioning across all environments (including CI, queue workers, and the scheduler) before the migration is scheduled.
Maintenance
Steady-state maintenance is modest but non-zero, and it is new maintenance that did not exist before because the feature was unusable. Specifically: a keyring to store and rotate, a two-phase rotation procedure to rehearse, and a periodic audit to confirm no plaintext has crept back into allowlisted keys. The three commands support this — dry-run by default, idempotent, and deliberately silent on values and lengths, which is the correct posture for a compliance-sensitive surface and should be preserved in any wrapper scripts.
Support and observability
Redaction of toArray(), toJson(), and logs is the right default, but it removes the previous (accidental) debugging channels. Support runbooks should be rewritten to lead with encryption-audit output and the exception hierarchy rather than log inspection. On-call needs to be able to distinguish, from an exception alone, between a missing kid, a context mismatch, and a plaintext-in-storage fail-closed trip — these have very different remediations. The release notes don't state whether these are separate exception types; confirm before writing the runbook.
Scaling
No meaningful per-request cost increase; envelope decryption replaces the previous path. Watch two things: the TEXT column change affects row size and any value-based index (see risk table), and the keyring must be available to every worker class — web, queue, scheduler, and any long-lived Octane process — since a missing keyring in a worker manifests as a background job failure rather than a user-visible error, which is the harder failure to notice.
Failure modes
encryption-audit a hard gate on the deploy.Ramp-up
Low for application developers — the API is unchanged, and the redaction is transparent. Moderate for platform/SRE — keyring provisioning, cache invalidation, migration window, and rotation drill. The realistic estimate is one focused day of platform work to provision the keyring across environments and rehearse encryption-migrate on a production copy, plus a short rotation exercise to validate the previous-key path before relying on it. Budget the audit-and-migrate gate as a distinct milestone; it is where the risk actually concentrates, and it is the item most likely to be under-scoped.
How can I help you explore Laravel packages today?