Skip to content

[12.x] Add --readable flag to env:encrypt for visible key names#58262

Merged
taylorotwell merged 12 commits into
12.xfrom
readable-encrypted-envs
Jan 5, 2026
Merged

[12.x] Add --readable flag to env:encrypt for visible key names#58262
taylorotwell merged 12 commits into
12.xfrom
readable-encrypted-envs

Conversation

@mathiasgrimm

@mathiasgrimm mathiasgrimm commented Jan 3, 2026

Copy link
Copy Markdown
Member

This adds a new --readable flag to the env:encrypt command that produces a line-by-line encrypted format where variable names remain visible but values are encrypted. This allows developers to see what environment variables exist without exposing sensitive data, and makes pull requests easier to review since reviewers can see which variables were added, removed, or renamed without needing to decrypt the file.

Format example:

APP_NAME=eyJpdiI6...
DB_HOST=eyJpdiI6...

Features:

  • Variable names visible, values encrypted as base64 JSON
  • Comments skipped (removed)
  • Blank lines skipped (removed)
  • Multiline values supported
  • Auto-detection during decryption (backward compatible)
  • Existing blob format continues to work unchanged

Encrypter changes

  • Add static encrypted() method to Encrypter

Notes

For context, inspired by Ansible's Vault Multiple Passwords

This adds a new `--readable` flag to the `env:encrypt` command that produces
a line-by-line encrypted format where variable names remain visible but
values are encrypted. This allows developers to see what environment
variables exist without exposing sensitive data.

Format example:
APP_NAME=eyJpdiI6...
DB_HOST=eyJpdiI6...

#:eyJpdiI6... (encrypted comment)

Features:
- Variable names visible, values encrypted as base64 JSON
- Comments encrypted with `#:` prefix
- Blank lines preserved
- Multiline values supported
- Auto-detection during decryption (backward compatible)
- Existing blob format continues to work unchanged
@mathiasgrimm mathiasgrimm marked this pull request as draft January 3, 2026 22:37
mathiasgrimm and others added 7 commits January 3, 2026 19:56
This adds a new `--readable` flag to the `env:encrypt` command that produces
a line-by-line encrypted format where variable names remain visible but
values are encrypted. This allows developers to see what environment
variables exist without exposing sensitive data.

Format example:
APP_NAME=eyJpdiI6...
DB_HOST=eyJpdiI6...

#:eyJpdiI6... (encrypted comment)

Features:
- Variable names visible, values encrypted as base64 JSON
- Comments encrypted with `#:` prefix
- Blank lines preserved
- Multiline values supported
- Auto-detection during decryption (backward compatible)
- Existing blob format continues to work unchanged
This adds a new `--readable` flag to the `env:encrypt` command that produces
a line-by-line encrypted format where variable names remain visible but
values are encrypted. This allows developers to see what environment
variables exist without exposing sensitive data.

Format example:
APP_NAME=eyJpdiI6...
DB_HOST=eyJpdiI6...

Features:
- Variable names visible, values encrypted
- Comments are skipped
- Blank lines skipped
- Multiline values supported
- Auto-detection during decryption (backward compatible)
- Existing blob format continues to work unchanged
This adds a new `--readable` flag to the `env:encrypt` command that produces
a line-by-line encrypted format where variable names remain visible but
values are encrypted. This allows developers to see what environment
variables exist without exposing sensitive data.

Format example:
APP_NAME=eyJpdiI6...
DB_HOST=eyJpdiI6...

Features:
- Variable names visible, values encrypted
- Comments are skipped
- Blank lines skipped
- Multiline values supported
- Auto-detection during decryption (backward compatible)
- Existing blob format continues to work unchanged
This adds a new `--readable` flag to the `env:encrypt` command that produces
a line-by-line encrypted format where variable names remain visible but
values are encrypted. This allows developers to see what environment
variables exist without exposing sensitive data.

Format example:
APP_NAME=eyJpdiI6...
DB_HOST=eyJpdiI6...

Features:
- Variable names visible, values encrypted
- Comments are skipped
- Blank lines skipped
- Multiline values supported
- Auto-detection during decryption (backward compatible)
- Existing blob format continues to work unchanged
This adds a new `--readable` flag to the `env:encrypt` command that produces
a line-by-line encrypted format where variable names remain visible but
values are encrypted. This allows developers to see what environment
variables exist without exposing sensitive data.

Format example:
APP_NAME=eyJpdiI6...
DB_HOST=eyJpdiI6...

Features:
- Variable names visible, values encrypted
- Comments are skipped
- Blank lines skipped
- Multiline values supported
- Auto-detection during decryption (backward compatible)
- Existing blob format continues to work unchanged

## Encrypter changes
- Add static encrypted() method to Encrypter
@mathiasgrimm mathiasgrimm marked this pull request as ready for review January 4, 2026 01:25
$result = '';

foreach (Lines::process(preg_split('/\r\n|\r|\n/', $contents)) as $entry) {
$pos = strpos($entry, '=');

@GrahamCampbell GrahamCampbell Jan 4, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implementation is broken. It doesn't handle multi-line values, quoted values and escape characters properly and it also won't resolve references to other variables. Instead of using Lines, you should use Dotenv::parse($contents) which will give you a key-value map of the data, with sub-variable resolution applied.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, it was all working. Let me
Check it again

@mathiasgrimm mathiasgrimm Jan 4, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was originally using the parse but will check it. For encryption I can't use it because DotEnv::parse interprets the variables and things like MY_ENV_2="${MY_ENV}" would be replaced with the actual value of MY_ENV, but I guess for the decryption I should use it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just tested it here and it worked 100%

CleanShot.2026-01-05.at.13.50.07.mp4

(sorry for the bad audio. Was in a noisy place)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@GrahamCampbell I wasn't able to run into any errors and everything you mentioned worked. Can you please let me know how to reproduce what you say is broken?

I've just did some more tests with accents, single quotes, etc

CleanShot.2026-01-05.at.14.08.06.mp4

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what a dd(Lines::process(preg_split('/\r\n|\r|\n/', $contents)) looks like

php artisan env:encrypt --key=3UVsEgGVK36XN82KKeyLFMhvosbZN1aF --env=production --readable
array:59 [
  0 => "APP_NAME=Laravel"
  1 => "APP_ENV=local"
  2 => "APP_KEY=base64:Ge+W23u+VZI2tbrp5QCGWrsUuxgcD65i7jtTRR2ZqfY="
  3 => "APP_DEBUG=true"
  4 => "APP_TIMEZONE=UTC"
  5 => "APP_URL=http://framework-test.test"
  6 => "APP_LOCALE=en"
  7 => "APP_FALLBACK_LOCALE=en"
  8 => "APP_FAKER_LOCALE=en_US"
  9 => "APP_MAINTENANCE_DRIVER=file"
  10 => "PHP_CLI_SERVER_WORKERS=4"
  11 => "BCRYPT_ROUNDS=12"
  12 => "LOG_CHANNEL=stack"
  13 => "LOG_STACK=single"
  14 => "LOG_DEPRECATIONS_CHANNEL=null"
  15 => "LOG_LEVEL=debug"
  16 => "DB_CONNECTION=pgsql"
  17 => "DB_HOST=127.0.0.1"
  18 => "DB_PORT=5432"
  19 => "DB_DATABASE=framework_test_4"
  20 => "DB_USERNAME=root"
  21 => "DB_PASSWORD="
  22 => "SESSION_DRIVER=redis"
  23 => "SESSION_LIFETIME=120"
  24 => "SESSION_ENCRYPT=false"
  25 => "SESSION_PATH=/"
  26 => "SESSION_DOMAIN=null"
  27 => "BROADCAST_CONNECTION=log"
  28 => "FILESYSTEM_DISK=local`"
  29 => "QUEUE_CONNECTION=redis"
  30 => "CACHE_STORE=redis"
  31 => "CACHE_PREFIX="
  32 => "MEMCACHED_HOST=127.0.0.1"
  33 => "REDIS_CLIENT=phpredis"
  34 => "REDIS_HOST=127.0.0.1"
  35 => "REDIS_PASSWORD=null"
  36 => "REDIS_PORT=6379"
  37 => "MAIL_MAILER=smtp"
  38 => "MAIL_SCHEME=null"
  39 => "MAIL_HOST=127.0.0.1"
  40 => "MAIL_PORT=2525"
  41 => "MAIL_USERNAME="Framework Test""
  42 => "MAIL_PASSWORD=null"
  43 => "MAIL_FROM_ADDRESS="hello@example.com""
  44 => "MAIL_FROM_NAME="${APP_NAME}""
  45 => "AWS_ACCESS_KEY_ID="
  46 => "AWS_SECRET_ACCESS_KEY="
  47 => "AWS_DEFAULT_REGION=us-east-1"
  48 => "AWS_BUCKET="
  49 => "AWS_USE_PATH_STYLE_ENDPOINT=false"
  50 => "VITE_APP_NAME="${APP_NAME}""
  51 => """
    APP_TEST="asdasd\n
    sd\n
    asd\n
    asd\n
    asd\n
    "
    """
  52 => """
    APP_TEST_2="asdasdasd\n
    asd\n
    asd\n
    as\n
    dasd\n
    "
    """
  53 => "APP_TEST_3="${APP_TEST_2}""
  54 => "NAME_1="JOSÉ""
  55 => "NAME_2=O'Connel"
  56 => "NAME_3="John O'Connel""
  57 => "abcdef"
  58 => "MY_ENV"
] // /Users/mathiasgrimm/laravel.com/github/framework/src/Illuminate/Foundation/Console/EnvironmentEncryptCommand.php:157

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CleanShot 2026-01-05 at 14 19 38@2x

@taylorotwell taylorotwell merged commit e624c2b into 12.x Jan 5, 2026
71 checks passed
@taylorotwell taylorotwell deleted the readable-encrypted-envs branch January 5, 2026 21:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants