> ## Documentation Index
> Fetch the complete documentation index at: https://site.aspect.build/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuring Bazel's Downloader

> Configure Bazel's downloader for efficient, secure package management, improving resilience and enhancing security

export const BlogPost = ({title, date, authors, tags, image, children}) => {
  const tagList = tags ? tags.split(", ").filter(Boolean) : [];
  const tagSlug = t => t.toLowerCase().replace(/&/g, "").replace(/\+/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
  const formattedDate = date ? new Date(date + "T00:00:00").toLocaleDateString("en-US", {
    year: "numeric",
    month: "long",
    day: "numeric"
  }) : "";
  return <section className="w-full flex justify-center px-4 py-12 md:py-16">
      <div style={{
    maxWidth: "800px",
    width: "100%"
  }}>
        {image && (typeof image === "string" ? <img noZoom src={image} alt={title} className="w-full rounded-xl mb-8" style={{
    maxHeight: "400px",
    objectFit: "cover"
  }} /> : <div className="blog-post-hero-image">{image}</div>)}
        <h1 className="text-3xl md:text-4xl font-bold text-zinc-900 dark:text-white">
          {title}
        </h1>
        <div className="flex flex-wrap items-center gap-3 mt-4 text-sm text-zinc-500 dark:text-zinc-400">
          {authors && <span>{authors}</span>}
          {authors && formattedDate && <span>·</span>}
          {formattedDate && <span>{formattedDate}</span>}
        </div>
        {tagList.length > 0 && <div className="flex flex-wrap gap-2 mt-3">
            {tagList.map(tag => <a key={tag} href={"/blog/tags/" + tagSlug(tag)} className="px-2 py-0.5 rounded-full text-xs bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 hover:bg-blue-100 dark:hover:bg-blue-900/40 hover:text-blue-700 dark:hover:text-blue-300 transition">
                {tag}
              </a>)}
          </div>}
        <hr className="my-8 border-zinc-200 dark:border-zinc-700" />
        <div className="prose dark:prose-invert max-w-none">{children}</div>
      </div>
    </section>;
};

export const MarketingPage = () => <div className="marketing-page-marker" style={{
  display: "none"
}} />;

export const Section = ({children, className = "", gray = false, dark = false, id}) => <section id={id} className={`w-full flex justify-center px-4 py-16 md:py-24 ${gray ? "bg-gray-50 dark:bg-zinc-900" : dark ? "bg-zinc-900 dark:bg-zinc-950" : ""} ${className}`}>
    <div className="w-full" style={{
  maxWidth: "1140px"
}}>
      {children}
    </div>
  </section>;

<MarketingPage />

<BlogPost title="Configuring Bazel's Downloader" date="2021-11-11" authors="Alex Eagle" tags="Bazel">
  <img noZoom src="https://mintcdn.com/aspectbuild/x1L7Iep716jCyJVo/images/blog/stock/server-racks.jpg?fit=max&auto=format&n=x1L7Iep716jCyJVo&q=85&s=060f00604db248271aa008f5e3eaadb8" alt="" className="blog-post-cover" width="800" height="449" data-path="images/blog/stock/server-racks.jpg" />

  Bazel has a built-in downloader that's used for many things. It has a separate cache from the repository cache, so even if some repository rule re-runs, you won't have to fetch from the internet. It's also configurable, though this is undocumented.

  Some repository rules run external programs like `yarn install`, these aren't aware of Bazel's downloader and do their own network fetches. The downloader is used from WORKSPACE with rules like `http_archive` or `http_file`, and can also be used in repository rules with `repository_ctx.download[_and_extract]`.

  Repository rules are a source of non-hermeticity in builds. They also present a security vulnerability when fetching untrusted third-party code. For these reasons we recommend using a local read-through cache like Artifactory for better resilience against network outages, with some security scanner to help identify known vulnerabilities in packages stored in the cache.

  You can tell Bazel to redirect all your downloads through that read-through cache. We recommend doing this on CI to start with, using `--experimental_downloader_config=bazel_downloader.cfg` in `.bazelrc`.

  Now you need to create that config file. Though there isn't documentation, the [source code for UrlRewriterConfig](https://github.com/bazelbuild/bazel/blob/09c621e4cf5b968f4c6cdf905ab142d5961f9ddc/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/UrlRewriterConfig.java#L66) will get you pretty close.

  Here's an example config to get you started.

  ```plaintext theme={null}
  # This file works by going through each URL and matching it to any rewrite line, and if it matches, adding the second
  # parameter as a candidate to the pool. If the candidate set is empty it uses the original. We order this file so that
  # the first match should work so that we don't get any `Warnings:` in the logs.

  allow s3.amazonaws.com

  # For some reason the bazel team decided that mirror.bazel.build should be the source of truth for these 3 files, let
  # those through
  rewrite (mirror.bazel.build/bazel_coverage_output_generator/.*) artifactory.internal.net/artifactory/$1
  rewrite (mirror.bazel.build/bazel_java_tools/.*) artifactory.internal.net/artifactory/$1
  rewrite (mirror.bazel.build/openjdk/.*) artifactory.internal.net/artifactory/$1
  # For everything else, our urls exactly match what mirror.bazel.build gives so skip the indirection
  rewrite mirror.bazel.build/(.*) artifactory.internal.net/artifactory/$1

  # Use any of our remote repositories
  rewrite (dl.google.com)/(.*) artifactory.internal.net/artifactory/$1/$2
  rewrite (files.pythonhosted.org)/(.*) artifactory.internal.net/artifactory/$1/$2
  rewrite (github.com)/(.*) artifactory.internal.net/artifactory/$1/$2
  rewrite (pypi.python.org)/(.*) artifactory.internal.net/artifactory/$1/$2
  rewrite (raw.githubusercontent.com)/(.*) artifactory.internal.net/artifactory/$1/$2
  rewrite (releases.llvm.org)/(.*) artifactory.internal.net/artifactory/$1/$2
  rewrite (repo.maven.apache.org)/(.*) artifactory.internal.net/artifactory/$1/$2
  rewrite (s3.amazonaws.com)/(.*) artifactory.internal.net/artifactory/$1/$2
  rewrite (storage.googleapis.com)/(.*) artifactory.internal.net/artifactory/$1/$2
  rewrite (www.python.org)/(.*) artifactory.internal.net/artifactory/$1/$2
  rewrite (zlib.net)/(.*) artifactory.internal.net/artifactory/$1/$2

  # These are identical URLs so instead of making more remote repositories we just alias the others
  rewrite pypi.org/(.*) artifactory.internal.net/artifactory/pypi.python.org/$1
  rewrite repo1.maven.org/(.*) artifactory.internal.net/artifactory/repo.maven.apache.org/$1

  # Improved security: only allow stuff from artifactory
  allow artifactory.internal.net
  block *
  ```
</BlogPost>
