Punk

 view release on metacpan or  search on metacpan

t/1200-config.t  view on Meta::CPAN

        'the public config redacts a secret');
    is($cfg->config->{database}{other},    '[redacted]', 'every secret');
    is($cfg->config->{database}{dsn}, 'dbi:SQLite:dbname=test.db',
        'ordinary values are untouched');

    # ... and nothing anywhere in it looks like the real thing
    my $dump = do {
        require File::Raw::JSON;
        File::Raw::JSON::file_json_encode($cfg->config);
    };
    unlike($dump, qr/from-the-environment|from-a-file|from-a-command/,
        'a full dump of the public config leaks no secret');

    is_deeply($cfg->secret_paths,
        [ sort qw(database.computed database.other database.password
                  database.plain) ],
        'the resolved secrets are listed');
    ok($cfg->has_secret('database.password'), 'has_secret');
    ok(!$cfg->has_secret('database.dsn'), 'and only for real secrets');

    # get() reaches the resolved value, for the boot consumers
    is($cfg->get('database.password'), 'from-the-environment',
        'get returns the resolved value');
}

# ---- resolver failures are loud ---------------------------------------------
{
    write_file('punk.yml', "token: { \$env: PUNK_DEFINITELY_NOT_SET }\n");
    my $err = '';
    eval { Punk::Config->load(file => "$dir/punk.yml", env => 'none') }
        or $err = $@;
    like($err, qr/PUNK_DEFINITELY_NOT_SET.*not set/,
        'a missing environment variable is fatal, not an empty password');

    write_file('punk.yml', "token: { \$file: /no/such/secret }\n");
    $err = '';
    eval { Punk::Config->load(file => "$dir/punk.yml", env => 'none') }
        or $err = $@;
    like($err, qr/cannot read/, 'an unreadable secret file is fatal');

    write_file('punk.yml', "token: { \$nope: x }\n");
    $err = '';
    eval { Punk::Config->load(file => "$dir/punk.yml", env => 'none') }
        or $err = $@;
    like($err, qr/unknown resolver/, 'an unknown resolver croaks, listing them');
}

# ---- a plaintext value is nobody else's business -----------------------------
#
# There used to be a guardrail here: a plaintext value under a key whose NAME
# looked secret-shaped warned, and `secrets => 'strict'` refused to boot. It
# is gone. Whether a password sits in the file is the decision of whoever
# writes the file, and a warning that fires on a key's name rather than on
# anything it knows is a warning people learn to ignore.
#
# These assert the silence, so reintroducing it fails here rather than in
# somebody's boot log.
{
    unlink "$dir/punk.local.yml" if -e "$dir/punk.local.yml";

    for my $key (qw(password passwd secret token api_key private_key
                    credentials auth)) {
        write_file('punk.yml', "thing:\n  $key: something\n");
        my @warned;
        {
            local $SIG{__WARN__} = sub { push @warned, $_[0] };
            Punk::Config->load(file => "$dir/punk.yml", env => 'none');
        }
        is(scalar @warned, 0, "a plaintext '$key' is loaded without comment");
    }

    write_file('punk.yml', "db:\n  dsn: dbi:Pg:dbname=x;password=oops\n");
    my @warned;
    {
        local $SIG{__WARN__} = sub { push @warned, $_[0] };
        my $c = Punk::Config->load(file => "$dir/punk.yml", env => 'none');
        is($c->get('db.dsn'), 'dbi:Pg:dbname=x;password=oops',
            'and a dsn with the password in it is just a dsn');
    }
    is(scalar @warned, 0, 'no warning for that either');

    # The resolvers are untouched: this is about not second-guessing a
    # plaintext value, not about taking the alternative away.
    local $ENV{PUNK_T_SECRET} = 'from-the-environment';
    write_file('punk.yml', "database:\n  password: { \$env: PUNK_T_SECRET }\n");
    my $cfg = Punk::Config->load(file => "$dir/punk.yml", env => 'none');
    is($cfg->secret('database.password'), 'from-the-environment',
        '$env still resolves');
    is($cfg->config->{database}{password}, '[redacted]',
        'and a resolved secret is still redacted out of the public copy');
}

# ---- config drives the DSL ---------------------------------------------------
{
    mkdir "$dir/templates";
    open my $t, '>', "$dir/templates/hello.tmpl" or die $!;
    print $t '<p>{% msg %}</p>';
    close $t;

    local $ENV{PUNK_TEST_DB_PASSWORD} = 'from-the-env';
    write_file('punk.yml', <<"YAML");
app:
  name: base
views:
  Stencil:
    template_dir: $dir/templates
database:
  dsn: dbi:SQLite:dbname=$dir/app.db
  password: { \$env: PUNK_TEST_DB_PASSWORD }
plugins:
  ConfigTestMark: {}
YAML
    write_file('punk.staging.yml', "app:\n  name: staging\n");
    unlink "$dir/punk.local.yml" if -e "$dir/punk.local.yml";

    package Punk::Plugin::ConfigTestMark;
    our @ISA = ('Punk::Plugin');
    sub register {
        my ($self, $app) = @_;
        $app->helper(config_marked => sub { 'plugin from config' });
    }



( run in 0.717 second using v1.01-cache-2.11-cpan-036bef1c656 )