Supporting adding additional gpg keys. (#48)

* Supporting adding additional gpg keys.

Besides, add_apt_key now takes "image_tar" instead of "image".
diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml
index 5c5e74d..0d9d73d 100644
--- a/.bazelci/presubmit.yml
+++ b/.bazelci/presubmit.yml
@@ -18,6 +18,7 @@
     - "//container/rbe-debian8:toolchain-test"
     - "//container/experimental/rbe-debian9:toolchain-test"
     - "//container/experimental/rbe-ubuntu16_04:toolchain-test"
+    - "//container/test:bazel-toolchain-test"
   ubuntu1604:
     test_targets:
     - "//test/configs:debian-jessie-autoconfig_test"
@@ -36,3 +37,4 @@
     - "//container/rbe-debian8:toolchain-test"
     - "//container/experimental/rbe-debian9:toolchain-test"
     - "//container/experimental/rbe-ubuntu16_04:toolchain-test"
+    - "//container/test:bazel-toolchain-test"
diff --git a/WORKSPACE b/WORKSPACE
index 243b245..4c15ab3 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -23,9 +23,9 @@
 # https://docs.bazel.build/versions/master/be/workspace.html#git_repository
 http_archive(
     name = "io_bazel_rules_docker",
-    sha256 = "3af41275396fba9fcbb88741d946ac37e51c48888cbdaba2a58a2e75a492da91",
-    strip_prefix = "rules_docker-4d8ec6570a5313fb0128e2354f2bc4323685282a",
-    urls = ["https://github.com/bazelbuild/rules_docker/archive/4d8ec6570a5313fb0128e2354f2bc4323685282a.tar.gz"],
+    sha256 = "0c2a63f09e7e85e08d83a32af41fc93a3b4796c80fc3fe4626df82a63b92bcff",
+    strip_prefix = "rules_docker-1144f83122750fe4aca139bd0f205d99c9bd94c1",
+    urls = ["https://github.com/bazelbuild/rules_docker/archive/1144f83122750fe4aca139bd0f205d99c9bd94c1.tar.gz"],
 )
 
 load(
@@ -100,9 +100,9 @@
 
 http_archive(
     name = "base_images_docker",
-    sha256 = "8297bd2afd5dc14c062d0fca062fe0c9fa9fe5e755c98ed94aa94aa681bb8f79",
-    strip_prefix = "base-images-docker-6472e597b35456d27de76799e29cd3e5d40ade8a",
-    urls = ["https://github.com/GoogleCloudPlatform/base-images-docker/archive/6472e597b35456d27de76799e29cd3e5d40ade8a.tar.gz"],
+    sha256 = "44c5d801ea553938b06cd7f82c605d46c79da79a0f1c2ee1a24bed7c49934906",
+    strip_prefix = "base-images-docker-521a8d65328303c45b72818dc97d24fd7a73b400",
+    urls = ["https://github.com/GoogleCloudPlatform/base-images-docker/archive/521a8d65328303c45b72818dc97d24fd7a73b400.tar.gz"],
 )
 
 http_file(
diff --git a/container/rules/docker_toolchains.bzl b/container/rules/docker_toolchains.bzl
index 915a603..8cd4e5c 100644
--- a/container/rules/docker_toolchains.bzl
+++ b/container/rules/docker_toolchains.bzl
@@ -17,6 +17,7 @@
 load("@io_bazel_rules_docker//container:container.bzl", _container = "container")
 load("@base_images_docker//package_managers:download_pkgs.bzl", _download = "download")
 load("@base_images_docker//package_managers:install_pkgs.bzl", _install = "install")
+load("@base_images_docker//package_managers:apt_key.bzl", _key = "key")
 
 def _input_validation(kwargs):
   if "debs" in kwargs:
@@ -28,6 +29,8 @@
   has_no_packages = "packages" not in kwargs or kwargs["packages"] == []
   if has_no_packages and "additional_repos" in kwargs:
     fail("'additional_repos' can only be specified when 'packages' is not empty.")
+  if has_no_packages and "keys" in kwargs:
+    fail("'keys' can only be specified when 'packages' is not empty.")
 
   has_no_tar = "installables_tar" not in kwargs or kwargs["installables_tar"] == ""
   if has_no_packages and has_no_tar and "installation_cleanup_commands" in kwargs:
@@ -36,7 +39,8 @@
 
 def _language_tool_layer_impl(ctx, symlinks=None, env=None, tars=None,
                               files=None, packages=None, additional_repos=None,
-                              installables_tars=None, installation_cleanup_commands=""):
+                              keys=None, installables_tars=None,
+                              installation_cleanup_commands=""):
   """Implementation for the language_tool_layer rule.
 
   Args:
@@ -53,6 +57,7 @@
     files: File list, overrides ctx.files.files
     packages: str List, overrides ctx.attr.packages
     additional_repos: str List, overrides ctx.attr.additional_repos
+    keys: File list, overrides ctx.files.keys
     installables_tars: File list, overrides [ctx.file.installables_tar]
     installation_cleanup_commands: str, overrides ctx.attr.installation_cleanup_commands
 
@@ -65,6 +70,7 @@
   files = files or ctx.files.files
   packages = packages or ctx.attr.packages
   additional_repos = additional_repos or ctx.attr.additional_repos
+  keys = keys or ctx.files.keys
   installables_tars = installables_tars or []
   installation_cleanup_commands = installation_cleanup_commands or ctx.attr.installation_cleanup_commands
 
@@ -74,6 +80,29 @@
   # Otherwise, download packages if packages list is not empty, and add the tar of downloaded
   # debs to installables_tars.
   elif packages != []:
+
+    # Prepare base image for the download_pkgs rule.
+    download_base = ctx.files.base[0]
+
+    # Create an intermediate image with additional gpg keys used to download packages.
+    if keys != []:
+      image_with_keys = "%s_with_keys" % ctx.attr.name
+      # Declare intermediate output file generated by add_apt_key rule.
+      image_with_keys_output_executable = ctx.actions.declare_file(image_with_keys)
+      image_with_keys_output_tarball = ctx.actions.declare_file(image_with_keys + ".tar")
+      image_with_keys_output_layer = ctx.actions.declare_file(image_with_keys + "-layer.tar")
+
+      _key.implementation(
+        ctx,
+        name = image_with_keys,
+        image_tar=ctx.files.base[0],
+        keys=keys,
+        output_executable=image_with_keys_output_executable,
+        output_tarball=image_with_keys_output_tarball,
+        output_layer=image_with_keys_output_layer
+      )
+      download_base = image_with_keys_output_tarball
+
     # Declare intermediate output file generated by download_pkgs rule.
     download_pkgs_output_executable = ctx.actions.declare_file(ctx.attr.name + "-download_pkgs_output_executable.sh")
     download_pkgs_output_tar = ctx.actions.declare_file(ctx.attr.name + "-download_pkgs_output_tar.tar")
@@ -82,7 +111,7 @@
     # download_pkgs rule consumes 'packages' and 'additional_repos'.
     _download.implementation(
       ctx,
-      image_tar=ctx.files.base[0],
+      image_tar=download_base,
       packages=packages,
       additional_repos=additional_repos,
       output_executable=download_pkgs_output_executable,
@@ -142,17 +171,21 @@
                 symlinks = symlinks,
                 packages = packages,
                 additional_repos = additional_repos,
+                keys = keys,
                 installables_tar = ctx.file.installables_tar,
                 installation_cleanup_commands = installation_cleanup_commands
                 )
 
-language_tool_layer_attrs = _container.image.attrs + _install.attrs + _download.attrs + {
+language_tool_layer_attrs = _container.image.attrs + _key.attrs + _download.attrs + _install.attrs + {
     # Redeclare following attributes as non-mandatory.
     "image_tar": attr.label(
         allow_files = True,
         single_file = True,
     ),
     "packages": attr.string_list(),
+    "keys": attr.label_list(
+        allow_files = True,
+    ),
     "installables_tar": attr.label(
         allow_files = True,
         single_file = True,
@@ -183,6 +216,8 @@
       packages: list of packages to fetch and install in the base image.
       additional_repos: list of additional debian package repos to use,
         in sources.list format.
+      keys: list of labels of additional gpg keys to use while downloading
+        packages.
       installables_tar: a tar of debian packages to install in the base image.
       installation_cleanup_commands: cleanup commands to run after package
         installation.
@@ -216,6 +251,7 @@
   symlinks = {}
   packages = []
   additional_repos = []
+  keys = []
   installables_tars = []
   installation_cleanup_commands = "cd ."
 
@@ -228,21 +264,24 @@
     symlinks.update(layer.symlinks)
     packages.extend(layer.packages)
     additional_repos.extend(layer.additional_repos)
+    keys.extend(layer.keys)
     if layer.installables_tar:
       installables_tars.append(layer.installables_tar)
     if layer.installation_cleanup_commands:
       installation_cleanup_commands += (" && " + layer.installation_cleanup_commands)
-  tars.extend(ctx.attr.tars)
+  tars.extend(ctx.files.tars)
   env.update(ctx.attr.env)
   symlinks.update(ctx.attr.symlinks)
   packages.extend(ctx.attr.packages)
   additional_repos.extend(ctx.attr.additional_repos)
+  keys.extend(ctx.files.keys)
   if ctx.attr.installation_cleanup_commands:
     installation_cleanup_commands += (" && " + ctx.attr.installation_cleanup_commands)
 
   files = depset(files).to_list()
   packages = depset(packages).to_list()
   additional_repos = depset(additional_repos).to_list()
+  keys = depset(keys).to_list()
   installables_tars = depset(installables_tars).to_list()
 
   return _language_tool_layer_impl(ctx,
@@ -252,6 +291,7 @@
                                    files=files,
                                    packages=packages,
                                    additional_repos=additional_repos,
+                                   keys=keys,
                                    installables_tars=installables_tars,
                                    installation_cleanup_commands=installation_cleanup_commands
                                    )
@@ -279,6 +319,8 @@
       packages: list of packages to fetch and install in the base image.
       additional_repos: list of additional debian package repos to use,
         in sources.list format.
+      keys: list of labels of additional gpg keys to use while downloading
+        packages.
       installation_cleanup_commands: cleanup commands to run after package
         installation.
 
diff --git a/container/test/BUILD b/container/test/BUILD
index 263db40..0c9d377 100644
--- a/container/test/BUILD
+++ b/container/test/BUILD
@@ -17,3 +17,31 @@
 package(default_visibility = ["//visibility:public"])
 
 exports_files(glob(["**"]))
+
+load("//container/rules:docker_toolchains.bzl", "toolchain_container")
+load("@io_bazel_rules_docker//contrib:test.bzl", "container_test")
+
+toolchain_container(
+    name = "bazel-toolchain",
+    base = "@debian8//image",
+    packages = [
+        "bazel",
+    ],
+    additional_repos = [
+      "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8",
+    ],
+    keys = [
+      "@bazel_gpg//file",
+    ],
+    language_layers = [
+        "//container/rbe-debian8:java-ltl",
+    ],
+)
+
+container_test(
+    name = "bazel-toolchain-test",
+    configs = [
+        "//container/test:bazel.yaml",
+    ],
+    image = ":bazel-toolchain",
+)
diff --git a/container/test/bazel.yaml b/container/test/bazel.yaml
new file mode 100644
index 0000000..0948dee
--- /dev/null
+++ b/container/test/bazel.yaml
@@ -0,0 +1,34 @@
+schemaVersion: "1.0.0"
+
+# TODO: split out the common tests once resolve the CI issues
+
+# Distro-specific tests
+commandTests:
+- name: 'os-version'
+  command: ['sh', '-c', 'cat /etc/issue.net']
+  expectedOutput: ['Debian GNU/Linux 8']
+
+# Common tests
+commandTests:
+- name: 'path-envvar'
+  command: ['sh', '-c', 'echo $PATH']
+  expectedOutput: ['/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin']
+- name: 'javahome-envvar'
+  command: ['sh', '-c', 'echo $JAVA_HOME']
+  expectedOutput: ['/usr/lib/jvm/java-8-openjdk-amd64']
+- name: 'java-version'
+  command: ['bash', '-c', 'java -version 2>&1']
+  expectedOutput: ['openjdk version \"1.8.*']
+- name: 'check-openssl'
+  command: ['bash', '-c', 'openssl version']
+  expectedOutput: ['OpenSSL .*']
+- name: 'bazel'
+  command: ['bazel']
+  expectedOutput: ['Usage: bazel <command> <options>.*']
+
+# File existence tests
+fileExistenceTests:
+- name: 'OpenJDK'
+  isDirectory: true
+  path: '/usr/lib/jvm/java-8-openjdk-amd64'
+  shouldExist: true
diff --git a/rules/docker_config.bzl b/rules/docker_config.bzl
index 6dd0090..445b85a 100644
--- a/rules/docker_config.bzl
+++ b/rules/docker_config.bzl
@@ -171,7 +171,7 @@
   # Create an intermediate image which includes additional gpg keys.
   add_apt_key(
       name = name + "_with_keys",
-      image = base,
+      image_tar = base,
       keys = keys,
   )