The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

ENV::Util - parse prefixed environment variables and dotenv (.env) files into Perl

SYNOPSIS

Efficiently load an '.env' file into %ENV:

    use ENV::Util -load_dotenv;

Turn all %ENV keys that match a prefix into a lowercased config hash:

    use ENV::Util;

    my %cfg = ENV::Util::prefix2hash('MYAPP_');
    # MYAPP_SOME_OPTION becomes $cfg{ some_option }

Safe dump of %ENV without tokens or passwords:

    use ENV::Util;
    my %masked_env = ENV::Util::redacted_env();
    say $masked_env{token_secret}; # '<redacted>'

DESCRIPTION

This module provides a set of utilities to let you easily handle environment variables from within your Perl program.

It is lightweight, should work on any Perl 5 version and has no dependencies.

FUNCTIONS

prefix2hash( 'PREFIX' )

    my %config = ENV::Util::prefix2hash( 'MYAPP_' );

This function returns all data from environment variables that begin with the given prefix. You can use that to allow users to control your program directly from their environment without risking name clashing of env vars.

So for example if your app is called "MYAPP", you can allow them to setup MYAPP_TOKEN, MYAPP_USERNAME, MYAPP_ROLES, MYAPP_TOKEN, etc. as environment variables. By calling prefix2hash() with the proper prefix (in this case, 'MYAPP_'), you get a hash of all the specified keys and values, with the prefix properly stripped and all keys in lowercase, as is common practice in Perl code.

load_dotenv()

load_dotenv( $filename )

This functions load the contents of any dotenv file (defaults to '.env') into %ENV. It does *NOT* override keys/values already in the environment (%ENV). To use a filename other than ".env", simply pass it as an argument.

    ENV::Util::load_dotenv();                # loads ".env"
    ENV::Util::load_dotenv('somefile.env');  # loads "somefile.env"

    # to load multiple files in a given order:
    ENV::Util::load_dotenv($_) for qw( file1.env file2.env file3.env );

NOTE: because loading a .env file is so common for apps running in containers, we added a shortcut that loads it directly at compile time:

    use ENV::Util -load_dotenv;

The .env file format

Despite being almost ubiquitous in containerized environments, there is no standard format for "dotenv", and each implementation does its own thing.

This is ours:

    # comments can be standalone or inline.
    # blank lines are also accepted.

    # variable names must follow the pattern [A-Za-z_][a-zA-Z0-9_]+
    # but usually are just A..Z in all caps.
    FOO  =  some value   # spaces are trimmed except inside the string.
    FOO='some value'     # so both lines here are the same.

    NEWLINE=\n           # unquoted values are treated WITH interpolation.
    NEWLINE="\n"         # so this line and the one above are the same.
    LITERAL='\n'         # but this is a literal '\' and a literal 'n'.

    BAR=baz          # bash/zsh format.
    export BAR=baz   # bash format.
    set BAR=baz      # tcsh/csh format.
    setenv BAR baz   # tcsh/csh format (note this one lacks '=').

    # empty values are set to the empty string ''
    NONE =
    ALSONONE

    # you can prepend '$' to variable names to interpolate them
    # in unquoted or double quoted values. You can point to variables
    # declared before in the file or available in your %ENV
    # *AS LONG AS* you don't try to replace variables from %ENV,
    # which is not allowed by design.
    MYKEY=$OTHERKEY
    MYKEY=$MYKEY and something else  # ok to use the same variable.

redacted_env()

redacted_env( %options )

    $ENV{ HARMLESS_VAR } = 1234;
    $ENV{ APP_SECRET } = 4321;

    my %masked = ENV::Util::redacted_env();
    say $masked{ HARMLESS_VAR };  # 1234;
    say $masked{ APP_SECRET };    # <redacted>;

Returns a masked (redacted) version of %ENV, (hopefully) without sensitive information. This can be useful if you are dumping your environment variables to a log/debug facility without compromising information security/privacy.

WARNING: This function is heuristic and redacts based on suspicious token/value data. There is NO WARRANTY that your sensitive data will be redacted. You are advised to test and tweak options according to your environment and data, and use it at your own discretion and risk.

Any keys matching the following will be redacted/masked: USER, ID, NAME, MAIL, ACC, TOKEN, PASS, PW, SECRET, KEY, ACCESS, PIN, SSN, CARD, IP.

Regardless of keys, any values that contain '@', ':' or '=' will also be redacted.

Creating your own mask/redaction rules:

To override the following rules with your own, simply pass to the function a hash with a rules key, holding an array reference of hash references containing each rule. The format is as follows:

    my %masked_env = ENV::Util::redacted_env(
        rules => [
            { key => qr(...), mask => '<redacted>' },
            { key => qr( another key ), drop => 1 },
        ],
    );

As you can see above, each rule is a hash reference that may contain the following fields:

  • key is a regexp to be tested against %ENV keys.

  • value is a regexp to be tested against %ENV values.

  • mask is what to replace the value with. Default to undef.

  • drop if set to true, removes the matching key entirely.

SEE ALSO

Dotenv, Env::Dot, Config::ENV, Config::Layered::Source::ENV.

LICENSE AND COPYRIGHT

Copyright (C) 2023 Breno G. de Oliveira

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.

DISCLAIMER OF WARRANTY

BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION.

IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.