API-Docker

 view release on metacpan or  search on metacpan

t/tls.t  view on Meta::CPAN

# cleartext whatever tls said, and tls => 1 croaked at construction rather
# than pretending otherwise. TLS is wired now -- IO::Socket::SSL in the
# tcp:// branch of the socket builder, certificates from the directory
# cert_path always pointed at -- so every one of those claims is replaced by
# its inverse here.
#
# The handshake subtests at the bottom fork a TLS server on 127.0.0.1 and
# generate their own certificates; nothing here reaches a Docker daemon or
# the network, and no certificate is read from anywhere but a temporary
# directory this file created.

my $HAVE_SSL = eval { require IO::Socket::SSL; 1 };

sub client {
  return API::Docker->new(
    host        => 'tcp://dockerhost:2376',
    api_version => '1.41',
    @_,
  );
}

# ===========================================================================
# Construction
# ===========================================================================

subtest 'tls => 1 constructs, and cert_path is what it acts on' => sub {
  # The claim this replaces: "tls => 1 croaks at construction ... TLS is
  # still not implemented", and "cert_path does not rescue tls => 1".
  my $docker = eval { client(tls => 1) };
  is $@, '', 'no croak';
  ok $docker, 'a client comes back';
  is $docker->tls, 1, 'and it knows it is a TLS client';

  my $dir = Path::Tiny->tempdir;
  $dir->child('ca.pem')->spew('');
  my $with_certs = eval { client(tls => 1, cert_path => "$dir") };
  is $@, '', 'tls => 1 with a cert_path constructs too';
  is $with_certs->cert_path, "$dir", 'and keeps the path, to act on it';
};

subtest 'every falsy form of tls is still accepted' => sub {
  for my $off (0, undef, '') {
    my $docker = eval { client(tls => $off) };
    is $@, '', 'tls => ' . (defined $off ? "'$off'" : 'undef') . ' constructs';
    ok $docker, 'and returns a client';
  }

  # Pinned against the developer's own shell: the default now reads
  # DOCKER_TLS_VERIFY (karr k42), and the claim being made here is the one
  # that has always been made -- with nothing set, a tcp:// host is plaintext.
  delete local $ENV{DOCKER_TLS_VERIFY};
  is client()->tls, 0, 'the default is still 0: a tcp:// host is plaintext '
    . 'unless TLS is asked for';
};

# ===========================================================================
# DOCKER_TLS_VERIFY (karr k42)
# ===========================================================================

subtest 'the default is DOCKER_TLS_VERIFY, on the docker CLI rule' => sub {
  # Measured against docker/cli rather than guessed. cli/flags/options.go:
  #
  #     dockerTLSVerify = os.Getenv(client.EnvTLSVerify) != ""
  #
  # so the test is "non-empty", not "true", and non-empty means TLS on *and*
  # verification on (InsecureSkipVerify = !o.TLSVerify). The one place Perl
  # truthiness and that rule disagree is the string '0' -- which is exactly
  # what a user types for "off".
  {
    local $ENV{DOCKER_TLS_VERIFY} = '1';
    is client()->tls, 1, "'1' turns TLS on";
  }
  {
    local $ENV{DOCKER_TLS_VERIFY} = '0';
    is client()->tls, 1, "'0' turns TLS ON as well: the CLI reads != \"\", not "
      . 'truthiness, and this is the case a naive port gets backwards';
  }
  for my $value (qw( false no off true yes 2 )) {
    local $ENV{DOCKER_TLS_VERIFY} = $value;
    is client()->tls, 1, "'$value' is non-empty, so it is on too";
  }
  {
    local $ENV{DOCKER_TLS_VERIFY} = '';
    is client()->tls, 0, 'the empty string is the only set value that is off';
  }
  {
    delete local $ENV{DOCKER_TLS_VERIFY};
    is client()->tls, 0, 'and unset is off, which is the old default unchanged';
  }

  {
    local $ENV{DOCKER_TLS_VERIFY} = '1';
    is client(tls => 0)->tls, 0, 'an explicit tls => 0 outranks the variable';
    delete local $ENV{DOCKER_TLS_VERIFY};
    is client(tls => 1)->tls, 1, 'and an explicit tls => 1 needs no variable';
  }
};

subtest 'DOCKER_TLS_VERIFY is ignored on a socket host' => sub {
  # The CLI ignores it there too -- cli/context/docker/load.go, "there's no
  # need to configure TLS for a socket connection", true for unix, npipe and
  # fd. Here it MUST be ignored rather than merely being tidy: BUILD croaks on
  # tls => 1 with a non-tcp:// host, so a host-blind default would make a bare
  # API::Docker->new die on every machine that talks to a local socket and
  # happens to export the variable -- this repo's own default host included.
  local $ENV{DOCKER_TLS_VERIFY} = '1';

  for my $host (
    'unix:///var/run/docker.sock',
    'unix:///run/user/1000/podman/podman.sock',
  ) {
    my $docker = eval { API::Docker->new(host => $host, api_version => '1.41') };
    is $@, '', $host . ' still constructs';
    is $docker->tls, 0, 'and TLS stayed off, so BUILD had nothing to croak about';
  }

  my ($bare, $err) = do {
    local $ENV{DOCKER_HOST} = 'unix:///var/run/docker.sock';
    local $@;
    my $client = eval { API::Docker->new };
    ($client, $@);



( run in 0.653 second using v1.01-cache-2.11-cpan-54e63673c56 )