# Technical Documentation: docker/DISTRIBUTION

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/docker/DISTRIBUTION)

### Overview (`README.md`)

<p align="center">
<img style="align: center; padding-left: 10px; padding-right: 10px; padding-bottom: 10px;" width="238px" height="238px" src="./distribution-logo.svg" />
</p>

[](https://github.com/distribution/distribution/actions/workflows/build.yml?query=branch%3Amain+event%3Apush)
[](https://pkg.go.dev/github.com/distribution/distribution)
[](LICENSE)
[](https://codecov.io/gh/distribution/distribution)
[](https://app.fossa.com/projects/custom%2B162%2Fgithub.com%2Fdistribution%2Fdistribution?ref=badge_shield)
[](https://github.com/distribution/distribution/actions?query=workflow%3Aconformance)
[](https://securityscorecards.dev/viewer/?uri=github.com/distribution/distribution)

The toolset to pack, ship, store, and deliver content.

This repository's main product is the Open Source Registry implementation
for storing and distributing container images and other content using the
[OCI Distribution Specification](https://github.com/opencontainers/distribution-spec).
The goal of this project is to provide a simple, secure, and scalable base
for building a large scale registry solution or running a simple private registry.
It is a core library for many registry operators including Docker Hub, GitHub Container Registry,
GitLab Container Registry and DigitalOcean Container Registry, as well as the CNCF Harbor
Project, and VMware Harbor Registry.

This repository contains the following components:

|**Component**       |Description                                                                                                                                                                                         |
|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **registry**       | An implementation of the [OCI Distribution Specification](https://github.com/opencontainers/distribution-spec).                                                                                                 |
| **libraries**      | A rich set of libraries for interacting with distribution components. Please see [godoc](https://pkg.go.dev/github.com/distribution/distribution) for details. **Note**: The interfaces for these libraries are **unstable**. |
| **documentation**  | Full documentation is available at [https://distribution.github.io/distribution](https://distribution.github.io/distribution/).

### How does this integrate with Docker, containerd, and other OCI client?

Clients implement against the OCI specification and communicate with the
registry using HTTP. This project contains a client implementation which
is currently in use by Docker, however, it is deprecated for the
[implementation in containerd](https://github.com/containerd/containerd/tree/main/core/remotes/docker)
and will not support new features.

### What are the long term goals of the Distribution project?

The _Distribution_ project has the further long term goal of providing a
secure tool chain for distributing content. The specifications, APIs and tools
should be as useful with Docker as they are without.

Our goal is to design a professional grade and extensible content distribution
system that allow users to:

* Enjoy an efficient, secured and reliable way to store, manage, package and
  exchange content
* Hack/roll their own on top of healthy open-source components
* Implement their own home made solution through good specs, and solid
  extensions mechanism.

## Contribution

Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute
issues, fixes, and patches to this project. If you are contributing code, see
the instructions for [building a development environment](BUILDING.md).

## Communication

For async communication and long running discussions please use issues and pull requests on the github repo.
This will be the best place to discuss design and implementation.

For sync communication we have a #distribution channel in the [CNCF Slack](https://slack.cncf.io/)
that everyone is welcome to join and chat about development.

## Licenses

The distribution codebase is released under the [Apache 2.0 license](LICENSE).
The README.md file, and files in the "docs" folder are licensed under the
Creative Commons Attribution 4.0 International License. You may obtain a
copy of the license, titled CC-BY-4.0, at http://creativecommons.org/licenses/by/4.0/.

---

### Overview (`releases/README.md`)

## Registry Release Checklist

10. Compile release notes detailing features added since the last release.

  Add release template file to `releases/` directory. The template is defined
by containerd's release tool. Name the file using the version, for rc add
an `-rc` suffix.
See https://github.com/containerd/release-tool

20. Update the `.mailmap` files.

30. Update the version file: `https://github.com/distribution/distribution/blob/master/version/version.go`

40. Create a signed tag.

  Choose a tag for the next release, distribution uses semantic versioning
and expects tags to be formatted as `vx.y.z[-rc.n]`. Run the release tool using
the release template file and tag to generate the release notes for the tag
and Github release. To create the tag, you will need PGP installed and a PGP
key which has been added to your Github account. The comment for the tag will
be the generated release notes, always compare with previous tags to ensure
the output is expected and consistent.
Run `git tag --cleanup=whitespace -s vx.y.z[-rc.n] -F release-notes` to create
tag and `git -v vx.y.z[-rc.n]` to verify tag, check comment and correct commit
hash.

50. Push the signed tag

60. Create a new [release](https://github.com/distribution/distribution/releases).
In the case of a release candidate, tick the `pre-release` checkbox. Use
the generate release notes from the release tool

70. Update the registry binary in the [distribution library image repo](https://github.com/distribution/distribution-library-image) by running the update script and  opening a pull request.

80. Update the official image.  Add the new version in the [official images repo](https://github.com/docker-library/official-images) by appending a new version to the `registry/registry` file with the git hash pointed to by the signed tag.  Update the major version to point to the latest version and the minor version to point to new patch release if necessary.
e.g. to release `2.3.1`

   `2.3.1 (new)`

   `2.3.0 -> 2.3.0` can be removed

   `2 -> 2.3.1`

   `2.3 -> 2.3.1`

90. Build a new distribution/registry image on [Docker Hub](https://hub.docker.com/u/distribution/dashboard) by adding a new automated build with the new tag and re-building the images.

---

### Overview (`project/hooks/README.md`)

Git Hooks
=========

To enforce valid and properly-formatted code, there is CI in place which runs `gofmt`, `golint`, and `go vet` against code in the repository.

As an aid to prevent committing invalid code in the first place, a git pre-commit hook has been added to the repository, found in [pre-commit](./pre-commit). As it is impossible to automatically add linked hooks to a git repository, this hook should be linked into your `.git/hooks/pre-commit`, which can be done by running the `configure-hooks.sh` script in this directory. This script is the preferred method of configuring hooks, as it will be updated as more are added.

---

### Overview (`docs/themes/hugo-geekdoc/README.md`)

# Geekdoc

[](https://ci.thegeeklab.de/repos/thegeeklab/hugo-geekdoc)
[](https://gohugo.io)
[](https://github.com/thegeeklab/hugo-geekdoc/releases/latest)
[](https://github.com/thegeeklab/hugo-geekdoc/graphs/contributors)
[](https://github.com/thegeeklab/hugo-geekdoc/blob/main/LICENSE)

Geekdoc is a simple Hugo theme for documentations. It is intentionally designed as a fast and lean theme and may not fit the requirements of complex projects. If a more feature-complete theme is required there are a lot of good alternatives out there. You can find a demo and the full documentation at [https://geekdocs.de](https://geekdocs.de).



## Build and release process

This theme is subject to a CI driven build and release process common for software development. During the release build, all necessary assets are automatically built by [webpack](https://webpack.js.org/) and bundled in a release tarball. You can download the latest release from the GitHub [release page](https://github.com/thegeeklab/hugo-geekdoc/releases).

Due to the fact that `webpack` and `npm scripts` are used as pre-processors, the theme cannot be used from the main branch by default. If you want to use the theme from a cloned branch instead of a release tarball you'll need to install `webpack` locally and run the build script once to create all required assets.

```shell
# install required packages from package.json
npm install

# run the build script to build required assets
npm run build

# build release tarball
npm run pack
```

See the [Getting Started Guide](https://geekdocs.de/usage/getting-started/) for details about the different setup options.

## Contributors

Special thanks to all [contributors](https://github.com/thegeeklab/hugo-geekdoc/graphs/contributors). If you would like to contribute, please see the [instructions](https://github.com/thegeeklab/hugo-geekdoc/blob/main/CONTRIBUTING.md).

Geekdoc is inspired and partially based on the [hugo-book](https://github.com/alex-shpak/hugo-book) theme, thanks [Alex Shpak](https://github.com/alex-shpak/) for your work.

## License

This project is licensed under the MIT License - see the [LICENSE](https://github.com/thegeeklab/hugo-geekdoc/blob/main/LICENSE) file for details.

The used SVG icons and generated icon fonts are licensed under the license of the respective icon pack:

- Font Awesome: [CC BY 4.0 License](https://github.com/FortAwesome/Font-Awesome#license)
- IcoMoon Free Pack: [GPL/CC BY 4.0](https://icomoon.io/#icons-icomoon)
- Material Icons: [Apache License 2.0](https://github.com/google/material-design-icons/blob/main/LICENSE)

---

### Overview (`vendor/cel.dev/expr/README.md`)

# Common Expression Language

The Common Expression Language (CEL) implements common semantics for expression
evaluation, enabling different applications to more easily interoperate.

Key Applications

*   Security policy: organizations have complex infrastructure and need common
    tooling to reason about the system as a whole
*   Protocols: expressions are a useful data type and require interoperability
    across programming languages and platforms.


Guiding philosophy:

1.  Keep it small & fast.
    *   CEL evaluates in linear time, is mutation free, and not Turing-complete.
        This limitation is a feature of the language design, which allows the
        implementation to evaluate orders of magnitude faster than equivalently
        sandboxed JavaScript.
2.  Make it extensible.
    *   CEL is designed to be embedded in applications, and allows for
        extensibility via its context which allows for functions and data to be
        provided by the software that embeds it.
3.  Developer-friendly.
    *   The language is approachable to developers. The initial spec was based
        on the experience of developing Firebase Rules and usability testing
        many prior iterations.
    *   The library itself and accompanying toolings should be easy to adopt by
        teams that seek to integrate CEL into their platforms.

The required components of a system that supports CEL are:

*   The textual representation of an expression as written by a developer. It is
    of similar syntax to expressions in C/C++/Java/JavaScript
*   A representation of the program's abstract syntax tree (AST).
*   A compiler library that converts the textual representation to the binary
    representation. This can be done ahead of time (in the control plane) or
    just before evaluation (in the data plane).
*   A context containing one or more typed variables, often protobuf messages.
    Most use-cases will use `attribute_context.proto`
*   An evaluator library that takes the binary format in the context and
    produces a result, usually a Boolean.

For use cases which require persistence or cross-process communcation, it is
highly recommended to serialize the type-checked expression as a protocol
buffer. The CEL team will maintains canonical protocol buffers for ASTs and
will keep these versions identical and wire-compatible in perpetuity:

*  [CEL canonical](https://github.com/google/cel-spec/tree/master/proto/cel/expr)
*  [CEL v1alpha1](https://github.com/googleapis/googleapis/tree/master/google/api/expr/v1alpha1)


Example of boolean conditions and object construction:

``` c
// Condition
account.balance >= transaction.withdrawal
    || (account.overdraftProtection
    && account.overdraftLimit >= transaction.withdrawal  - account.balance)

// Object construction
common.GeoPoint{ latitude: 10.0, longitude: -5.5 }
```

For more detail, see:

*   [Introduction](doc/intro.md)
*   [Language Definition](doc/langdef.md)

Released under the [Apache License](LICENSE).

---

### Overview (`vendor/go.opentelemetry.io/otel/README.md`)

# OpenTelemetry-Go

[](https://github.com/open-telemetry/opentelemetry-go/actions/workflows/ci.yml)
[](https://app.codecov.io/gh/open-telemetry/opentelemetry-go?branch=main)
[](https://pkg.go.dev/go.opentelemetry.io/otel)
[](https://goreportcard.com/report/go.opentelemetry.io/otel)
[](https://scorecard.dev/viewer/?uri=github.com/open-telemetry/opentelemetry-go)
[](https://www.bestpractices.dev/projects/9996)
[](https://issues.oss-fuzz.com/issues?q=project:opentelemetry-go)
[](https://app.fossa.com/projects/custom%2B162%2Fgithub.com%2Fopen-telemetry%2Fopentelemetry-go?ref=badge_shield&issueType=license)
[](https://cloud-native.slack.com/archives/C01NPAXACKT)

OpenTelemetry-Go is the [Go](https://golang.org/) implementation of [OpenTelemetry](https://opentelemetry.io/).
It provides a set of APIs to directly measure performance and behavior of your software and send this data to observability platforms.

## Project Status

| Signal  | Status             |
|---------|--------------------|
| Traces  | Stable             |
| Metrics | Stable             |
| Logs    | Beta[^1]           |

Progress and status specific to this repository is tracked in our
[project boards](https://github.com/open-telemetry/opentelemetry-go/projects)
and
[milestones](https://github.com/open-telemetry/opentelemetry-go/milestones).

Project versioning information and stability guarantees can be found in the
[versioning documentation](VERSIONING.md).

[^1]: https://github.com/orgs/open-telemetry/projects/43

### Compatibility

OpenTelemetry-Go ensures compatibility with the current supported versions of
the [Go language](https://golang.org/doc/devel/release#policy):

> Each major Go release is supported until there are two newer major releases.
> For example, Go 1.5 was supported until the Go 1.7 release, and Go 1.6 was supported until the Go 1.8 release.

For versions of Go that are no longer supported upstream, opentelemetry-go will
stop ensuring compatibility with these versions in the following manner:

- A minor release of opentelemetry-go will be made to add support for the new
  supported release of Go.
- The following minor release of opentelemetry-go will remove compatibility
  testing for the oldest (now archived upstream) version of Go. This, and
  future, releases of opentelemetry-go may include features only supported by
  the currently supported versions of Go.

Currently, this project supports the following environments.

| OS       | Go Version | Architecture |
|----------|------------|--------------|
| Ubuntu   | 1.26       | amd64        |
| Ubuntu   | 1.25       | amd64        |
| Ubuntu   | 1.26       | 386          |
| Ubuntu   | 1.25       | 386          |
| Ubuntu   | 1.26       | arm64        |
| Ubuntu   | 1.25       | arm64        |
| macOS    | 1.26       | amd64        |
| macOS    | 1.25       | amd64        |
| macOS    | 1.26       | arm64        |
| macOS    | 1.25       | arm64        |
| Windows  | 1.26       | amd64        |
| Windows  | 1.25       | amd64        |
| Windows  | 1.26       | 386          |
| Windows  | 1.25       | 386          |

While this project should work for other systems, no compatibility guarantees
are made for those systems currently.

## Getting Started

You can find a getting started guide on [opentelemetry.io](https://opentelemetry.io/docs/languages/go/getting-started/).

OpenTelemetry's goal is to provide a single set of APIs to capture distributed
traces and metrics from your application and send them to an observability
platform. This project allows you to do just that for applications written in
Go. There are two steps to this process: instrument your application, and
configure an exporter.

### Instrumentation

To start capturing distributed traces and metric events from your application
it first needs to be instrumented. The easiest way to do this is by using an
instrumentation library for your code. Be sure to check out [the officially
supported instrumentation
libraries](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/instrumentation).

If you need to extend the telemetry an instrumentation library provides or want
to build your own instrumentation for your application directly you will need
to use the
[Go otel](https://pkg.go.dev/go.opentelemetry.io/otel)
package. The [examples](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/examples)
are a good way to see some practical uses of this process.

### Export

Now that your application is instrumented to collect telemetry, it needs an
export pipeline to send that telemetry to an observability platform.

All officially supported exporters for the OpenTelemetry project are contained in the [exporters directory](./exporters).

| Exporter                              | Logs | Metrics | Traces |
|---------------------------------------|:----:|:-------:|:------:|
| [OTLP](./exporters/otlp/)             |  ✓   |    ✓    |   ✓    |
| [Prometheus](./exporters/prometheus/) |      |    ✓    |        |
| [stdout](./exporters/stdout/)         |  ✓   |    ✓    |   ✓    |
| [Zipkin](./exporters/zipkin/)         |      |         |   ✓    |

## Contributing

See the [contributing documentation](CONTRIBUTING.md).

### Emeritus

- [Alex Kats](https://github.com/akats7), Triager

For more information about the emeritus role, see the
[community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#emeritus-maintainerapprovertriager).

---

### Overview (`vendor/google.golang.org/grpc/README.md`)

# gRPC-Go

[][API]
[](https://goreportcard.com/report/github.com/grpc/grpc-go)
[](https://codecov.io/gh/grpc/grpc-go)

The [Go][] implementation of [gRPC][]: A high performance, open source, general
RPC framework that puts mobile and HTTP/2 first. For more information see the
[Go gRPC docs][], or jump directly into the [quick start][].

## Prerequisites

- **[Go][]**: any one of the **two latest major** [releases][go-releases].

## Installation

Simply add the following import to your code, and then `go [build|run|test]`
will automatically fetch the necessary dependencies:


```go
import "google.golang.org/grpc"
```

> **Note:** If you are trying to access `grpc-go` from **China**, see the
> [FAQ](#FAQ) below.

## Learn more

- [Go gRPC docs][], which include a [quick start][] and [API
  reference][API] among other resources
- [Low-level technical docs](Documentation) from this repository
- [Performance benchmark][]
- [Examples](examples)
- [Contribution guidelines](CONTRIBUTING.md)

## FAQ

### I/O Timeout Errors

The `golang.org` domain may be blocked from some countries. `go get` usually
produces an error like the following when this happens:

```console
$ go get -u google.golang.org/grpc
package google.golang.org/grpc: unrecognized import path "google.golang.org/grpc" (https fetch: Get https://google.golang.org/grpc?go-get=1: dial tcp 216.239.37.1:443: i/o timeout)
```

To build Go code, there are several options:

- Set up a VPN and access google.golang.org through that.

- With Go module support: it is possible to use the `replace` feature of `go
  mod` to create aliases for golang.org packages.  In your project's directory:

  ```sh
  go mod edit -replace=google.golang.org/grpc=github.com/grpc/grpc-go@latest
  go mod tidy
  go mod vendor
  go build -mod=vendor
  ```

  Again, this will need to be done for all transitive dependencies hosted on
  golang.org as well. For details, refer to [golang/go issue
  #28652](https://github.com/golang/go/issues/28652).

### Compiling error, undefined: grpc.SupportPackageIsVersion

Please update to the latest version of gRPC-Go using
`go get google.golang.org/grpc`.

### How to turn on logging

The default logger is controlled by environment variables. Turn everything on
like this:

```console
$ export GRPC_GO_LOG_VERBOSITY_LEVEL=99
$ export GRPC_GO_LOG_SEVERITY_LEVEL=info
```

### The RPC failed with error `"code = Unavailable desc = transport is closing"`

This error means the connection the RPC is using was closed, and there are many
possible reasons, including:
 1. mis-configured transport credentials, connection failed on handshaking
 1. bytes disrupted, possibly by a proxy in between
 1. server shutdown
 1. Keepalive parameters caused connection shutdown, for example if you have
    configured your server to terminate connections regularly to [trigger DNS
    lookups](https://github.com/grpc/grpc-go/issues/3170#issuecomment-552517779).
    If this is the case, you may want to increase your
    [MaxConnectionAgeGrace](https://pkg.go.dev/google.golang.org/grpc/keepalive?tab=doc#ServerParameters),
    to allow longer RPC calls to finish.

It can be tricky to debug this because the error happens on the client side but
the root cause of the connection being closed is on the server side. Turn on
logging on __both client and server__, and see if there are any transport
errors.

[API]: https://pkg.go.dev/google.golang.org/grpc
[Go]: https://golang.org
[Go module]: https://github.com/golang/go/wiki/Modules
[gRPC]: https://grpc.io
[Go gRPC docs]: https://grpc.io/docs/languages/go
[Performance benchmark]: https://performance-dot-grpc-testing.appspot.com/explore?dashboard=5180705743044608
[quick start]: https://grpc.io/docs/languages/go/quickstart
[go-releases]: https://golang.org/doc/devel/release.html

---

### Overview (`vendor/cloud.google.com/go/auth/README.md`)

# Google Auth Library for Go

[](https://pkg.go.dev/cloud.google.com/go/auth)

## Install

``` bash
go get cloud.google.com/go/auth@latest
```

## Usage

The most common way this library is used is transitively, by default, from any
of our Go client libraries.

### Notable use-cases

- To create a credential directly please see examples in the
  [credentials](https://pkg.go.dev/cloud.google.com/go/auth/credentials)
  package.
- To create a authenticated HTTP client please see examples in the
  [httptransport](https://pkg.go.dev/cloud.google.com/go/auth/httptransport)
  package.
- To create a authenticated gRPC connection please see examples in the
  [grpctransport](https://pkg.go.dev/cloud.google.com/go/auth/grpctransport)
  package.
- To create an ID token please see examples in the
  [idtoken](https://pkg.go.dev/cloud.google.com/go/auth/credentials/idtoken)
  package.

## Contributing

Contributions are welcome. Please, see the
[CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md)
document for details.

Please note that this project is released with a Contributor Code of Conduct.
By participating in this project you agree to abide by its terms.
See [Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md#contributor-code-of-conduct)
for more information.

---

### Overview (`vendor/cloud.google.com/go/iam/README.md`)

# IAM API

[](https://pkg.go.dev/cloud.google.com/go/iam)

Go Client Library for IAM API.

## Install

```bash
go get cloud.google.com/go/iam
```

## Stability

The stability of this module is indicated by SemVer.

However, a `v1+` module may have breaking changes in two scenarios:

* Packages with `alpha` or `beta` in the import path
* The GoDoc has an explicit stability disclaimer (for example, for an experimental feature).

## Go Version Support

See the [Go Versions Supported](https://github.com/googleapis/google-cloud-go#go-versions-supported)
section in the root directory's README.

## Authorization

See the [Authorization](https://github.com/googleapis/google-cloud-go#authorization)
section in the root directory's README.

## Contributing

Contributions are welcome. Please, see the [CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md)
document for details.

Please note that this project is released with a Contributor Code of Conduct.
By participating in this project you agree to abide by its terms. See
[Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md#contributor-code-of-conduct)
for more information.

---

### Overview (`vendor/cloud.google.com/go/internal/README.md`)

# Internal

This directory contains internal code for cloud.google.com/go packages.

## .repo-metadata-full.json

`.repo-metadata-full.json` contains metadata about the packages in this repo. It
is generated by `internal/gapicgen/generator`. It's processed by external tools
to build lists of all of the packages.

Don't make breaking changes to the format without consulting with the external
tools.

One day, we may want to create individual `.repo-metadata.json` files next to
each package, which is the pattern followed by some other languages. External
tools would then talk to pkg.go.dev or some other service to get the overall
list of packages and use the `.repo-metadata.json` files to get the additional
metadata required. For now, `.repo-metadata-full.json` includes everything.

### Updating OwlBot SHA

You may want to manually update the which version of the post-processor will be
used -- to do this you need to update the SHA in the OwlBot lock file.

See the [postprocessor/README](postprocessor/README.md) for detailed
instructions.

*Note*: OwlBot will eventually open a pull request to update this value if it
discovers a new version of the container.

---

### Overview (`vendor/cloud.google.com/go/storage/README.md`)

## Cloud Storage [](https://pkg.go.dev/cloud.google.com/go/storage)

- [About Cloud Storage](https://cloud.google.com/storage/)
- [API documentation](https://cloud.google.com/storage/docs)
- [Go client documentation](https://cloud.google.com/go/docs/reference/cloud.google.com/go/storage/latest)
- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/main/storage)

### Example Usage

First create a `storage.Client` to use throughout your application:

[snip]:# (storage-1)
```go
client, err := storage.NewClient(ctx)
if err != nil {
	log.Fatal(err)
}
```

[snip]:# (storage-2)
```go
// Read the object1 from bucket.
rc, err := client.Bucket("bucket").Object("object1").NewReader(ctx)
if err != nil {
	log.Fatal(err)
}
defer rc.Close()
body, err := io.ReadAll(rc)
if err != nil {
	log.Fatal(err)
}
```

---

### Overview (`vendor/github.com/AdaLogics/go-fuzz-headers/README.md`)

# go-fuzz-headers
This repository contains various helper functions for go fuzzing. It is mostly used in combination with [go-fuzz](https://github.com/dvyukov/go-fuzz), but compatibility with fuzzing in the standard library will also be supported. Any coverage guided fuzzing engine that provides an array or slice of bytes can be used with go-fuzz-headers.


## Usage
Using go-fuzz-headers is easy. First create a new consumer with the bytes provided by the fuzzing engine:

```go
import (
	fuzz "github.com/AdaLogics/go-fuzz-headers"
)
data := []byte{'R', 'a', 'n', 'd', 'o', 'm'}
f := fuzz.NewConsumer(data)

```

This creates a `Consumer` that consumes the bytes of the input as it uses them to fuzz different types.

After that, `f` can be used to easily create fuzzed instances of different types. Below are some examples:

### Structs
One of the most useful features of go-fuzz-headers is its ability to fill structs with the data provided by the fuzzing engine. This is done with a single line:
```go
type Person struct {
    Name string
    Age  int
}
p := Person{}
// Fill p with values based on the data provided by the fuzzing engine:
err := f.GenerateStruct(&p)
```

This includes nested structs too. In this example, the fuzz Consumer will also insert values in `p.BestFriend`:
```go
type PersonI struct {
    Name       string
    Age        int
    BestFriend PersonII
}
type PersonII struct {
    Name string
    Age  int
}
p := PersonI{}
err := f.GenerateStruct(&p)
```

If the consumer should insert values for unexported fields as well as exported, this can be enabled with:

```go
f.AllowUnexportedFields()
```

...and disabled with:

```go
f.DisallowUnexportedFields()
```

### Other types:

Other useful APIs:

```go
createdString, err := f.GetString() // Gets a string
createdInt, err := f.GetInt() // Gets an integer
createdByte, err := f.GetByte() // Gets a byte
createdBytes, err := f.GetBytes() // Gets a byte slice
createdBool, err := f.GetBool() // Gets a boolean
err := f.FuzzMap(target_map) // Fills a map
createdTarBytes, err := f.TarBytes() // Gets bytes of a valid tar archive
err := f.CreateFiles(inThisDir) // Fills inThisDir with files
createdString, err := f.GetStringFrom("anyCharInThisString", ofThisLength) // Gets a string that consists of chars from "anyCharInThisString" and has the exact length "ofThisLength"
```

Most APIs are added as they are needed.

## Projects that use go-fuzz-headers
- [runC](https://github.com/opencontainers/runc)
- [Istio](https://github.com/istio/istio)
- [Vitess](https://github.com/vitessio/vitess)
- [Containerd](https://github.com/containerd/containerd)

Feel free to add your own project to the list, if you use go-fuzz-headers to fuzz it.


 

## Status
The project is under development and will be updated regularly.

## References
go-fuzz-headers' approach to fuzzing structs is strongly inspired by [gofuzz](https://github.com/google/gofuzz).

---

### Overview (`vendor/github.com/cyphar/filepath-securejoin/README.md`)

## `filepath-securejoin` ##

[](https://github.com/cyphar/filepath-securejoin/actions/workflows/ci.yml)

An implementation of `SecureJoin`, a [candidate for inclusion in the Go
standard library][go#20126]. The purpose of this function is to be a "secure"
alternative to `filepath.Join`, and in particular it provides certain
guarantees that are not provided by `filepath.Join`.

> **NOTE**: This code is *only* safe if you are not at risk of other processes
> modifying path components after you've used `SecureJoin`. If it is possible
> for a malicious process to modify path components of the resolved path, then
> you will be vulnerable to some fairly trivial TOCTOU race conditions. [There
> are some Linux kernel patches I'm working on which might allow for a better
> solution.][lwn-obeneath]
>
> In addition, with a slightly modified API it might be possible to use
> `O_PATH` and verify that the opened path is actually the resolved one -- but
> I have not done that yet. I might add it in the future as a helper function
> to help users verify the path (we can't just return `/proc/self/fd/<foo>`
> because that doesn't always work transparently for all users).

This is the function prototype:

```go
func SecureJoin(root, unsafePath string) (string, error)
```

This library **guarantees** the following:

* If no error is set, the resulting string **must** be a child path of
  `root` and will not contain any symlink path components (they will all be
  expanded).

* When expanding symlinks, all symlink path components **must** be resolved
  relative to the provided root. In particular, this can be considered a
  userspace implementation of how `chroot(2)` operates on file paths. Note that
  these symlinks will **not** be expanded lexically (`filepath.Clean` is not
  called on the input before processing).

* Non-existent path components are unaffected by `SecureJoin` (similar to
  `filepath.EvalSymlinks`'s semantics).

* The returned path will always be `filepath.Clean`ed and thus not contain any
  `..` components.

A (trivial) implementation of this function on GNU/Linux systems could be done
with the following (note that this requires root privileges and is far more
opaque than the implementation in this library, and also requires that
`readlink` is inside the `root` path):

```go
package securejoin

import (
	"os/exec"
	"path/filepath"
)

func SecureJoin(root, unsafePath string) (string, error) {
	unsafePath = string(filepath.Separator) + unsafePath
	cmd := exec.Command("chroot", root,
		"readlink", "--canonicalize-missing", "--no-newline", unsafePath)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return "", err
	}
	expanded := string(output)
	return filepath.Join(root, expanded), nil
}
```

[lwn-obeneath]: https://lwn.net/Articles/767547/
[go#20126]: https://github.com/golang/go/issues/20126

### License ###

The license of this project is the same as Go, which is a BSD 3-clause license
available in the `LICENSE` file.

---

### Overview (`vendor/github.com/distribution/reference/README.md`)

# Distribution reference

Go library to handle references to container images.

<img src="/distribution-logo.svg" width="200px" />

[](https://github.com/distribution/reference/actions?query=workflow%3ACI)
[](https://pkg.go.dev/github.com/distribution/reference)
[](LICENSE)
[](https://codecov.io/gh/distribution/reference)
[](https://app.fossa.com/projects/custom%2B162%2Fgithub.com%2Fdistribution%2Freference?ref=badge_shield)

This repository contains a library for handling references to container images held in container registries. Please see [godoc](https://pkg.go.dev/github.com/distribution/reference) for details.

## Contribution

Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute
issues, fixes, and patches to this project.

## Communication

For async communication and long running discussions please use issues and pull requests on the github repo.
This will be the best place to discuss design and implementation.

For sync communication we have a #distribution channel in the [CNCF Slack](https://slack.cncf.io/)
that everyone is welcome to join and chat about development.

## Licenses

The distribution codebase is released under the [Apache 2.0 license](LICENSE).

---

### Overview (`vendor/github.com/docker/go-events/README.md`)

# Docker Events Package

[](https://godoc.org/github.com/docker/go-events)
[](https://github.com/docker/go-events/actions/workflows/ci.yml)
[](https://goreportcard.com/report/github.com/docker/go-events)

The Docker `events` package implements a composable event distribution package
for Go.

Originally created to implement the [notifications in Docker Registry
2](https://github.com/docker/distribution/blob/master/docs/notifications.md),
we've found the pattern to be useful in other applications. This package is
most of the same code with slightly updated interfaces. Much of the internals
have been made available.

## Usage

The `events` package centers around a `Sink` type.  Events are written with
calls to `Sink.Write(event Event)`. Sinks can be wired up in various
configurations to achieve interesting behavior.

The canonical example is that employed by the
[docker/distribution/notifications](https://godoc.org/github.com/docker/distribution/notifications)
package. Let's say we have a type `httpSink` where we'd like to queue
notifications. As a rule, it should send a single http request and return an
error if it fails:

```go
func (h *httpSink) Write(event Event) error {
	p, err := json.Marshal(event)
	if err != nil {
		return err
	}
	body := bytes.NewReader(p)
	resp, err := h.client.Post(h.url, "application/json", body)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	
	if resp.Status != 200 {
		return errors.New("unexpected status")
	}

	return nil
}

// implement (*httpSink).Close()
```

With just that, we can start using components from this package. One can call
`(*httpSink).Write` to send events as the body of a post request to a
configured URL.

### Retries

HTTP can be unreliable. The first feature we'd like is to have some retry:

```go
hs := newHTTPSink(/*...*/)
retry := NewRetryingSink(hs, NewBreaker(5, time.Second))
```

We now have a sink that will retry events against the `httpSink` until they
succeed. The retry will backoff for one second after 5 consecutive failures
using the breaker strategy.

### Queues

This isn't quite enough. We we want a sink that doesn't block while we are
waiting for events to be sent. Let's add a `Queue`:

```go
queue := NewQueue(retry)
```

Now, we have an unbounded queue that will work through all events sent with
`(*Queue).Write`. Events can be added asynchronously to the queue without
blocking the current execution path. This is ideal for use in an http request.

### Broadcast

It usually turns out that you want to send to more than one listener. We can
use `Broadcaster` to support this:

```go
var broadcast = NewBroadcaster() // make it available somewhere in your application.
broadcast.Add(queue) // add your queue!
broadcast.Add(queue2) // and another!
```

With the above, we can now call `broadcast.Write` in our http handlers and have
all the events distributed to each queue. Because the events are queued, not
listener blocks another.

### Extending

For the most part, the above is sufficient for a lot of applications. However,
extending the above functionality can be done implementing your own `Sink`. The
behavior and semantics of the sink can be completely dependent on the
application requirements. The interface is provided below for reference:

```go
type Sink {
	Write(Event) error
	Close() error
}
```

Application behavior can be controlled by how `Write` behaves. The examples
above are designed to queue the message and return as quickly as possible.
Other implementations may block until the event is committed to durable
storage.

## Copyright and license

Copyright © 2016 Docker, Inc. go-events is licensed under the Apache License,
Version 2.0. See [LICENSE](LICENSE) for the full license text.

---

### Overview (`vendor/github.com/docker/go-metrics/README.md`)

# go-metrics

[](https://pkg.go.dev/github.com/docker/go-metrics)

This package is small wrapper around the prometheus go client to help enforce convention and best practices for metrics collection in Docker projects.

## Best Practices

This packages is meant to be used for collecting metrics. It is not meant to be
used as a replacement for the prometheus client but to help enforce consistent
naming across metrics collected. If you have not already read the prometheus
best practices around naming and labels you can read the naming section in the
[prometheus documentation](https://prometheus.io/docs/practices/naming/).

The following are a few conventions that help naming metrics in your project.

### Namespace and Subsystem

This package provides you with a namespace type that allows you to specify the
same namespace and subsystem for your metrics.

```go
ns := metrics.NewNamespace("engine", "daemon", metrics.Labels{
        "version": daemon.Version,
        "commit":  daemon.GitCommit,
})
```

In the example above we are creating metrics for the daemon package.
`engine` would be the namespace in this example where `daemon` is the subsystem
or package where we are collecting the metrics.

A namespace also allows you to attach constant labels to the metrics such as
the git commit and version that it is collecting.

### Declaring your Metrics

Try to keep all your metric declarations in one file. This makes it easy for
others to see what constant labels are defined on the namespace and what
labels are defined on the metrics when they are created.

### Use labels instead of multiple metrics

Labels allow you to define one metric such as the time it takes to perform a
certain action on an object. If we wanted to collect timings on various container
actions such as create, start, and delete then we can define one metric called
`container_actions` and use labels to specify the type of action.


```go
containerActions = ns.NewLabeledTimer("container_actions", "The number of milliseconds it takes to process each container action", "action")
```

The last parameter is the label name or key. When adding a data point to the
metric you can use the `WithValues` function to specify the `action` that you
are collecting for.

```go
containerActions.WithValues("create").UpdateSince(start)
```

### Always use a unit

The metric name should describe what you are measuring but you also need to
provide the unit that it is being measured with. For a timer, the standard
unit is seconds and a counter's standard unit is a total. For gauges you must
provide the unit. This package provides a standard set of units for use within
your projects.

```go
Nanoseconds Unit = "nanoseconds"
Seconds     Unit = "seconds"
Bytes       Unit = "bytes"
Total       Unit = "total"
```

If you need to use a unit but it is not defined in the package please open
a PR to add it but first try to see if one of the existing units work for
your metric, i.e., seconds or nanoseconds vs adding milliseconds.

## HTTP Metrics

To instrument a http handler, you can wrap the code like this:

```go
namespace := metrics.NewNamespace("api_server", "http", metrics.Labels{"handler": "your_http_handler_name"})
httpMetrics := namespace.NewDefaultHttpMetrics()
metrics.Register(namespace)
instrumentedHandler = metrics.InstrumentHandler(httpMetrics, unInstrumentedHandler)
```
Note: The `handler` label must be provided when a new namespace is created.

## Additional Metrics

Additional metrics are also defined here that are not available in the prometheus client.
If you need a custom metrics and it is generic enough to be used by multiple projects, define it here.


## Copyright and license

Copyright © 2016 Docker, Inc. All rights reserved, except as follows. Code is released under the Apache 2.0 license.

---

### Overview (`vendor/github.com/felixge/httpsnoop/README.md`)

# httpsnoop

Package httpsnoop provides an easy way to capture http related metrics (i.e.
response time, bytes written, and http status code) from your application's
http.Handlers.

Doing this requires non-trivial wrapping of the http.ResponseWriter interface,
which is also exposed for users interested in a more low-level API.

[](https://pkg.go.dev/github.com/felixge/httpsnoop)
[](https://github.com/felixge/httpsnoop/actions/workflows/main.yaml)

## Usage Example

```go
// myH is your app's http handler, perhaps a http.ServeMux or similar.
var myH http.Handler
// wrappedH wraps myH in order to log every request.
wrappedH := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	m := httpsnoop.CaptureMetrics(myH, w, r)
	log.Printf(
		"%s %s (code=%d dt=%s written=%d)",
		r.Method,
		r.URL,
		m.Code,
		m.Duration,
		m.Written,
	)
})
http.ListenAndServe(":8080", wrappedH)
```

## Why this package exists

Instrumenting an application's http.Handler is surprisingly difficult.

However if you google for e.g. "capture ResponseWriter status code" you'll find
lots of advise and code examples that suggest it to be a fairly trivial
undertaking. Unfortunately everything I've seen so far has a high chance of
breaking your application.

The main problem is that a `http.ResponseWriter` often implements additional
interfaces such as `http.Flusher`, `http.CloseNotifier`, `http.Hijacker`, `http.Pusher`, and
`io.ReaderFrom`. So the naive approach of just wrapping `http.ResponseWriter`
in your own struct that also implements the `http.ResponseWriter` interface
will hide the additional interfaces mentioned above. This has a high change of
introducing subtle bugs into any non-trivial application.

Another approach I've seen people take is to return a struct that implements
all of the interfaces above. However, that's also problematic, because it's
difficult to fake some of these interfaces behaviors when the underlying
`http.ResponseWriter` doesn't have an implementation. It's also dangerous,
because an application may choose to operate differently, merely because it
detects the presence of these additional interfaces.

This package solves this problem by checking which additional interfaces a
`http.ResponseWriter` implements, returning a wrapped version implementing the
exact same set of interfaces.

Additionally this package properly handles edge cases such as `WriteHeader` not
being called, or called more than once, as well as concurrent calls to
`http.ResponseWriter` methods, and even calls happening after the wrapped
`ServeHTTP` has already returned.

Unfortunately this package is not perfect either. It's possible that it is
still missing some interfaces provided by the go core (let me know if you find
one), and it won't work for applications adding their own interfaces into the
mix. You can however use `httpsnoop.Unwrap(w)` to access the underlying
`http.ResponseWriter` and type-assert the result to its other interfaces.

However, hopefully the explanation above has sufficiently scared you of rolling
your own solution to this problem. httpsnoop may still break your application,
but at least it tries to avoid it as much as possible.

Anyway, the real problem here is that smuggling additional interfaces inside
`http.ResponseWriter` is a problematic design choice, but it probably goes as
deep as the Go language specification itself. But that's okay, I still prefer
Go over the alternatives ;).

## Performance

```
BenchmarkBaseline-8      	   20000	     94912 ns/op
BenchmarkCaptureMetrics-8	   20000	     95461 ns/op
```

As you can see, using `CaptureMetrics` on a vanilla http.Handler introduces an
overhead of ~500 ns per http request on my machine. However, the margin of
error appears to be larger than that, therefor it should be reasonable to
assume that the overhead introduced by `CaptureMetrics` is absolutely
negligible.

## License

MIT

---

### Overview (`vendor/github.com/go-logr/logr/README.md`)

# A minimal logging API for Go

[](https://pkg.go.dev/github.com/go-logr/logr)
[](https://goreportcard.com/report/github.com/go-logr/logr)
[](https://securityscorecards.dev/viewer/?platform=github.com&org=go-logr&repo=logr)

logr offers an(other) opinion on how Go programs and libraries can do logging
without becoming coupled to a particular logging implementation.  This is not
an implementation of logging - it is an API.  In fact it is two APIs with two
different sets of users.

The `Logger` type is intended for application and library authors.  It provides
a relatively small API which can be used everywhere you want to emit logs.  It
defers the actual act of writing logs (to files, to stdout, or whatever) to the
`LogSink` interface.

The `LogSink` interface is intended for logging library implementers.  It is a
pure interface which can be implemented by logging frameworks to provide the actual logging
functionality.

This decoupling allows application and library developers to write code in
terms of `logr.Logger` (which has very low dependency fan-out) while the
implementation of logging is managed "up stack" (e.g. in or near `main()`.)
Application developers can then switch out implementations as necessary.

Many people assert that libraries should not be logging, and as such efforts
like this are pointless.  Those people are welcome to convince the authors of
the tens-of-thousands of libraries that *DO* write logs that they are all
wrong.  In the meantime, logr takes a more practical approach.

## Typical usage

Somewhere, early in an application's life, it will make a decision about which
logging library (implementation) it actually wants to use.  Something like:

```
    func main() {
        // ... other setup code ...

        // Create the "root" logger.  We have chosen the "logimpl" implementation,
        // which takes some initial parameters and returns a logr.Logger.
        logger := logimpl.New(param1, param2)

        // ... other setup code ...
```

Most apps will call into other libraries, create structures to govern the flow,
etc.  The `logr.Logger` object can be passed to these other libraries, stored
in structs, or even used as a package-global variable, if needed.  For example:

```
    app := createTheAppObject(logger)
    app.Run()
```

Outside of this early setup, no other packages need to know about the choice of
implementation.  They write logs in terms of the `logr.Logger` that they
received:

```
    type appObject struct {
        // ... other fields ...
        logger logr.Logger
        // ... other fields ...
    }

    func (app *appObject) Run() {
        app.logger.Info("starting up", "timestamp", time.Now())

        // ... app code ...
```

## Background

If the Go standard library had defined an interface for logging, this project
probably would not be needed.  Alas, here we are.

When the Go developers started developing such an interface with
[slog](https://github.com/golang/go/issues/56345), they adopted some of the
logr design but also left out some parts and changed others:

| Feature | logr | slog |
|---------|------|------|
| High-level API | `Logger` (passed by value) | `Logger` (passed by [pointer](https://github.com/golang/go/issues/59126)) |
| Low-level API | `LogSink` | `Handler` |
| Stack unwinding | done by `LogSink` | done by `Logger` |
| Skipping helper functions | `WithCallDepth`, `WithCallStackHelper` | [not supported by Logger](https://github.com/golang/go/issues/59145) |
| Generating a value for logging on demand | `Marshaler` | `LogValuer` |
| Log levels | >= 0, higher meaning "less important" | positive and negative, with 0 for "info" and higher meaning "more important" |
| Error log entries | always logged, don't have a verbosity level | normal log entries with level >= `LevelError` |
| Passing logger via context | `NewContext`, `FromContext` | no API |
| Adding a name to a logger | `WithName` | no API |
| Modify verbosity of log entries in a call chain | `V` | no API |
| Grouping of key/value pairs | not supported | `WithGroup`, `GroupValue` |
| Pass context for extracting additional values | no API | API variants like `InfoCtx` |

The high-level slog API is explicitly meant to be one of many different APIs
that can be layered on top of a shared `slog.Handler`. logr is one such
alternative API, with [interoperability](#slog-interoperability) provided by
some conversion functions.

### Inspiration

Before you consider this package, please read [this blog post by the
inimitable Dave Cheney][warning-makes-no-sense].  We really appreciate what
he has to say, and it largely aligns with our own experiences.

### Differences from Dave's ideas

The main differences are:

1. Dave basically proposes doing away with the notion of a logging API in favor
of `fmt.Printf()`.  We disagree, especially when you consider things like output
locations, timestamps, file and line decorations, and structured logging.  This
package restricts the logging API to just 2 types of logs: info and error.

Info logs are things you want to tell the user which are not errors.  Error
logs are, well, errors.  If your code receives an `error` from a subordinate
function call and is logging that `error` *and not returning it*, use error
logs.

2. Verbosity-levels on info logs.  This gives developers a chance to indicate
arbitrary grades of importance for info logs, without assigning names with
semantic meaning such as "warning", "trace", and "debug."  Superficially this
may feel very similar, but the primary difference is the lack of semantics.
Because verbosity is a numerical value, it's safe to assume that an app running
with higher verbosity means more (and less important) logs will be generated.

## Implementations (non-exhaustive)

There are implementations for the following logging libraries:

- **a function** (can bridge to non-structured libraries): [funcr](https://github.com/go-logr/logr/tree/master/funcr)
- **a testing.T** (for use in Go tests, with JSON-like output): [testr](https://github.com/go-logr/logr/tree/master/testr)
- **github.com/google/glog**: [glogr](https://github.com/go-logr/glogr)
- **k8s.io/klog** (for Kubernetes): [klogr](https://git.k8s.io/klog/klogr)
- **a testing.T** (with klog-like text output): [ktesting](https://git.k8s.io/klog/ktesting)
- **go.uber.org/zap**: [zapr](https://github.com/go-logr/zapr)
- **log** (the Go standard library logger): [stdr](https://github.com/go-logr/stdr)
- **github.com/sirupsen/logrus**: [logrusr](https://github.com/bombsimon/logrusr)
- **github.com/wojas/genericr**: [genericr](https://github.com/wojas/genericr) (makes it easy to implement your own backend)
- **logfmt** (Heroku style [logging](https://www.brandur.org/logfmt)): [logfmtr](https://github.com/iand/logfmtr)
- **github.com/rs/zerolog**: [zerologr](https://github.com/go-logr/zerologr)
- **github.com/go-kit/log**: [gokitlogr](https://github.com/tonglil/gokitlogr) (also compatible with github.com/go-kit/kit/log since v0.12.0)
- **bytes.Buffer** (writing to a buffer): [bufrlogr](https://github.com/tonglil/buflogr) (useful for ensuring values were logged, like during testing)

## slog interoperability

Interoperability goes both ways, using the `logr.Logger` API with a `slog.Handler`
and using the `slog.Logger` API with a `logr.LogSink`. `FromSlogHandler` and
`ToSlogHandler` convert between a `logr.Logger` and a `slog.Handler`.
As usual, `slog.New` can be used to wrap such a `slog.Handler` in the high-level
slog API.

### Using a `logr.LogSink` as backend for slog

Ideally, a logr sink implementation should support both logr and slog by
implementing both the normal logr interface(s) and `SlogSink`.  Because
of a conflict in the parameters of the common `Enabled` method, it is [not
possible to implement both slog.Handler and logr.Sink in the same
type](https://github.com/golang/go/issues/59110).

If both are supported, log calls can go from the high-level APIs to the backend
without the need to convert parameters. `FromSlogHandler` and `ToSlogHandler` can
convert back and forth without adding additional wrappers, with one exception:
when `Logger.V` was used to adjust the verbosity for a `slog.Handler`, then
`ToSlogHandler` has to use a wrapper which adjusts the verbosity for future
log calls.

Such an implementation should also support values that implement specific
interfaces from both packages for logging (`logr.Marshaler`, `slog.LogValuer`,
`slog.GroupValue`). logr does not convert those.

Not supporting slog has several drawbacks:
- Recording source code locations works correctly if the handler gets called
  through `slog.Logger`, but may be wrong in other cases. That's because a
  `logr.Sink` does its own stack unwinding instead of using the program counter
  provided by the high-level API.
- slog levels <= 0 can be mapped to logr levels by negating the level without a
  loss of information. But all slog levels > 0 (e.g. `slog.LevelWarning` as
  used by `slog.Logger.Warn`) must be mapped to 0 before calling the sink
  because logr does not support "more important than info" levels.
- The slog group concept is supported by prefixing each key in a key/value
  pair with the group names, separated by a dot. For structured output like
  JSON it would be better to group the key/value pairs inside an object.
- Special slog values and interfaces don't work as expected.
- The overhead is likely to be higher.

These drawbacks are severe enough that applications using a mixture of slog and
logr should switch to a different backend.

### Using a `slog.Handler` as backend for logr

Using a plain `slog.Handler` without support for logr works better than the
other direction:
- All logr verbosity levels can be mapped 1:1 to their corresponding slog level
  by negating them.
- Stack unwinding is done by the `SlogSink` and the resulting program
  counter is passed to the `slog.Handler`.
- Names added via `Logger.WithName` are gathered and recorded in an additional
  attribute with `logger` as key and the names separated by slash as value.
- `Logger.Error` is turned into a log record with `slog.LevelError` as level
  and an additional attribute with `err` as key, if an error was provided.

The main drawback is that `logr.Marshaler` will not be supported. Types should
ideally support both `logr.Marshaler` and `slog.Valuer`. If compatibility
with logr implementations without slog support is not important, then
`slog.Valuer` is sufficient.

### Context support for slog

Storing a logger in a `context.Context` is not supported by
slog. `NewContextWithSlogLogger` and `FromContextAsSlogLogger` can be
used to fill this gap. They store and retrieve a `slog.Logger` pointer
under the same context key that is also used by `NewContext` and
`FromContext` for `logr.Logger` value.

When `NewContextWithSlogLogger` is followed by `FromContext`, the latter will
automatically convert the `slog.Logger` to a
`logr.Logger`. `FromContextAsSlogLogger` does the same for the other direction.

With this approach, binaries which use either slog or logr are as efficient as
possible with no unnecessary allocations. This is also why the API stores a
`slog.Logger` pointer: when storing a `slog.Handler`, creating a `slog.Logger`
on retrieval would need to allocate one.

The downside is that switching back and forth needs more allocations. Because
logr is the API that is already in use by different packages, in particular
Kubernetes, the recommendation is to use the `logr.Logger` API in code which
uses contextual logging.

An alternative to adding values to a logger and storing that logger in the
context is to store the values in the context and to configure a logging
backend to extract those values when emitting log entries. This only works when
log calls are passed the context, which is not supported by the logr API.

With the slog API, it is possible, but not
required. https://github.com/veqryn/slog-context is a package for slog which
provides additional support code for this approach. It also contains wrappers
for the context functions in logr, so developers who prefer to not use the logr
APIs directly can use those instead and the resulting code will still be
interoperable with logr.

## FAQ

### Conceptual

#### Why structured logging?

- **Structured logs are more easily queryable**: Since you've got
  key-value pairs, it's much easier to query your structured logs for
  particular values by filtering on the contents of a particular key --
  think searching request logs for error codes, Kubernetes reconcilers for
  the name and namespace of the reconciled object, etc.

- **Structured logging makes it easier to have cross-referenceable logs**:
  Similarly to searchability, if you maintain conventions around your
  keys, it becomes easy to gather all log lines related to a particular
  concept.

- **Structured logs allow better dimensions of filtering**: if you have
  structure to your logs, you've got more precise control over how much
  information is logged -- you might choose in a particular configuration
  to log certain keys but not others, only log lines where a certain key
  matches a certain value, etc., instead of just having v-levels and names
  to key off of.

- **Structured logs better represent structured data**: sometimes, the
  data that you want to log is inherently structured (think tuple-link
  objects.)  Structured logs allow you to preserve that structure when
  outputting.

#### Why V-levels?

**V-levels give operators an easy way to control the chattiness of log
operations**.  V-levels provide a way for a given package to distinguish
the relative importance or verbosity of a given log message.  Then, if
a particular logger or package is logging too many messages, the user
of the package can simply change the v-levels for that library.

#### Why not named levels, like Info/Warning/Error?

Read [Dave Cheney's post][warning-makes-no-sense].  Then read [Differences
from Dave's ideas](#differences-from-daves-ideas).

#### Why not allow format strings, too?

**Format strings negate many of the benefits of structured logs**:

- They're not easily searchable without resorting to fuzzy searching,
  regular expressions, etc.

- They don't store structured data well, since contents are flattened into
  a string.

- They're not cross-referenceable.

- They don't compress easily, since the message is not constant.

(Unless you turn positional parameters into key-value pairs with numerical
keys, at which point you've gotten key-value logging with meaningless
keys.)

### Practical

#### Why key-value pairs, and not a map?

Key-value pairs are *much* easier to optimize, especially around
allocations.  Zap (a structured logger that inspired logr's interface) has
[performance measurements](https://github.com/uber-go/zap#performance)
that show this quite nicely.

While the interface ends up being a little less obvious, you get
potentially better performance, plus avoid making users type
`map[string]string{}` every time they want to log.

#### What if my V-levels differ between libraries?

That's fine.  Control your V-levels on a per-logger basis, and use the
`WithName` method to pass different loggers to different libraries.

Generally, you should take care to ensure that you have relatively
consistent V-levels within a given logger, however, as this makes deciding
on what verbosity of logs to request easier.

#### But I really want to use a format string!

That's not actually a question.  Assuming your question is "how do
I convert my mental model of logging with format strings to logging with
constant messages":

1. Figure out what the error actually is, as you'd write in a TL;DR style,
   and use that as a message.

2. For every place you'd write a format specifier, look to the word before
   it, and add that as a key value pair.

For instance, consider the following examples (all taken from spots in the
Kubernetes codebase):

- `klog.V(4).Infof("Client is returning errors: code %v, error %v",
  responseCode, err)` becomes `logger.Error(err, "client returned an
  error", "code", responseCode)`

- `klog.V(4).Infof("Got a Retry-After %ds response for attempt %d to %v",
  seconds, retries, url)` becomes `logger.V(4).Info("got a retry-after
  response when requesting url", "attempt", retries, "after
  seconds", seconds, "url", url)`

If you *really* must use a format string, use it in a key's value, and
call `fmt.Sprintf` yourself.  For instance: `log.Printf("unable to
reflect over type %T")` becomes `logger.Info("unable to reflect over
type", "type", fmt.Sprintf("%T"))`.  In general though, the cases where
this is necessary should be few and far between.

#### How do I choose my V-levels?

This is basically the only hard constraint: increase V-levels to denote
more verbose or more debug-y logs.

Otherwise, you can start out with `0` as "you always want to see this",
`1` as "common logging that you might *possibly* want to turn off", and
`10` as "I would like to performance-test your log collection stack."

Then gradually choose levels in between as you need them, working your way
down from 10 (for debug and trace style logs) and up from 1 (for chattier
info-type logs). For reference, slog pre-defines -4 for debug logs
(corresponds to 4 in logr), which matches what is
[recommended for Kubernetes](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md#what-method-to-use).

#### How do I choose my keys?

Keys are fairly flexible, and can hold more or less any string
value. For best compatibility with implementations and consistency
with existing code in other projects, there are a few conventions you
should consider.

- Make your keys human-readable.
- Constant keys are generally a good idea.
- Be consistent across your codebase.
- Keys should naturally match parts of the message string.
- Use lower case for simple keys and
  [lowerCamelCase](https://en.wiktionary.org/wiki/lowerCamelCase) for
  more complex ones. Kubernetes is one example of a project that has
  [adopted that
  convention](https://github.com/kubernetes/community/blob/HEAD/contributors/devel/sig-instrumentation/migration-to-structured-logging.md#name-arguments).

While key names are mostly unrestricted (and spaces are acceptable),
it's generally a good idea to stick to printable ascii characters, or at
least match the general character set of your log lines.

#### Why should keys be constant values?

The point of structured logging is to make later log processing easier.  Your
keys are, effectively, the schema of each log message.  If you use different
keys across instances of the same log line, you will make your structured logs
much harder to use.  `Sprintf()` is for values, not for keys!

#### Why is this not a pure interface?

The Logger type is implemented as a struct in order to allow the Go compiler to
optimize things like high-V `Info` logs that are not triggered.  Not all of
these implementations are implemented yet, but this structure was suggested as
a way to ensure they *can* be implemented.  All of the real work is behind the
`LogSink` interface.

[warning-makes-no-sense]: http://dave.cheney.net/2015/11/05/lets-talk-about-logging

---

### Overview (`vendor/github.com/go-logr/stdr/README.md`)

# Minimal Go logging using logr and Go's standard library

[](https://pkg.go.dev/github.com/go-logr/stdr)

This package implements the [logr interface](https://github.com/go-logr/logr)
in terms of Go's standard log package(https://pkg.go.dev/log).

---

### Overview (`vendor/github.com/google/s2a-go/README.md`)

# Secure Session Agent Client Libraries

The Secure Session Agent is a service that enables a workload to offload select
operations from the mTLS handshake and protects a workload's private key
material from exfiltration. Specifically, the workload asks the Secure Session
Agent for the TLS configuration to use during the handshake, to perform private
key operations, and to validate the peer certificate chain. The Secure Session
Agent's client libraries enable applications to communicate with the Secure
Session Agent during the TLS handshake, and to encrypt traffic to the peer
after the TLS handshake is complete.

This repository contains the source code for the Secure Session Agent's Go
client libraries, which allow gRPC and HTTP Go applications to use the Secure Session
Agent.

---

### Overview (`vendor/github.com/google/uuid/README.md`)

# uuid
The uuid package generates and inspects UUIDs based on
[RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122)
and DCE 1.1: Authentication and Security Services. 

This package is based on the github.com/pborman/uuid package (previously named
code.google.com/p/go-uuid).  It differs from these earlier packages in that
a UUID is a 16 byte array rather than a byte slice.  One loss due to this
change is the ability to represent an invalid UUID (vs a NIL UUID).

###### Install
```sh
go get github.com/google/uuid
```

###### Documentation 
[](https://pkg.go.dev/github.com/google/uuid)

Full `go doc` style documentation for the package can be viewed online without
installing this package by using the GoDoc site here: 
http://pkg.go.dev/github.com/google/uuid

---

### Overview (`vendor/github.com/gorilla/handlers/README.md`)

# gorilla/handlers


[](https://codecov.io/github/gorilla/handlers)
[](https://godoc.org/github.com/gorilla/handlers)
[](https://sourcegraph.com/github.com/gorilla/handlers?badge)

Package handlers is a collection of handlers (aka "HTTP middleware") for use
with Go's `net/http` package (or any framework supporting `http.Handler`), including:

* [**LoggingHandler**](https://godoc.org/github.com/gorilla/handlers#LoggingHandler) for logging HTTP requests in the Apache [Common Log
  Format](http://httpd.apache.org/docs/2.2/logs.html#common).
* [**CombinedLoggingHandler**](https://godoc.org/github.com/gorilla/handlers#CombinedLoggingHandler) for logging HTTP requests in the Apache [Combined Log
  Format](http://httpd.apache.org/docs/2.2/logs.html#combined) commonly used by
  both Apache and nginx.
* [**CompressHandler**](https://godoc.org/github.com/gorilla/handlers#CompressHandler) for gzipping responses.
* [**ContentTypeHandler**](https://godoc.org/github.com/gorilla/handlers#ContentTypeHandler) for validating requests against a list of accepted
  content types.
* [**MethodHandler**](https://godoc.org/github.com/gorilla/handlers#MethodHandler) for matching HTTP methods against handlers in a
  `map[string]http.Handler`
* [**ProxyHeaders**](https://godoc.org/github.com/gorilla/handlers#ProxyHeaders) for populating `r.RemoteAddr` and `r.URL.Scheme` based on the
  `X-Forwarded-For`, `X-Real-IP`, `X-Forwarded-Proto` and RFC7239 `Forwarded`
  headers when running a Go server behind a HTTP reverse proxy.
* [**CanonicalHost**](https://godoc.org/github.com/gorilla/handlers#CanonicalHost) for re-directing to the preferred host when handling multiple 
  domains (i.e. multiple CNAME aliases).
* [**RecoveryHandler**](https://godoc.org/github.com/gorilla/handlers#RecoveryHandler) for recovering from unexpected panics.

Other handlers are documented [on the Gorilla
website](https://www.gorillatoolkit.org/pkg/handlers).

## Example

A simple example using `handlers.LoggingHandler` and `handlers.CompressHandler`:

```go
import (
    "net/http"
    "github.com/gorilla/handlers"
)

func main() {
    r := http.NewServeMux()

    // Only log requests to our admin dashboard to stdout
    r.Handle("/admin", handlers.LoggingHandler(os.Stdout, http.HandlerFunc(ShowAdminDashboard)))
    r.HandleFunc("/", ShowIndex)

    // Wrap our server with our gzip handler to gzip compress all responses.
    http.ListenAndServe(":8000", handlers.CompressHandler(r))
}
```

## License

BSD licensed. See the included LICENSE file for details.

---

### Overview (`vendor/github.com/gorilla/mux/README.md`)

# gorilla/mux


[](https://codecov.io/github/gorilla/mux)
[](https://godoc.org/github.com/gorilla/mux)
[](https://sourcegraph.com/github.com/gorilla/mux?badge)




Package `gorilla/mux` implements a request router and dispatcher for matching incoming requests to
their respective handler.

The name mux stands for "HTTP request multiplexer". Like the standard `http.ServeMux`, `mux.Router` matches incoming requests against a list of registered routes and calls a handler for the route that matches the URL or other conditions. The main features are:

* It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`.
* Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers.
* URL hosts, paths and query values can have variables with an optional regular expression.
* Registered URLs can be built, or "reversed", which helps maintaining references to resources.
* Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching.

---

* [Install](#install)
* [Examples](#examples)
* [Matching Routes](#matching-routes)
* [Static Files](#static-files)
* [Serving Single Page Applications](#serving-single-page-applications) (e.g. React, Vue, Ember.js, etc.)
* [Registered URLs](#registered-urls)
* [Walking Routes](#walking-routes)
* [Graceful Shutdown](#graceful-shutdown)
* [Middleware](#middleware)
* [Handling CORS Requests](#handling-cors-requests)
* [Testing Handlers](#testing-handlers)
* [Full Example](#full-example)

---

## Install

With a [correctly configured](https://golang.org/doc/install#testing) Go toolchain:

```sh
go get -u github.com/gorilla/mux
```

## Examples

Let's start registering a couple of URL paths and handlers:

```go
func main() {
    r := mux.NewRouter()
    r.HandleFunc("/", HomeHandler)
    r.HandleFunc("/products", ProductsHandler)
    r.HandleFunc("/articles", ArticlesHandler)
    http.Handle("/", r)
}
```

Here we register three routes mapping URL paths to handlers. This is equivalent to how `http.HandleFunc()` works: if an incoming request URL matches one of the paths, the corresponding handler is called passing (`http.ResponseWriter`, `*http.Request`) as parameters.

Paths can have variables. They are defined using the format `{name}` or `{name:pattern}`. If a regular expression pattern is not defined, the matched variable will be anything until the next slash. For example:

```go
r := mux.NewRouter()
r.HandleFunc("/products/{key}", ProductHandler)
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
```

The names are used to create a map of route variables which can be retrieved calling `mux.Vars()`:

```go
func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, "Category: %v\n", vars["category"])
}
```

And this is all you need to know about the basic usage. More advanced options are explained below.

### Matching Routes

Routes can also be restricted to a domain or subdomain. Just define a host pattern to be matched. They can also have variables:

```go
r := mux.NewRouter()
// Only matches if domain is "www.example.com".
r.Host("www.example.com")
// Matches a dynamic subdomain.
r.Host("{subdomain:[a-z]+}.example.com")
```

There are several other matchers that can be added. To match path prefixes:

```go
r.PathPrefix("/products/")
```

...or HTTP methods:

```go
r.Methods("GET", "POST")
```

...or URL schemes:

```go
r.Schemes("https")
```

...or header values:

```go
r.Headers("X-Requested-With", "XMLHttpRequest")
```

...or query values:

```go
r.Queries("key", "value")
```

...or to use a custom matcher function:

```go
r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
    return r.ProtoMajor == 0
})
```

...and finally, it is possible to combine several matchers in a single route:

```go
r.HandleFunc("/products", ProductsHandler).
  Host("www.example.com").
  Methods("GET").
  Schemes("http")
```

Routes are tested in the order they were added to the router. If two routes match, the first one wins:

```go
r := mux.NewRouter()
r.HandleFunc("/specific", specificHandler)
r.PathPrefix("/").Handler(catchAllHandler)
```

Setting the same matching conditions again and again can be boring, so we have a way to group several routes that share the same requirements. We call it "subrouting".

For example, let's say we have several URLs that should only match when the host is `www.example.com`. Create a route for that host and get a "subrouter" from it:

```go
r := mux.NewRouter()
s := r.Host("www.example.com").Subrouter()
```

Then register routes in the subrouter:

```go
s.HandleFunc("/products/", ProductsHandler)
s.HandleFunc("/products/{key}", ProductHandler)
s.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
```

The three URL paths we registered above will only be tested if the domain is `www.example.com`, because the subrouter is tested first. This is not only convenient, but also optimizes request matching. You can create subrouters combining any attribute matchers accepted by a route.

Subrouters can be used to create domain or path "namespaces": you define subrouters in a central place and then parts of the app can register its paths relatively to a given subrouter.

There's one more thing about subroutes. When a subrouter has a path prefix, the inner routes use it as base for their paths:

```go
r := mux.NewRouter()
s := r.PathPrefix("/products").Subrouter()
// "/products/"
s.HandleFunc("/", ProductsHandler)
// "/products/{key}/"
s.HandleFunc("/{key}/", ProductHandler)
// "/products/{key}/details"
s.HandleFunc("/{key}/details", ProductDetailsHandler)
```


### Static Files

Note that the path provided to `PathPrefix()` represents a "wildcard": calling
`PathPrefix("/static/").Handler(...)` means that the handler will be passed any
request that matches "/static/\*". This makes it easy to serve static files with mux:

```go
func main() {
    var dir string

    flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
    flag.Parse()
    r := mux.NewRouter()

    // This will serve files under http://localhost:8000/static/<filename>
    r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))

    srv := &http.Server{
        Handler:      r,
        Addr:         "127.0.0.1:8000",
        // Good practice: enforce timeouts for servers you create!
        WriteTimeout: 15 * time.Second,
        ReadTimeout:  15 * time.Second,
    }

    log.Fatal(srv.ListenAndServe())
}
```

### Serving Single Page Applications

Most of the time it makes sense to serve your SPA on a separate web server from your API,
but sometimes it's desirable to serve them both from one place. It's possible to write a simple
handler for serving your SPA (for use with React Router's [BrowserRouter](https://reacttraining.com/react-router/web/api/BrowserRouter) for example), and leverage
mux's powerful routing for your API endpoints.

```
/* Detailed source-code truncated for AI context efficiency. */
```

### Registered URLs

Now let's see how to build registered URLs.

Routes can be named. All routes that define a name can have their URLs built, or "reversed". We define a name calling `Name()` on a route. For example:

```go
r := mux.NewRouter()
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
  Name("article")
```

To build a URL, get the route and call the `URL()` method, passing a sequence of key/value pairs for the route variables. For the previous route, we would do:

```go
url, err := r.Get("article").URL("category", "technology", "id", "42")
```

...and the result will be a `url.URL` with the following path:

```
"/articles/technology/42"
```

This also works for host and query value variables:

```go
r := mux.NewRouter()
r.Host("{subdomain}.example.com").
  Path("/articles/{category}/{id:[0-9]+}").
  Queries("filter", "{filter}").
  HandlerFunc(ArticleHandler).
  Name("article")

// url.String() will be "http://news.example.com/articles/technology/42?filter=gorilla"
url, err := r.Get("article").URL("subdomain", "news",
                                 "category", "technology",
                                 "id", "42",
                                 "filter", "gorilla")
```

All variables defined in the route are required, and their values must conform to the corresponding patterns. These requirements guarantee that a generated URL will always match a registered route -- the only exception is for explicitly defined "build-only" routes which never match.

Regex support also exists for matching Headers within a route. For example, we could do:

```go
r.HeadersRegexp("Content-Type", "application/(text|json)")
```

...and the route will match both requests with a Content-Type of `application/json` as well as `application/text`

There's also a way to build only the URL host or path for a route: use the methods `URLHost()` or `URLPath()` instead. For the previous route, we would do:

```go
// "http://news.example.com/"
host, err := r.Get("article").URLHost("subdomain", "news")

// "/articles/technology/42"
path, err := r.Get("article").URLPath("category", "technology", "id", "42")
```

And if you use subrouters, host and path defined separately can be built as well:

```go
r := mux.NewRouter()
s := r.Host("{subdomain}.example.com").Subrouter()
s.Path("/articles/{category}/{id:[0-9]+}").
  HandlerFunc(ArticleHandler).
  Name("article")

// "http://news.example.com/articles/technology/42"
url, err := r.Get("article").URL("subdomain", "news",
                                 "category", "technology",
                                 "id", "42")
```

To find all the required variables for a given route when calling `URL()`, the method `GetVarNames()` is available:
```go
r := mux.NewRouter()
r.Host("{domain}").
    Path("/{group}/{item_id}").
    Queries("some_data1", "{some_data1}").
    Queries("some_data2", "{some_data2}").
    Name("article")

// Will print [domain group item_id some_data1 some_data2] <nil>
fmt.Println(r.Get("article").GetVarNames())

```
### Walking Routes

The `Walk` function on `mux.Router` can be used to visit all of the routes that are registered on a router. For example,
the following prints all of the registered routes:

```go
package main

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/gorilla/mux"
)

func handler(w http.ResponseWriter, r *http.Request) {
	return
}

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/", handler)
	r.HandleFunc("/products", handler).Methods("POST")
	r.HandleFunc("/articles", handler).Methods("GET")
	r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
	r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
	err := r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
		pathTemplate, err := route.GetPathTemplate()
		if err == nil {
			fmt.Println("ROUTE:", pathTemplate)
		}
		pathRegexp, err := route.GetPathRegexp()
		if err == nil {
			fmt.Println("Path regexp:", pathRegexp)
		}
		queriesTemplates, err := route.GetQueriesTemplates()
		if err == nil {
			fmt.Println("Queries templates:", strings.Join(queriesTemplates, ","))
		}
		queriesRegexps, err := route.GetQueriesRegexp()
		if err == nil {
			fmt.Println("Queries regexps:", strings.Join(queriesRegexps, ","))
		}
		methods, err := route.GetMethods()
		if err == nil {
			fmt.Println("Methods:", strings.Join(methods, ","))
		}
		fmt.Println()
		return nil
	})

	if err != nil {
		fmt.Println(err)
	}

	http.Handle("/", r)
}
```

### Graceful Shutdown

Go 1.8 introduced the ability to [gracefully shutdown](https://golang.org/doc/go1.8#http_shutdown) a `*http.Server`. Here's how to do that alongside `mux`:

```
/* Detailed source-code truncated for AI context efficiency. */
```

### Middleware

Mux supports the addition of middlewares to a [Router](https://godoc.org/github.com/gorilla/mux#Router), which are executed in the order they are added if a match is found, including its subrouters.
Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or `ResponseWriter` hijacking.

Mux middlewares are defined using the de facto standard type:

```go
type MiddlewareFunc func(http.Handler) http.Handler
```

Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc. This takes advantage of closures being able access variables from the context where they are created, while retaining the signature enforced by the receivers.

A very basic middleware which logs the URI of the request being handled could be written as:

```go
func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Do stuff here
        log.Println(r.RequestURI)
        // Call the next handler, which can be another middleware in the chain, or the final handler.
        next.ServeHTTP(w, r)
    })
}
```

Middlewares can be added to a router using `Router.Use()`:

```go
r := mux.NewRouter()
r.HandleFunc("/", handler)
r.Use(loggingMiddleware)
```

A more complex authentication middleware, which maps session token to users, could be written as:

```go
// Define our struct
type authenticationMiddleware struct {
	tokenUsers map[string]string
}

// Initialize it somewhere
func (amw *authenticationMiddleware) Populate() {
	amw.tokenUsers["00000000"] = "user0"
	amw.tokenUsers["aaaaaaaa"] = "userA"
	amw.tokenUsers["05f717e5"] = "randomUser"
	amw.tokenUsers["deadbeef"] = "user0"
}

// Middleware function, which will be called for each request
func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("X-Session-Token")

        if user, found := amw.tokenUsers[token]; found {
        	// We found the token in our map
        	log.Printf("Authenticated user %s\n", user)
        	// Pass down the request to the next middleware (or final handler)
        	next.ServeHTTP(w, r)
        } else {
        	// Write an error and stop the handler chain
        	http.Error(w, "Forbidden", http.StatusForbidden)
        }
    })
}
```

```go
r := mux.NewRouter()
r.HandleFunc("/", handler)

amw := authenticationMiddleware{tokenUsers: make(map[string]string)}
amw.Populate()

r.Use(amw.Middleware)
```

Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares _should_ write to `ResponseWriter` if they _are_ going to terminate the request, and they _should not_ write to `ResponseWriter` if they _are not_ going to terminate it.

### Handling CORS Requests

[CORSMethodMiddleware](https://godoc.org/github.com/gorilla/mux#CORSMethodMiddleware) intends to make it easier to strictly set the `Access-Control-Allow-Methods` response header.

* You will still need to use your own CORS handler to set the other CORS headers such as `Access-Control-Allow-Origin`
* The middleware will set the `Access-Control-Allow-Methods` header to all the method matchers (e.g. `r.Methods(http.MethodGet, http.MethodPut, http.MethodOptions)` -> `Access-Control-Allow-Methods: GET,PUT,OPTIONS`) on a route
* If you do not specify any methods, then:
> _Important_: there must be an `OPTIONS` method matcher for the middleware to set the headers.

Here is an example of using `CORSMethodMiddleware` along with a custom `OPTIONS` handler to set all the required CORS headers:

```go
package main

import (
	"net/http"
	"github.com/gorilla/mux"
)

func main() {
    r := mux.NewRouter()

    // IMPORTANT: you must specify an OPTIONS method matcher for the middleware to set CORS headers
    r.HandleFunc("/foo", fooHandler).Methods(http.MethodGet, http.MethodPut, http.MethodPatch, http.MethodOptions)
    r.Use(mux.CORSMethodMiddleware(r))
    
    http.ListenAndServe(":8080", r)
}

func fooHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    if r.Method == http.MethodOptions {
        return
    }

    w.Write([]byte("foo"))
}
```

And an request to `/foo` using something like:

```bash
curl localhost:8080/foo -v
```

Would look like:

```bash
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /foo HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.59.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Access-Control-Allow-Methods: GET,PUT,PATCH,OPTIONS
< Access-Control-Allow-Origin: *
< Date: Fri, 28 Jun 2019 20:13:30 GMT
< Content-Length: 3
< Content-Type: text/plain; charset=utf-8
< 
* Connection #0 to host localhost left intact
foo
```

### Testing Handlers

Testing handlers in a Go web application is straightforward, and _mux_ doesn't complicate this any further. Given two files: `endpoints.go` and `endpoints_test.go`, here's how we'd test an application using _mux_.

First, our simple HTTP handler:

```go
// endpoints.go
package main

func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
    // A very simple health check.
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)

    // In the future we could report back on the status of our DB, or our cache
    // (e.g. Redis) by performing a simple PING, and include them in the response.
    io.WriteString(w, `{"alive": true}`)
}

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/health", HealthCheckHandler)

    log.Fatal(http.ListenAndServe("localhost:8080", r))
}
```

Our test code:

```go
// endpoints_test.go
package main

import (
    "net/http"
    "net/http/httptest"
    "testing"
)

func TestHealthCheckHandler(t *testing.T) {
    // Create a request to pass to our handler. We don't have any query parameters for now, so we'll
    // pass 'nil' as the third parameter.
    req, err := http.NewRequest("GET", "/health", nil)
    if err != nil {
        t.Fatal(err)
    }

    // We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.
    rr := httptest.NewRecorder()
    handler := http.HandlerFunc(HealthCheckHandler)

    // Our handlers satisfy http.Handler, so we can call their ServeHTTP method
    // directly and pass in our Request and ResponseRecorder.
    handler.ServeHTTP(rr, req)

    // Check the status code is what we expect.
    if status := rr.Code; status != http.StatusOK {
        t.Errorf("handler returned wrong status code: got %v want %v",
            status, http.StatusOK)
    }

    // Check the response body is what we expect.
    expected := `{"alive": true}`
    if rr.Body.String() != expected {
        t.Errorf("handler returned unexpected body: got %v want %v",
            rr.Body.String(), expected)
    }
}
```

In the case that our routes have [variables](#examples), we can pass those in the request. We could write
[table-driven tests](https://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go) to test multiple
possible route variables as needed.

```go
// endpoints.go
func main() {
    r := mux.NewRouter()
    // A route with a route variable:
    r.HandleFunc("/metrics/{type}", MetricsHandler)

    log.Fatal(http.ListenAndServe("localhost:8080", r))
}
```

Our test file, with a table-driven test of `routeVariables`:

```go
// endpoints_test.go
func TestMetricsHandler(t *testing.T) {
    tt := []struct{
        routeVariable string
        shouldPass bool
    }{
        {"goroutines", true},
        {"heap", true},
        {"counters", true},
        {"queries", true},
        {"adhadaeqm3k", false},
    }

    for _, tc := range tt {
        path := fmt.Sprintf("/metrics/%s", tc.routeVariable)
        req, err := http.NewRequest("GET", path, nil)
        if err != nil {
            t.Fatal(err)
        }

        rr := httptest.NewRecorder()
	
	// To add the vars to the context, 
	// we need to create a router through which we can pass the request.
	router := mux.NewRouter()
        router.HandleFunc("/metrics/{type}", MetricsHandler)
        router.ServeHTTP(rr, req)

        // In this case, our MetricsHandler returns a non-200 response
        // for a route variable it doesn't know about.
        if rr.Code == http.StatusOK && !tc.shouldPass {
            t.Errorf("handler should have failed on routeVariable %s: got %v want %v",
                tc.routeVariable, rr.Code, http.StatusOK)
        }
    }
}
```

## Full Example

Here's a complete, runnable example of a small `mux` based server:

```go
package main

import (
    "net/http"
    "log"
    "github.com/gorilla/mux"
)

func YourHandler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Gorilla!\n"))
}

func main() {
    r := mux.NewRouter()
    // Routes consist of a path and a handler function.
    r.HandleFunc("/", YourHandler)

    // Bind to a port and pass our router in
    log.Fatal(http.ListenAndServe(":8000", r))
}
```

## License

BSD licensed. See the LICENSE file for details.

---

### Overview (`vendor/github.com/inconshreveable/mousetrap/README.md`)

# mousetrap

mousetrap is a tiny library that answers a single question.

On a Windows machine, was the process invoked by someone double clicking on
the executable file while browsing in explorer?

### Motivation

Windows developers unfamiliar with command line tools will often "double-click"
the executable for a tool. Because most CLI tools print the help and then exit
when invoked without arguments, this is often very frustrating for those users.

mousetrap provides a way to detect these invocations so that you can provide
more helpful behavior and instructions on how to run the CLI tool. To see what
this looks like, both from an organizational and a technical perspective, see
https://inconshreveable.com/09-09-2014/sweat-the-small-stuff/

### The interface

The library exposes a single interface:

    func StartedByExplorer() (bool)

---

### Overview (`vendor/github.com/jmespath/go-jmespath/README.md`)

# go-jmespath - A JMESPath implementation in Go

[](https://travis-ci.org/jmespath/go-jmespath)



go-jmespath is a GO implementation of JMESPath,
which is a query language for JSON.  It will take a JSON
document and transform it into another JSON document
through a JMESPath expression.

Using go-jmespath is really easy.  There's a single function
you use, `jmespath.search`:


```go
> import "github.com/jmespath/go-jmespath"
>
> var jsondata = []byte(`{"foo": {"bar": {"baz": [0, 1, 2, 3, 4]}}}`) // your data
> var data interface{}
> err := json.Unmarshal(jsondata, &data)
> result, err := jmespath.Search("foo.bar.baz[2]", data)
result = 2
```

In the example we gave the ``search`` function input data of
`{"foo": {"bar": {"baz": [0, 1, 2, 3, 4]}}}` as well as the JMESPath
expression `foo.bar.baz[2]`, and the `search` function evaluated
the expression against the input data to produce the result ``2``.

The JMESPath language can do a lot more than select an element
from a list.  Here are a few more examples:

```go
> var jsondata = []byte(`{"foo": {"bar": {"baz": [0, 1, 2, 3, 4]}}}`) // your data
> var data interface{}
> err := json.Unmarshal(jsondata, &data)
> result, err := jmespath.search("foo.bar", data)
result = { "baz": [ 0, 1, 2, 3, 4 ] }


> var jsondata  = []byte(`{"foo": [{"first": "a", "last": "b"},
                           {"first": "c", "last": "d"}]}`) // your data
> var data interface{}
> err := json.Unmarshal(jsondata, &data)
> result, err := jmespath.search({"foo[*].first", data)
result [ 'a', 'c' ]


> var jsondata = []byte(`{"foo": [{"age": 20}, {"age": 25},
                           {"age": 30}, {"age": 35},
                           {"age": 40}]}`) // your data
> var data interface{}
> err := json.Unmarshal(jsondata, &data)
> result, err := jmespath.search("foo[?age > `30`]")
result = [ { age: 35 }, { age: 40 } ]
```

You can also pre-compile your query. This is usefull if 
you are going to run multiple searches with it:

```go
	> var jsondata = []byte(`{"foo": "bar"}`)
	> var data interface{}
    > err := json.Unmarshal(jsondata, &data)
	> precompiled, err := Compile("foo")
	> if err != nil{
    >   // ... handle the error
    > }
    > result, err := precompiled.Search(data)
	result = "bar"
```

## More Resources

The example above only show a small amount of what
a JMESPath expression can do.  If you want to take a
tour of the language, the *best* place to go is the
[JMESPath Tutorial](http://jmespath.org/tutorial.html).

One of the best things about JMESPath is that it is
implemented in many different programming languages including
python, ruby, php, lua, etc.  To see a complete list of libraries,
check out the [JMESPath libraries page](http://jmespath.org/libraries.html).

And finally, the full JMESPath specification can be found
on the [JMESPath site](http://jmespath.org/specification.html).

---

### Overview (`vendor/github.com/klauspost/compress/README.md`)

# compress

This package provides various compression algorithms.

* [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and decompression in pure Go.
* [S2](https://github.com/klauspost/compress/tree/master/s2#s2-compression) is a high performance replacement for Snappy.
* Optimized [deflate](https://godoc.org/github.com/klauspost/compress/flate) packages which can be used as a dropin replacement for [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip) and [zlib](https://godoc.org/github.com/klauspost/compress/zlib).
* [snappy](https://github.com/klauspost/compress/tree/master/snappy) is a drop-in replacement for `github.com/golang/snappy` offering better compression and concurrent streams.
* [huff0](https://github.com/klauspost/compress/tree/master/huff0) and [FSE](https://github.com/klauspost/compress/tree/master/fse) implementations for raw entropy encoding.
* [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp) Provides client and server wrappers for handling gzipped/zstd HTTP requests efficiently.
* [pgzip](https://github.com/klauspost/pgzip) is a separate package that provides a very fast parallel gzip implementation.

[](https://pkg.go.dev/github.com/klauspost/compress?tab=subdirectories)
[](https://github.com/klauspost/compress/actions/workflows/go.yml)
[](https://sourcegraph.com/github.com/klauspost/compress?badge)

# package usage

Use `go get github.com/klauspost/compress@latest` to add it to your project.

This package will support the current Go version and 2 versions back.

* Use the `nounsafe` tag to disable all use of the "unsafe" package.
* Use the `noasm` tag to disable all assembly across packages.

Use the links above for more information on each.

# changelog
* Jan 16th, 2026 [1.18.3](https://github.com/klauspost/compress/releases/tag/v1.18.3)
	* Downstream CVE-2025-61728. See [golang/go#77102](https://github.com/golang/go/issues/77102).

* Dec 1st, 2025 - [1.18.2](https://github.com/klauspost/compress/releases/tag/v1.18.2)
	* flate: Fix invalid encoding on level 9 with single value input in https://github.com/klauspost/compress/pull/1115
	* flate: reduce stateless allocations by @RXamzin in https://github.com/klauspost/compress/pull/1106

* Oct 20, 2025 - [1.18.1](https://github.com/klauspost/compress/releases/tag/v1.18.1) - RETRACTED
  * zstd: Add simple zstd EncodeTo/DecodeTo functions  https://github.com/klauspost/compress/pull/1079
  * zstd: Fix incorrect buffer size in dictionary encodes https://github.com/klauspost/compress/pull/1059
  * s2: check for cap, not len of buffer in EncodeBetter/Best by @vdarulis in https://github.com/klauspost/compress/pull/1080
  * zlib: Avoiding extra allocation in zlib.reader.Reset by @travelpolicy in https://github.com/klauspost/compress/pull/1086
  * gzhttp: remove redundant err check in zstdReader by @ryanfowler in https://github.com/klauspost/compress/pull/1090
  * flate: Faster load+store https://github.com/klauspost/compress/pull/1104
  * flate: Simplify matchlen https://github.com/klauspost/compress/pull/1101
  * flate: Use exact sizes for huffman tables https://github.com/klauspost/compress/pull/1103

* Feb 19th, 2025 - [1.18.0](https://github.com/klauspost/compress/releases/tag/v1.18.0)
  * Add unsafe little endian loaders https://github.com/klauspost/compress/pull/1036
  * fix: check `r.err != nil` but return a nil value error `err` by @alingse in https://github.com/klauspost/compress/pull/1028
  * flate: Simplify L4-6 loading https://github.com/klauspost/compress/pull/1043
  * flate: Simplify matchlen (remove asm) https://github.com/klauspost/compress/pull/1045
  * s2: Improve small block compression speed w/o asm https://github.com/klauspost/compress/pull/1048
  * flate: Fix matchlen L5+L6 https://github.com/klauspost/compress/pull/1049
  * flate: Cleanup & reduce casts https://github.com/klauspost/compress/pull/1050

<details>
	<summary>See changes to v1.17.x</summary>

* Oct 11th, 2024 - [1.17.11](https://github.com/klauspost/compress/releases/tag/v1.17.11)
  * zstd: Fix extra CRC written with multiple Close calls https://github.com/klauspost/compress/pull/1017
  * s2: Don't use stack for index tables https://github.com/klauspost/compress/pull/1014
  * gzhttp: No content-type on no body response code by @juliens in https://github.com/klauspost/compress/pull/1011
  * gzhttp: Do not set the content-type when response has no body by @kevinpollet in https://github.com/klauspost/compress/pull/1013

* Sep 23rd, 2024 - [1.17.10](https://github.com/klauspost/compress/releases/tag/v1.17.10)
	* gzhttp: Add TransportAlwaysDecompress option. https://github.com/klauspost/compress/pull/978
	* gzhttp: Add supported decompress request body by @mirecl in https://github.com/klauspost/compress/pull/1002
	* s2: Add EncodeBuffer buffer recycling callback https://github.com/klauspost/compress/pull/982
	* zstd: Improve memory usage on small streaming encodes https://github.com/klauspost/compress/pull/1007
	* flate: read data written with partial flush by @vajexal in https://github.com/klauspost/compress/pull/996

* Jun 12th, 2024 - [1.17.9](https://github.com/klauspost/compress/releases/tag/v1.17.9)
	* s2: Reduce ReadFrom temporary allocations https://github.com/klauspost/compress/pull/949
	* flate, zstd: Shave some bytes off amd64 matchLen by @greatroar in https://github.com/klauspost/compress/pull/963
	* Upgrade zip/zlib to 1.22.4 upstream https://github.com/klauspost/compress/pull/970 https://github.com/klauspost/compress/pull/971
	* zstd: BuildDict fails with RLE table https://github.com/klauspost/compress/pull/951

* Apr 9th, 2024 - [1.17.8](https://github.com/klauspost/compress/releases/tag/v1.17.8)
	* zstd: Reject blocks where reserved values are not 0 https://github.com/klauspost/compress/pull/885
	* zstd: Add RLE detection+encoding https://github.com/klauspost/compress/pull/938

* Feb 21st, 2024 - [1.17.7](https://github.com/klauspost/compress/releases/tag/v1.17.7)
	* s2: Add AsyncFlush method: Complete the block without flushing by @Jille in https://github.com/klauspost/compress/pull/927
	* s2: Fix literal+repeat exceeds dst crash https://github.com/klauspost/compress/pull/930
  
* Feb 5th, 2024 - [1.17.6](https://github.com/klauspost/compress/releases/tag/v1.17.6)
	* zstd: Fix incorrect repeat coding in best mode https://github.com/klauspost/compress/pull/923
	* s2: Fix DecodeConcurrent deadlock on errors https://github.com/klauspost/compress/pull/925
  
* Jan 26th, 2024 - [v1.17.5](https://github.com/klauspost/compress/releases/tag/v1.17.5)
	* flate: Fix reset with dictionary on custom window encodes https://github.com/klauspost/compress/pull/912
	* zstd: Add Frame header encoding and stripping https://github.com/klauspost/compress/pull/908
	* zstd: Limit better/best default window to 8MB https://github.com/klauspost/compress/pull/913
	* zstd: Speed improvements by @greatroar in https://github.com/klauspost/compress/pull/896 https://github.com/klauspost/compress/pull/910
	* s2: Fix callbacks for skippable blocks and disallow 0xfe (Padding) by @Jille in https://github.com/klauspost/compress/pull/916 https://github.com/klauspost/compress/pull/917
https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/compress/pull/918

* Dec 1st, 2023 - [v1.17.4](https://github.com/klauspost/compress/releases/tag/v1.17.4)
	* huff0: Speed up symbol counting by @greatroar in https://github.com/klauspost/compress/pull/887
	* huff0: Remove byteReader by @greatroar in https://github.com/klauspost/compress/pull/886
	* gzhttp: Allow overriding decompression on transport https://github.com/klauspost/compress/pull/892
	* gzhttp: Clamp compression level https://github.com/klauspost/compress/pull/890
	* gzip: Error out if reserved bits are set https://github.com/klauspost/compress/pull/891

* Nov 15th, 2023 - [v1.17.3](https://github.com/klauspost/compress/releases/tag/v1.17.3)
	* fse: Fix max header size https://github.com/klauspost/compress/pull/881
	* zstd: Improve better/best compression https://github.com/klauspost/compress/pull/877
	* gzhttp: Fix missing content type on Close https://github.com/klauspost/compress/pull/883

* Oct 22nd, 2023 - [v1.17.2](https://github.com/klauspost/compress/releases/tag/v1.17.2)
	* zstd: Fix rare *CORRUPTION* output in "best" mode. See https://github.com/klauspost/compress/pull/876

* Oct 14th, 2023 - [v1.17.1](https://github.com/klauspost/compress/releases/tag/v1.17.1)
	* s2: Fix S2 "best" dictionary wrong encoding https://github.com/klauspost/compress/pull/871
	* flate: Reduce allocations in decompressor and minor code improvements by @fakefloordiv in https://github.com/klauspost/compress/pull/869
	* s2: Fix EstimateBlockSize on 6&7 length input https://github.com/klauspost/compress/pull/867

* Sept 19th, 2023 - [v1.17.0](https://github.com/klauspost/compress/releases/tag/v1.17.0)
	* Add experimental dictionary builder  https://github.com/klauspost/compress/pull/853
	* Add xerial snappy read/writer https://github.com/klauspost/compress/pull/838
	* flate: Add limited window compression https://github.com/klauspost/compress/pull/843
	* s2: Do 2 overlapping match checks https://github.com/klauspost/compress/pull/839
	* flate: Add amd64 assembly matchlen https://github.com/klauspost/compress/pull/837
	* gzip: Copy bufio.Reader on Reset by @thatguystone in https://github.com/klauspost/compress/pull/860
   
</details>
<details>
	<summary>See changes to v1.16.x</summary>

   
* July 1st, 2023 - [v1.16.7](https://github.com/klauspost/compress/releases/tag/v1.16.7)
	* zstd: Fix default level first dictionary encode https://github.com/klauspost/compress/pull/829
	* s2: add GetBufferCapacity() method by @GiedriusS in https://github.com/klauspost/compress/pull/832

* June 13, 2023 - [v1.16.6](https://github.com/klauspost/compress/releases/tag/v1.16.6)
	* zstd: correctly ignore WithEncoderPadding(1) by @ianlancetaylor in https://github.com/klauspost/compress/pull/806
	* zstd: Add amd64 match length assembly https://github.com/klauspost/compress/pull/824
	* gzhttp: Handle informational headers by @rtribotte in https://github.com/klauspost/compress/pull/815
	* s2: Improve Better compression slightly https://github.com/klauspost/compress/pull/663

* Apr 16, 2023 - [v1.16.5](https://github.com/klauspost/compress/releases/tag/v1.16.5)
	* zstd: readByte needs to use io.ReadFull by @jnoxon in https://github.com/klauspost/compress/pull/802
	* gzip: Fix WriterTo after initial read https://github.com/klauspost/compress/pull/804

* Apr 5, 2023 - [v1.16.4](https://github.com/klauspost/compress/releases/tag/v1.16.4)
	* zstd: Improve zstd best efficiency by @greatroar and @klauspost in https://github.com/klauspost/compress/pull/784
	* zstd: Respect WithAllLitEntropyCompression https://github.com/klauspost/compress/pull/792
	* zstd: Fix amd64 not always detecting corrupt data https://github.com/klauspost/compress/pull/785
	* zstd: Various minor improvements by @greatroar in https://github.com/klauspost/compress/pull/788 https://github.com/klauspost/compress/pull/794 https://github.com/klauspost/compress/pull/795
	* s2: Fix huge block overflow https://github.com/klauspost/compress/pull/779
	* s2: Allow CustomEncoder fallback https://github.com/klauspost/compress/pull/780
	* gzhttp: Support ResponseWriter Unwrap() in gzhttp handler by @jgimenez in https://github.com/klauspost/compress/pull/799

* Mar 13, 2023 - [v1.16.1](https://github.com/klauspost/compress/releases/tag/v1.16.1)
	* zstd: Speed up + improve best encoder by @greatroar in https://github.com/klauspost/compress/pull/776
	* gzhttp: Add optional [BREACH mitigation](https://github.com/klauspost/compress/tree/master/gzhttp#breach-mitigation). https://github.com/klauspost/compress/pull/762 https://github.com/klauspost/compress/pull/768 https://github.com/klauspost/compress/pull/769 https://github.com/klauspost/compress/pull/770 https://github.com/klauspost/compress/pull/767
	* s2: Add Intel LZ4s converter https://github.com/klauspost/compress/pull/766
	* zstd: Minor bug fixes https://github.com/klauspost/compress/pull/771 https://github.com/klauspost/compress/pull/772 https://github.com/klauspost/compress/pull/773
	* huff0: Speed up compress1xDo by @greatroar in https://github.com/klauspost/compress/pull/774

* Feb 26, 2023 - [v1.16.0](https://github.com/klauspost/compress/releases/tag/v1.16.0)
	* s2: Add [Dictionary](https://github.com/klauspost/compress/tree/master/s2#dictionaries) support.  https://github.com/klauspost/compress/pull/685
	* s2: Add Compression Size Estimate.  https://github.com/klauspost/compress/pull/752
	* s2: Add support for custom stream encoder. https://github.com/klauspost/compress/pull/755
	* s2: Add LZ4 block converter. https://github.com/klauspost/compress/pull/748
	* s2: Support io.ReaderAt in ReadSeeker. https://github.com/klauspost/compress/pull/747
	* s2c/s2sx: Use concurrent decoding. https://github.com/klauspost/compress/pull/746
</details>

<details>
	<summary>See changes to v1.15.x</summary>
	
* Jan 21st, 2023 (v1.15.15)
	* deflate: Improve level 7-9 https://github.com/klauspost/compress/pull/739
	* zstd: Add delta encoding support by @greatroar in https://github.com/klauspost/compress/pull/728
	* zstd: Various speed improvements by @greatroar https://github.com/klauspost/compress/pull/741 https://github.com/klauspost/compress/pull/734 https://github.com/klauspost/compress/pull/736 https://github.com/klauspost/compress/pull/744 https://github.com/klauspost/compress/pull/743 https://github.com/klauspost/compress/pull/745
	* gzhttp: Add SuffixETag() and DropETag() options to prevent ETag collisions on compressed responses by @willbicks in https://github.com/klauspost/compress/pull/740

* Jan 3rd, 2023 (v1.15.14)

	* flate: Improve speed in big stateless blocks https://github.com/klauspost/compress/pull/718
	* zstd: Minor speed tweaks by @greatroar in https://github.com/klauspost/compress/pull/716 https://github.com/klauspost/compress/pull/720
	* export NoGzipResponseWriter for custom ResponseWriter wrappers by @harshavardhana in https://github.com/klauspost/compress/pull/722
	* s2: Add example for indexing and existing stream https://github.com/klauspost/compress/pull/723

* Dec 11, 2022 (v1.15.13)
	* zstd: Add [MaxEncodedSize](https://pkg.go.dev/github.com/klauspost/compress@v1.15.13/zstd#Encoder.MaxEncodedSize) to encoder  https://github.com/klauspost/compress/pull/691
	* zstd: Various tweaks and improvements https://github.com/klauspost/compress/pull/693 https://github.com/klauspost/compress/pull/695 https://github.com/klauspost/compress/pull/696 https://github.com/klauspost/compress/pull/701 https://github.com/klauspost/compress/pull/702 https://github.com/klauspost/compress/pull/703 https://github.com/klauspost/compress/pull/704 https://github.com/klauspost/compress/pull/705 https://github.com/klauspost/compress/pull/706 https://github.com/klauspost/compress/pull/707 https://github.com/klauspost/compress/pull/708

* Oct 26, 2022 (v1.15.12)

	* zstd: Tweak decoder allocs. https://github.com/klauspost/compress/pull/680
	* gzhttp: Always delete `HeaderNoCompression` https://github.com/klauspost/compress/pull/683

* Sept 26, 2022 (v1.15.11)

	* flate: Improve level 1-3 compression  https://github.com/klauspost/compress/pull/678
	* zstd: Improve "best" compression by @nightwolfz in https://github.com/klauspost/compress/pull/677
	* zstd: Fix+reduce decompression allocations https://github.com/klauspost/compress/pull/668
	* zstd: Fix non-effective noescape tag https://github.com/klauspost/compress/pull/667

* Sept 16, 2022 (v1.15.10)

	* zstd: Add [WithDecodeAllCapLimit](https://pkg.go.dev/github.com/klauspost/compress@v1.15.10/zstd#WithDecodeAllCapLimit) https://github.com/klauspost/compress/pull/649
	* Add Go 1.19 - deprecate Go 1.16  https://github.com/klauspost/compress/pull/651
	* flate: Improve level 5+6 compression https://github.com/klauspost/compress/pull/656
	* zstd: Improve "better" compression  https://github.com/klauspost/compress/pull/657
	* s2: Improve "best" compression https://github.com/klauspost/compress/pull/658
	* s2: Improve "better" compression. https://github.com/klauspost/compress/pull/635
	* s2: Slightly faster non-assembly decompression https://github.com/klauspost/compress/pull/646
	* Use arrays for constant size copies https://github.com/klauspost/compress/pull/659

* July 21, 2022 (v1.15.9)

	* zstd: Fix decoder crash on amd64 (no BMI) on invalid input https://github.com/klauspost/compress/pull/645
	* zstd: Disable decoder extended memory copies (amd64) due to possible crashes https://github.com/klauspost/compress/pull/644
	* zstd: Allow single segments up to "max decoded size" https://github.com/klauspost/compress/pull/643

* July 13, 2022 (v1.15.8)

	* gzip: fix stack exhaustion bug in Reader.Read https://github.com/klauspost/compress/pull/641
	* s2: Add Index header trim/restore https://github.com/klauspost/compress/pull/638
	* zstd: Optimize seqdeq amd64 asm by @greatroar in https://github.com/klauspost/compress/pull/636
	* zstd: Improve decoder memcopy https://github.com/klauspost/compress/pull/637
	* huff0: Pass a single bitReader pointer to asm by @greatroar in https://github.com/klauspost/compress/pull/634
	* zstd: Branchless getBits for amd64 w/o BMI2 by @greatroar in https://github.com/klauspost/compress/pull/640
	* gzhttp: Remove header before writing https://github.com/klauspost/compress/pull/639

* June 29, 2022 (v1.15.7)

	* s2: Fix absolute forward seeks  https://github.com/klauspost/compress/pull/633
	* zip: Merge upstream  https://github.com/klauspost/compress/pull/631
	* zip: Re-add zip64 fix https://github.com/klauspost/compress/pull/624
	* zstd: translate fseDecoder.buildDtable into asm by @WojciechMula in https://github.com/klauspost/compress/pull/598
	* flate: Faster histograms  https://github.com/klauspost/compress/pull/620
	* deflate: Use compound hcode  https://github.com/klauspost/compress/pull/622

* June 3, 2022 (v1.15.6)
	* s2: Improve coding for long, close matches https://github.com/klauspost/compress/pull/613
	* s2c: Add Snappy/S2 stream recompression https://github.com/klauspost/compress/pull/611
	* zstd: Always use configured block size https://github.com/klauspost/compress/pull/605
	* zstd: Fix incorrect hash table placement for dict encoding in default https://github.com/klauspost/compress/pull/606
	* zstd: Apply default config to ZipDecompressor without options https://github.com/klauspost/compress/pull/608
	* gzhttp: Exclude more common archive formats https://github.com/klauspost/compress/pull/612
	* s2: Add ReaderIgnoreCRC https://github.com/klauspost/compress/pull/609
	* s2: Remove sanity load on index creation https://github.com/klauspost/compress/pull/607
	* snappy: Use dedicated function for scoring https://github.com/klauspost/compress/pull/614
	* s2c+s2d: Use official snappy framed extension https://github.com/klauspost/compress/pull/610

* May 25, 2022 (v1.15.5)
	* s2: Add concurrent stream decompression https://github.com/klauspost/compress/pull/602
	* s2: Fix final emit oob read crash on amd64 https://github.com/klauspost/compress/pull/601
	* huff0: asm implementation of Decompress1X by @WojciechMula https://github.com/klauspost/compress/pull/596
	* zstd: Use 1 less goroutine for stream decoding https://github.com/klauspost/compress/pull/588
	* zstd: Copy literal in 16 byte blocks when possible https://github.com/klauspost/compress/pull/592
	* zstd: Speed up when WithDecoderLowmem(false) https://github.com/klauspost/compress/pull/599
	* zstd: faster next state update in BMI2 version of decode by @WojciechMula in https://github.com/klauspost/compress/pull/593
	* huff0: Do not check max size when reading table. https://github.com/klauspost/compress/pull/586
	* flate: Inplace hashing for level 7-9 https://github.com/klauspost/compress/pull/590


* May 11, 2022 (v1.15.4)
	* huff0: decompress directly into output by @WojciechMula in [#577](https://github.com/klauspost/compress/pull/577)
	* inflate: Keep dict on stack [#581](https://github.com/klauspost/compress/pull/581)
	* zstd: Faster decoding memcopy in asm [#583](https://github.com/klauspost/compress/pull/583)
	* zstd: Fix ignored crc [#580](https://github.com/klauspost/compress/pull/580)

* May 5, 2022 (v1.15.3)
	* zstd: Allow to ignore checksum checking by @WojciechMula [#572](https://github.com/klauspost/compress/pull/572)
	* s2: Fix incorrect seek for io.SeekEnd in [#575](https://github.com/klauspost/compress/pull/575)

* Apr 26, 2022 (v1.15.2)
	* zstd: Add x86-64 assembly for decompression on streams and blocks. Contributed by [@WojciechMula](https://github.com/WojciechMula). Typically 2x faster.  [#528](https://github.com/klauspost/compress/pull/528) [#531](https://github.com/klauspost/compress/pull/531) [#545](https://github.com/klauspost/compress/pull/545) [#537](https://github.com/klauspost/compress/pull/537)
	* zstd: Add options to ZipDecompressor and fixes [#539](https://github.com/klauspost/compress/pull/539)
	* s2: Use sorted search for index [#555](https://github.com/klauspost/compress/pull/555)
	* Minimum version is Go 1.16, added CI test on 1.18.

* Mar 11, 2022 (v1.15.1)
	* huff0: Add x86 assembly of Decode4X by @WojciechMula in [#512](https://github.com/klauspost/compress/pull/512)
	* zstd: Reuse zip decoders in [#514](https://github.com/klauspost/compress/pull/514)
	* zstd: Detect extra block data and report as corrupted in [#520](https://github.com/klauspost/compress/pull/520)
	* zstd: Handle zero sized frame content size stricter in [#521](https://github.com/klauspost/compress/pull/521)
	* zstd: Add stricter block size checks in [#523](https://github.com/klauspost/compress/pull/523)

* Mar 3, 2022 (v1.15.0)
	* zstd: Refactor decoder [#498](https://github.com/klauspost/compress/pull/498)
	* zstd: Add stream encoding without goroutines [#505](https://github.com/klauspost/compress/pull/505)
	* huff0: Prevent single blocks exceeding 16 bits by @klauspost in[#507](https://github.com/klauspost/compress/pull/507)
	* flate: Inline literal emission [#509](https://github.com/klauspost/compress/pull/509)
	* gzhttp: Add zstd to transport [#400](https://github.com/klauspost/compress/pull/400)
	* gzhttp: Make content-type optional [#510](https://github.com/klauspost/compress/pull/510)

Both compression and decompression now supports "synchronous" stream operations. This means that whenever "concurrency" is set to 1, they will operate without spawning goroutines.

Stream decompression is now faster on asynchronous, since the goroutine allocation much more effectively splits the workload. On typical streams this will typically use 2 cores fully for decompression. When a stream has finished decoding no goroutines will be left over, so decoders can now safely be pooled and still be garbage collected.

While the release has been extensively tested, it is recommended to testing when upgrading.

</details>

<details>
	<summary>See changes to v1.14.x</summary>
	
* Feb 22, 2022 (v1.14.4)
	* flate: Fix rare huffman only (-2) corruption. [#503](https://github.com/klauspost/compress/pull/503)
	* zip: Update deprecated CreateHeaderRaw to correctly call CreateRaw by @saracen in [#502](https://github.com/klauspost/compress/pull/502)
	* zip: don't read data descriptor early by @saracen in [#501](https://github.com/klauspost/compress/pull/501)  #501
	* huff0: Use static decompression buffer up to 30% faster [#499](https://github.com/klauspost/compress/pull/499) [#500](https://github.com/klauspost/compress/pull/500)

* Feb 17, 2022 (v1.14.3)
	* flate: Improve fastest levels compression speed ~10% more throughput. [#482](https://github.com/klauspost/compress/pull/482) [#489](https://github.com/klauspost/compress/pull/489) [#490](https://github.com/klauspost/compress/pull/490) [#491](https://github.com/klauspost/compress/pull/491) [#494](https://github.com/klauspost/compress/pull/494)  [#478](https://github.com/klauspost/compress/pull/478)
	* flate: Faster decompression speed, ~5-10%. [#483](https://github.com/klauspost/compress/pull/483)
	* s2: Faster compression with Go v1.18 and amd64 microarch level 3+. [#484](https://github.com/klauspost/compress/pull/484) [#486](https://github.com/klauspost/compress/pull/486)

* Jan 25, 2022 (v1.14.2)
	* zstd: improve header decoder by @dsnet  [#476](https://github.com/klauspost/compress/pull/476)
	* zstd: Add bigger default blocks  [#469](https://github.com/klauspost/compress/pull/469)
	* zstd: Remove unused decompression buffer [#470](https://github.com/klauspost/compress/pull/470)
	* zstd: Fix logically dead code by @ningmingxiao [#472](https://github.com/klauspost/compress/pull/472)
	* flate: Improve level 7-9 [#471](https://github.com/klauspost/compress/pull/471) [#473](https://github.com/klauspost/compress/pull/473)
	* zstd: Add noasm tag for xxhash [#475](https://github.com/klauspost/compress/pull/475)

* Jan 11, 2022 (v1.14.1)
	* s2: Add stream index in [#462](https://github.com/klauspost/compress/pull/462)
	* flate: Speed and efficiency improvements in [#439](https://github.com/klauspost/compress/pull/439) [#461](https://github.com/klauspost/compress/pull/461) [#455](https://github.com/klauspost/compress/pull/455) [#452](https://github.com/klauspost/compress/pull/452) [#458](https://github.com/klauspost/compress/pull/458)
	* zstd: Performance improvement in [#420]( https://github.com/klauspost/compress/pull/420) [#456](https://github.com/klauspost/compress/pull/456) [#437](https://github.com/klauspost/compress/pull/437) [#467](https://github.com/klauspost/compress/pull/467) [#468](https://github.com/klauspost/compress/pull/468)
	* zstd: add arm64 xxhash assembly in [#464](https://github.com/klauspost/compress/pull/464)
	* Add garbled for binaries for s2 in [#445](https://github.com/klauspost/compress/pull/445)
</details>

<details>
	<summary>See changes to v1.13.x</summary>
	
* Aug 30, 2021 (v1.13.5)
	* gz/zlib/flate: Alias stdlib errors [#425](https://github.com/klauspost/compress/pull/425)
	* s2: Add block support to commandline tools [#413](https://github.com/klauspost/compress/pull/413)
	* zstd: pooledZipWriter should return Writers to the same pool [#426](https://github.com/klauspost/compress/pull/426)
	* Removed golang/snappy as external dependency for tests [#421](https://github.com/klauspost/compress/pull/421)

* Aug 12, 2021 (v1.13.4)
	* Add [snappy replacement package](https://github.com/klauspost/compress/tree/master/snappy).
	* zstd: Fix incorrect encoding in "best" mode [#415](https://github.com/klauspost/compress/pull/415)

* Aug 3, 2021 (v1.13.3) 
	* zstd: Improve Best compression [#404](https://github.com/klauspost/compress/pull/404)
	* zstd: Fix WriteTo error forwarding [#411](https://github.com/klauspost/compress/pull/411)
	* gzhttp: Return http.HandlerFunc instead of http.Handler. Unlikely breaking change. [#406](https://github.com/klauspost/compress/pull/406)
	* s2sx: Fix max size error [#399](https://github.com/klauspost/compress/pull/399)
	* zstd: Add optional stream content size on reset [#401](https://github.com/klauspost/compress/pull/401)
	* zstd: use SpeedBestCompression for level >= 10 [#410](https://github.com/klauspost/compress/pull/410)

* Jun 14, 2021 (v1.13.1)
	* s2: Add full Snappy output support  [#396](https://github.com/klauspost/compress/pull/396)
	* zstd: Add configurable [Decoder window](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithDecoderMaxWindow) size [#394](https://github.com/klauspost/compress/pull/394)
	* gzhttp: Add header to skip compression  [#389](https://github.com/klauspost/compress/pull/389)
	* s2: Improve speed with bigger output margin  [#395](https://github.com/klauspost/compress/pull/395)

* Jun 3, 2021 (v1.13.0)
	* Added [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp#gzip-handler) which allows wrapping HTTP servers and clients with GZIP compressors.
	* zstd: Detect short invalid signatures [#382](https://github.com/klauspost/compress/pull/382)
	* zstd: Spawn decoder goroutine only if needed. [#380](https://github.com/klauspost/compress/pull/380)
</details>


<details>
	<summary>See changes to v1.12.x</summary>
	
* May 25, 2021 (v1.12.3)
	* deflate: Better/faster Huffman encoding [#374](https://github.com/klauspost/compress/pull/374)
	* deflate: Allocate less for history. [#375](https://github.com/klauspost/compress/pull/375)
	* zstd: Forward read errors [#373](https://github.com/klauspost/compress/pull/373) 

* Apr 27, 2021 (v1.12.2)
	* zstd: Improve better/best compression [#360](https://github.com/klauspost/compress/pull/360) [#364](https://github.com/klauspost/compress/pull/364) [#365](https://github.com/klauspost/compress/pull/365)
	* zstd: Add helpers to compress/decompress zstd inside zip files [#363](https://github.com/klauspost/compress/pull/363)
	* deflate: Improve level 5+6 compression [#367](https://github.com/klauspost/compress/pull/367)
	* s2: Improve better/best compression [#358](https://github.com/klauspost/compress/pull/358) [#359](https://github.com/klauspost/compress/pull/358)
	* s2: Load after checking src limit on amd64. [#362](https://github.com/klauspost/compress/pull/362)
	* s2sx: Limit max executable size [#368](https://github.com/klauspost/compress/pull/368) 

* Apr 14, 2021 (v1.12.1)
	* snappy package removed. Upstream added as dependency.
	* s2: Better compression in "best" mode [#353](https://github.com/klauspost/compress/pull/353)
	* s2sx: Add stdin input and detect pre-compressed from signature [#352](https://github.com/klauspost/compress/pull/352)
	* s2c/s2d: Add http as possible input [#348](https://github.com/klauspost/compress/pull/348)
	* s2c/s2d/s2sx: Always truncate when writing files [#352](https://github.com/klauspost/compress/pull/352)
	* zstd: Reduce memory usage further when using [WithLowerEncoderMem](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithLowerEncoderMem) [#346](https://github.com/klauspost/compress/pull/346)
	* s2: Fix potential problem with amd64 assembly and profilers [#349](https://github.com/klauspost/compress/pull/349)
</details>

<details>
	<summary>See changes to v1.11.x</summary>
	
* Mar 26, 2021 (v1.11.13)
	* zstd: Big speedup on small dictionary encodes [#344](https://github.com/klauspost/compress/pull/344) [#345](https://github.com/klauspost/compress/pull/345)
	* zstd: Add [WithLowerEncoderMem](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithLowerEncoderMem) encoder option [#336](https://github.com/klauspost/compress/pull/336)
	* deflate: Improve entropy compression [#338](https://github.com/klauspost/compress/pull/338)
	* s2: Clean up and minor performance improvement in best [#341](https://github.com/klauspost/compress/pull/341)

* Mar 5, 2021 (v1.11.12)
	* s2: Add `s2sx` binary that creates [self extracting archives](https://github.com/klauspost/compress/tree/master/s2#s2sx-self-extracting-archives).
	* s2: Speed up decompression on non-assembly platforms [#328](https://github.com/klauspost/compress/pull/328)

* Mar 1, 2021 (v1.11.9)
	* s2: Add ARM64 decompression assembly. Around 2x output speed. [#324](https://github.com/klauspost/compress/pull/324)
	* s2: Improve "better" speed and efficiency. [#325](https://github.com/klauspost/compress/pull/325)
	* s2: Fix binaries.

* Feb 25, 2021 (v1.11.8)
	* s2: Fixed occasional out-of-bounds write on amd64. Upgrade recommended.
	* s2: Add AMD64 assembly for better mode. 25-50% faster. [#315](https://github.com/klauspost/compress/pull/315)
	* s2: Less upfront decoder allocation. [#322](https://github.com/klauspost/compress/pull/322)
	* zstd: Faster "compression" of incompressible data. [#314](https://github.com/klauspost/compress/pull/314)
	* zip: Fix zip64 headers. [#313](https://github.com/klauspost/compress/pull/313)
  
* Jan 14, 2021 (v1.11.7)
	* Use Bytes() interface to get bytes across packages. [#309](https://github.com/klauspost/compress/pull/309)
	* s2: Add 'best' compression option.  [#310](https://github.com/klauspost/compress/pull/310)
	* s2: Add ReaderMaxBlockSize, changes `s2.NewReader` signature to include varargs. [#311](https://github.com/klauspost/compress/pull/311)
	* s2: Fix crash on small better buffers. [#308](https://github.com/klauspost/compress/pull/308)
	* s2: Clean up decoder. [#312](https://github.com/klauspost/compress/pull/312)

* Jan 7, 2021 (v1.11.6)
	* zstd: Make decoder allocations smaller [#306](https://github.com/klauspost/compress/pull/306)
	* zstd: Free Decoder resources when Reset is called with a nil io.Reader  [#305](https://github.com/klauspost/compress/pull/305)

* Dec 20, 2020 (v1.11.4)
	* zstd: Add Best compression mode [#304](https://github.com/klauspost/compress/pull/304)
	* Add header decoder [#299](https://github.com/klauspost/compress/pull/299)
	* s2: Add uncompressed stream option [#297](https://github.com/klauspost/compress/pull/297)
	* Simplify/speed up small blocks with known max size. [#300](https://github.com/klauspost/compress/pull/300)
	* zstd: Always reset literal dict encoder [#303](https://github.com/klauspost/compress/pull/303)

* Nov 15, 2020 (v1.11.3)
	* inflate: 10-15% faster decompression  [#293](https://github.com/klauspost/compress/pull/293)
	* zstd: Tweak DecodeAll default allocation [#295](https://github.com/klauspost/compress/pull/295)

* Oct 11, 2020 (v1.11.2)
	* s2: Fix out of bounds read in "better" block compression [#291](https://github.com/klauspost/compress/pull/291)

* Oct 1, 2020 (v1.11.1)
	* zstd: Set allLitEntropy true in default configuration [#286](https://github.com/klauspost/compress/pull/286)

* Sept 8, 2020 (v1.11.0)
	* zstd: Add experimental compression [dictionaries](https://github.com/klauspost/compress/tree/master/zstd#dictionaries) [#281](https://github.com/klauspost/compress/pull/281)
	* zstd: Fix mixed Write and ReadFrom calls [#282](https://github.com/klauspost/compress/pull/282)
	* inflate/gz: Limit variable shifts, ~5% faster decompression [#274](https://github.com/klauspost/compress/pull/274)
</details>

<details>
	<summary>See changes to v1.10.x</summary>
 
* July 8, 2020 (v1.10.11) 
	* zstd: Fix extra block when compressing with ReadFrom. [#278](https://github.com/klauspost/compress/pull/278)
	* huff0: Also populate compression table when reading decoding table. [#275](https://github.com/klauspost/compress/pull/275)
	
* June 23, 2020 (v1.10.10) 
	* zstd: Skip entropy compression in fastest mode when no matches. [#270](https://github.com/klauspost/compress/pull/270)
	
* June 16, 2020 (v1.10.9): 
	* zstd: API change for specifying dictionaries. See [#268](https://github.com/klauspost/compress/pull/268)
	* zip: update CreateHeaderRaw to handle zip64 fields. [#266](https://github.com/klauspost/compress/pull/266)
	* Fuzzit tests removed. The service has been purchased and is no longer available.
	
* June 5, 2020 (v1.10.8): 
	* 1.15x faster zstd block decompression. [#265](https://github.com/klauspost/compress/pull/265)
	
* June 1, 2020 (v1.10.7): 
	* Added zstd decompression [dictionary support](https://github.com/klauspost/compress/tree/master/zstd#dictionaries)
	* Increase zstd decompression speed up to 1.19x.  [#259](https://github.com/klauspost/compress/pull/259)
	* Remove internal reset call in zstd compression and reduce allocations. [#263](https://github.com/klauspost/compress/pull/263)
	
* May 21, 2020: (v1.10.6) 
	* zstd: Reduce allocations while decoding. [#258](https://github.com/klauspost/compress/pull/258), [#252](https://github.com/klauspost/compress/pull/252)
	* zstd: Stricter decompression checks.
	
* April 12, 2020: (v1.10.5)
	* s2-commands: Flush output when receiving SIGINT. [#239](https://github.com/klauspost/compress/pull/239)
	
* Apr 8, 2020: (v1.10.4) 
	* zstd: Minor/special case optimizations. [#251](https://github.com/klauspost/compress/pull/251),  [#250](https://github.com/klauspost/compress/pull/250),  [#249](https://github.com/klauspost/compress/pull/249),  [#247](https://github.com/klauspost/compress/pull/247)
* Mar 11, 2020: (v1.10.3) 
	* s2: Use S2 encoder in pure Go mode for Snappy output as well. [#245](https://github.com/klauspost/compress/pull/245)
	* s2: Fix pure Go block encoder. [#244](https://github.com/klauspost/compress/pull/244)
	* zstd: Added "better compression" mode. [#240](https://github.com/klauspost/compress/pull/240)
	* zstd: Improve speed of fastest compression mode by 5-10% [#241](https://github.com/klauspost/compress/pull/241)
	* zstd: Skip creating encoders when not needed. [#238](https://github.com/klauspost/compress/pull/238)
	
* Feb 27, 2020: (v1.10.2) 
	* Close to 50% speedup in inflate (gzip/zip decompression). [#236](https://github.com/klauspost/compress/pull/236) [#234](https://github.com/klauspost/compress/pull/234) [#232](https://github.com/klauspost/compress/pull/232)
	* Reduce deflate level 1-6 memory usage up to 59%. [#227](https://github.com/klauspost/compress/pull/227)
	
* Feb 18, 2020: (v1.10.1)
	* Fix zstd crash when resetting multiple times without sending data. [#226](https://github.com/klauspost/compress/pull/226)
	* deflate: Fix dictionary use on level 1-6. [#224](https://github.com/klauspost/compress/pull/224)
	* Remove deflate writer reference when closing. [#224](https://github.com/klauspost/compress/pull/224)
	
* Feb 4, 2020: (v1.10.0) 
	* Add optional dictionary to [stateless deflate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc#StatelessDeflate). Breaking change, send `nil` for previous behaviour. [#216](https://github.com/klauspost/compress/pull/216)
	* Fix buffer overflow on repeated small block deflate.  [#218](https://github.com/klauspost/compress/pull/218)
	* Allow copying content from an existing ZIP file without decompressing+compressing. [#214](https://github.com/klauspost/compress/pull/214)
	* Added [S2](https://github.com/klauspost/compress/tree/master/s2#s2-compression) AMD64 assembler and various optimizations. Stream speed >10GB/s.  [#186](https://github.com/klauspost/compress/pull/186)

</details>

<details>
	<summary>See changes prior to v1.10.0</summary>

* Jan 20,2020 (v1.9.8) Optimize gzip/deflate with better size estimates and faster table generation. [#207](https://github.com/klauspost/compress/pull/207) by [luyu6056](https://github.com/luyu6056),  [#206](https://github.com/klauspost/compress/pull/206).
* Jan 11, 2020: S2 Encode/Decode will use provided buffer if capacity is big enough. [#204](https://github.com/klauspost/compress/pull/204) 
* Jan 5, 2020: (v1.9.7) Fix another zstd regression in v1.9.5 - v1.9.6 removed.
* Jan 4, 2020: (v1.9.6) Regression in v1.9.5 fixed causing corrupt zstd encodes in rare cases.
* Jan 4, 2020: Faster IO in [s2c + s2d commandline tools](https://github.com/klauspost/compress/tree/master/s2#commandline-tools) compression/decompression. [#192](https://github.com/klauspost/compress/pull/192)
* Dec 29, 2019: Removed v1.9.5 since fuzz tests showed a compatibility problem with the reference zstandard decoder.
* Dec 29, 2019: (v1.9.5) zstd: 10-20% faster block compression. [#199](https://github.com/klauspost/compress/pull/199)
* Dec 29, 2019: [zip](https://godoc.org/github.com/klauspost/compress/zip) package updated with latest Go features
* Dec 29, 2019: zstd: Single segment flag condintions tweaked. [#197](https://github.com/klauspost/compress/pull/197)
* Dec 18, 2019: s2: Faster compression when ReadFrom is used. [#198](https://github.com/klauspost/compress/pull/198)
* Dec 10, 2019: s2: Fix repeat length output when just above at 16MB limit.
* Dec 10, 2019: zstd: Add function to get decoder as io.ReadCloser. [#191](https://github.com/klauspost/compress/pull/191)
* Dec 3, 2019: (v1.9.4) S2: limit max repeat length. [#188](https://github.com/klauspost/compress/pull/188)
* Dec 3, 2019: Add [WithNoEntropyCompression](https://godoc.org/github.com/klauspost/compress/zstd#WithNoEntropyCompression) to zstd [#187](https://github.com/klauspost/compress/pull/187)
* Dec 3, 2019: Reduce memory use for tests. Check for leaked goroutines.
* Nov 28, 2019 (v1.9.3) Less allocations in stateless deflate.
* Nov 28, 2019: 5-20% Faster huff0 decode. Impacts zstd as well. [#184](https://github.com/klauspost/compress/pull/184)
* Nov 12, 2019 (v1.9.2) Added [Stateless Compression](#stateless-compression) for gzip/deflate.
* Nov 12, 2019: Fixed zstd decompression of large single blocks. [#180](https://github.com/klauspost/compress/pull/180)
* Nov 11, 2019: Set default  [s2c](https://github.com/klauspost/compress/tree/master/s2#commandline-tools) block size to 4MB.
* Nov 11, 2019: Reduce inflate memory use by 1KB.
* Nov 10, 2019: Less allocations in deflate bit writer.
* Nov 10, 2019: Fix inconsistent error returned by zstd decoder.
* Oct 28, 2019 (v1.9.1) ztsd: Fix crash when compressing blocks. [#174](https://github.com/klauspost/compress/pull/174)
* Oct 24, 2019 (v1.9.0) zstd: Fix rare data corruption [#173](https://github.com/klauspost/compress/pull/173)
* Oct 24, 2019 zstd: Fix huff0 out of buffer write [#171](https://github.com/klauspost/compress/pull/171) and always return errors [#172](https://github.com/klauspost/compress/pull/172) 
* Oct 10, 2019: Big deflate rewrite, 30-40% faster with better compression [#105](https://github.com/klauspost/compress/pull/105)

</details>

<details>
	<summary>See changes prior to v1.9.0</summary>

* Oct 10, 2019: (v1.8.6) zstd: Allow partial reads to get flushed data. [#169](https://github.com/klauspost/compress/pull/169)
* Oct 3, 2019: Fix inconsistent results on broken zstd streams.
* Sep 25, 2019: Added `-rm` (remove source files) and `-q` (no output except errors) to `s2c` and `s2d` [commands](https://github.com/klauspost/compress/tree/master/s2#commandline-tools)
* Sep 16, 2019: (v1.8.4) Add `s2c` and `s2d` [commandline tools](https://github.com/klauspost/compress/tree/master/s2#commandline-tools).
* Sep 10, 2019: (v1.8.3) Fix s2 decoder [Skip](https://godoc.org/github.com/klauspost/compress/s2#Reader.Skip).
* Sep 7, 2019: zstd: Added [WithWindowSize](https://godoc.org/github.com/klauspost/compress/zstd#WithWindowSize), contributed by [ianwilkes](https://github.com/ianwilkes).
* Sep 5, 2019: (v1.8.2) Add [WithZeroFrames](https://godoc.org/github.com/klauspost/compress/zstd#WithZeroFrames) which adds full zero payload block encoding option.
* Sep 5, 2019: Lazy initialization of zstandard predefined en/decoder tables.
* Aug 26, 2019: (v1.8.1) S2: 1-2% compression increase in "better" compression mode.
* Aug 26, 2019: zstd: Check maximum size of Huffman 1X compressed literals while decoding.
* Aug 24, 2019: (v1.8.0) Added [S2 compression](https://github.com/klauspost/compress/tree/master/s2#s2-compression), a high performance replacement for Snappy. 
* Aug 21, 2019: (v1.7.6) Fixed minor issues found by fuzzer. One could lead to zstd not decompressing.
* Aug 18, 2019: Add [fuzzit](https://fuzzit.dev/) continuous fuzzing.
* Aug 14, 2019: zstd: Skip incompressible data 2x faster.  [#147](https://github.com/klauspost/compress/pull/147)
* Aug 4, 2019 (v1.7.5): Better literal compression. [#146](https://github.com/klauspost/compress/pull/146)
* Aug 4, 2019: Faster zstd compression. [#143](https://github.com/klauspost/compress/pull/143) [#144](https://github.com/klauspost/compress/pull/144)
* Aug 4, 2019: Faster zstd decompression. [#145](https://github.com/klauspost/compress/pull/145) [#143](https://github.com/klauspost/compress/pull/143) [#142](https://github.com/klauspost/compress/pull/142)
* July 15, 2019 (v1.7.4): Fix double EOF block in rare cases on zstd encoder.
* July 15, 2019 (v1.7.3): Minor speedup/compression increase in default zstd encoder.
* July 14, 2019: zstd decoder: Fix decompression error on multiple uses with mixed content.
* July 7, 2019 (v1.7.2): Snappy update, zstd decoder potential race fix.
* June 17, 2019: zstd decompression bugfix.
* June 17, 2019: fix 32 bit builds.
* June 17, 2019: Easier use in modules (less dependencies).
* June 9, 2019: New stronger "default" [zstd](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression mode. Matches zstd default compression ratio.
* June 5, 2019: 20-40% throughput in [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and better compression.
* June 5, 2019: deflate/gzip compression: Reduce memory usage of lower compression levels.
* June 2, 2019: Added [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression!
* May 25, 2019: deflate/gzip: 10% faster bit writer, mostly visible in lower levels.
* Apr 22, 2019: [zstd](https://github.com/klauspost/compress/tree/master/zstd#zstd) decompression added.
* Aug 1, 2018: Added [huff0 README](https://github.com/klauspost/compress/tree/master/huff0#huff0-entropy-compression).
* Jul 8, 2018: Added [Performance Update 2018](#performance-update-2018) below.
* Jun 23, 2018: Merged [Go 1.11 inflate optimizations](https://go-review.googlesource.com/c/go/+/102235). Go 1.9 is now required. Backwards compatible version tagged with [v1.3.0](https://github.com/klauspost/compress/releases/tag/v1.3.0).
* Apr 2, 2018: Added [huff0](https://godoc.org/github.com/klauspost/compress/huff0) en/decoder. Experimental for now, API may change.
* Mar 4, 2018: Added [FSE Entropy](https://godoc.org/github.com/klauspost/compress/fse) en/decoder. Experimental for now, API may change.
* Nov 3, 2017: Add compression [Estimate](https://godoc.org/github.com/klauspost/compress#Estimate) function.
* May 28, 2017: Reduce allocations when resetting decoder.
* Apr 02, 2017: Change back to official crc32, since changes were merged in Go 1.7.
* Jan 14, 2017: Reduce stack pressure due to array copies. See [Issue #18625](https://github.com/golang/go/issues/18625).
* Oct 25, 2016: Level 2-4 have been rewritten and now offers significantly better performance than before.
* Oct 20, 2016: Port zlib changes from Go 1.7 to fix zlib writer issue. Please update.
* Oct 16, 2016: Go 1.7 changes merged. Apples to apples this package is a few percent faster, but has a significantly better balance between speed and compression per level. 
* Mar 24, 2016: Always attempt Huffman encoding on level 4-7. This improves base 64 encoded data compression.
* Mar 24, 2016: Small speedup for level 1-3.
* Feb 19, 2016: Faster bit writer, level -2 is 15% faster, level 1 is 4% faster.
* Feb 19, 2016: Handle small payloads faster in level 1-3.
* Feb 19, 2016: Added faster level 2 + 3 compression modes.
* Feb 19, 2016: [Rebalanced compression levels](https://blog.klauspost.com/rebalancing-deflate-compression-levels/), so there is a more even progression in terms of compression. New default level is 5.
* Feb 14, 2016: Snappy: Merge upstream changes. 
* Feb 14, 2016: Snappy: Fix aggressive skipping.
* Feb 14, 2016: Snappy: Update benchmark.
* Feb 13, 2016: Deflate: Fixed assembler problem that could lead to sub-optimal compression.
* Feb 12, 2016: Snappy: Added AMD64 SSE 4.2 optimizations to matching, which makes easy to compress material run faster. Typical speedup is around 25%.
* Feb 9, 2016: Added Snappy package fork. This version is 5-7% faster, much more on hard to compress content.
* Jan 30, 2016: Optimize level 1 to 3 by not considering static dictionary or storing uncompressed. ~4-5% speedup.
* Jan 16, 2016: Optimization on deflate level 1,2,3 compression.
* Jan 8 2016: Merge [CL 18317](https://go-review.googlesource.com/#/c/18317): fix reading, writing of zip64 archives.
* Dec 8 2015: Make level 1 and -2 deterministic even if write size differs.
* Dec 8 2015: Split encoding functions, so hashing and matching can potentially be inlined. 1-3% faster on AMD64. 5% faster on other platforms.
* Dec 8 2015: Fixed rare [one byte out-of bounds read](https://github.com/klauspost/compress/issues/20). Please update!
* Nov 23 2015: Optimization on token writer. ~2-4% faster. Contributed by [@dsnet](https://github.com/dsnet).
* Nov 20 2015: Small optimization to bit writer on 64 bit systems.
* Nov 17 2015: Fixed out-of-bound errors if the underlying Writer returned an error. See [#15](https://github.com/klauspost/compress/issues/15).
* Nov 12 2015: Added [io.WriterTo](https://golang.org/pkg/io/#WriterTo) support to gzip/inflate.
* Nov 11 2015: Merged [CL 16669](https://go-review.googlesource.com/#/c/16669/4): archive/zip: enable overriding (de)compressors per file
* Oct 15 2015: Added skipping on uncompressible data. Random data speed up >5x.

</details>

# deflate usage

The packages are drop-in replacements for standard library [deflate](https://godoc.org/github.com/klauspost/compress/flate), [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip), and [zlib](https://godoc.org/github.com/klauspost/compress/zlib). Simply replace the import path to use them:

Typical speed is about 2x of the standard library packages.

| old import       | new import                            | Documentation                                                           |
|------------------|---------------------------------------|-------------------------------------------------------------------------|
| `compress/gzip`  | `github.com/klauspost/compress/gzip`  | [gzip](https://pkg.go.dev/github.com/klauspost/compress/gzip?tab=doc)   |
| `compress/zlib`  | `github.com/klauspost/compress/zlib`  | [zlib](https://pkg.go.dev/github.com/klauspost/compress/zlib?tab=doc)   |
| `archive/zip`    | `github.com/klauspost/compress/zip`   | [zip](https://pkg.go.dev/github.com/klauspost/compress/zip?tab=doc)     |
| `compress/flate` | `github.com/klauspost/compress/flate` | [flate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc) |

You may also be interested in [pgzip](https://github.com/klauspost/pgzip), which is a drop-in replacement for gzip, which support multithreaded compression on big files and the optimized [crc32](https://github.com/klauspost/crc32) package used by these packages.

The packages implement the same API as the standard library, so you can use the original godoc documentation: [gzip](http://golang.org/pkg/compress/gzip/), [zip](http://golang.org/pkg/archive/zip/), [zlib](http://golang.org/pkg/compress/zlib/), [flate](http://golang.org/pkg/compress/flate/).

Currently there is only minor speedup on decompression (mostly CRC32 calculation).

Memory usage is typically 1MB for a Writer. stdlib is in the same range. 
If you expect to have a lot of concurrently allocated Writers consider using 
the stateless compression described below.

For compression performance, see: [this spreadsheet](https://docs.google.com/spreadsheets/d/1nuNE2nPfuINCZJRMt6wFWhKpToF95I47XjSsc-1rbPQ/edit?usp=sharing).

To disable all assembly add `-tags=noasm`. This works across all packages.

# Stateless compression

This package offers stateless compression as a special option for gzip/deflate. 
It will do compression but without maintaining any state between Write calls.

This means there will be no memory kept between Write calls, but compression and speed will be suboptimal.

This is only relevant in cases where you expect to run many thousands of compressors concurrently, 
but with very little activity. This is *not* intended for regular web servers serving individual requests.  

Because of this, the size of actual Write calls will affect output size.

In gzip, specify level `-3` / `gzip.StatelessCompression` to enable.

For direct deflate use, NewStatelessWriter and StatelessDeflate are available. See [documentation](https://godoc.org/github.com/klauspost/compress/flate#NewStatelessWriter)

A `bufio.Writer` can of course be used to control write sizes. For example, to use a 4KB buffer:

```go
	// replace 'ioutil.Discard' with your output.
	gzw, err := gzip.NewWriterLevel(ioutil.Discard, gzip.StatelessCompression)
	if err != nil {
		return err
	}
	defer gzw.Close()

	w := bufio.NewWriterSize(gzw, 4096)
	defer w.Flush()
	
	// Write to 'w' 
```

This will only use up to 4KB in memory when the writer is idle. 

Compression is almost always worse than the fastest compression level 
and each write will allocate (a little) memory. 


# Other packages

Here are other packages of good quality and pure Go (no cgo wrappers or autoconverted code):

* [github.com/pierrec/lz4](https://github.com/pierrec/lz4) - strong multithreaded LZ4 compression.
* [github.com/cosnicolaou/pbzip2](https://github.com/cosnicolaou/pbzip2) - multithreaded bzip2 decompression.
* [github.com/dsnet/compress](https://github.com/dsnet/compress) - brotli decompression, bzip2 writer.
* [github.com/ronanh/intcomp](https://github.com/ronanh/intcomp) - Integer compression.
* [github.com/spenczar/fpc](https://github.com/spenczar/fpc) - Float compression.
* [github.com/minio/zipindex](https://github.com/minio/zipindex) - External ZIP directory index.
* [github.com/ybirader/pzip](https://github.com/ybirader/pzip) - Fast concurrent zip archiver and extractor.

# license

This code is licensed under the same conditions as the original Go code. See LICENSE file.

---

### Overview (`vendor/github.com/mitchellh/mapstructure/README.md`)

# mapstructure [](https://godoc.org/github.com/mitchellh/mapstructure)

mapstructure is a Go library for decoding generic map values to structures
and vice versa, while providing helpful error handling.

This library is most useful when decoding values from some data stream (JSON,
Gob, etc.) where you don't _quite_ know the structure of the underlying data
until you read a part of it. You can therefore read a `map[string]interface{}`
and use this library to decode it into the proper underlying native Go
structure.

## Installation

Standard `go get`:

```
$ go get github.com/mitchellh/mapstructure
```

## Usage & Example

For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/mapstructure).

The `Decode` function has examples associated with it there.

## But Why?!

Go offers fantastic standard libraries for decoding formats such as JSON.
The standard method is to have a struct pre-created, and populate that struct
from the bytes of the encoded format. This is great, but the problem is if
you have configuration or an encoding that changes slightly depending on
specific fields. For example, consider this JSON:

```json
{
  "type": "person",
  "name": "Mitchell"
}
```

Perhaps we can't populate a specific structure without first reading
the "type" field from the JSON. We could always do two passes over the
decoding of the JSON (reading the "type" first, and the rest later).
However, it is much simpler to just decode this into a `map[string]interface{}`
structure, read the "type" key, then use something like this library
to decode it into the proper structure.

---

### Overview (`vendor/github.com/opencontainers/go-digest/README.md`)

# go-digest

[](https://godoc.org/github.com/opencontainers/go-digest) [](https://goreportcard.com/report/github.com/opencontainers/go-digest) [](https://travis-ci.org/opencontainers/go-digest)

Common digest package used across the container ecosystem.

Please see the [godoc](https://godoc.org/github.com/opencontainers/go-digest) for more information.

# What is a digest?

A digest is just a [hash](https://en.wikipedia.org/wiki/Hash_function).

The most common use case for a digest is to create a content identifier for use in [Content Addressable Storage](https://en.wikipedia.org/wiki/Content-addressable_storage) systems:

```go
id := digest.FromBytes([]byte("my content"))
```

In the example above, the id can be used to uniquely identify the byte slice "my content".
This allows two disparate applications to agree on a verifiable identifier without having to trust one another.

An identifying digest can be verified, as follows:

```go
if id != digest.FromBytes([]byte("my content")) {
  return errors.New("the content has changed!")
}
```

A `Verifier` type can be used to handle cases where an `io.Reader` makes more sense:

```go
rd := getContent()
verifier := id.Verifier()
io.Copy(verifier, rd)

if !verifier.Verified() {
  return errors.New("the content has changed!")
}
```

Using [Merkle DAGs](https://en.wikipedia.org/wiki/Merkle_tree), this can power a rich, safe, content distribution system.

# Usage

While the [godoc](https://godoc.org/github.com/opencontainers/go-digest) is considered the best resource, a few important items need to be called out when using this package.

1. Make sure to import the hash implementations into your application or the package will panic.
    You should have something like the following in the main (or other entrypoint) of your application:
   
    ```go
    import (
        _ "crypto/sha256"
        _ "crypto/sha512"
    )
    ```
    This may seem inconvenient but it allows you replace the hash 
    implementations with others, such as https://github.com/stevvooe/resumable.
 
2. Even though `digest.Digest` may be assemblable as a string, _always_ verify your input with `digest.Parse` or use `Digest.Validate` when accepting untrusted input.
    While there are measures to avoid common problems, this will ensure you have valid digests in the rest of your application.

3. While alternative encodings of hash values (digests) are possible (for example, base64), this package deals exclusively with hex-encoded digests.

# Stability

The Go API, at this stage, is considered stable, unless otherwise noted.

As always, before using a package export, read the [godoc](https://godoc.org/github.com/opencontainers/go-digest).

# Contributing

This package is considered fairly complete.
It has been in production in thousands (millions?) of deployments and is fairly battle-hardened.
New additions will be met with skepticism.
If you think there is a missing feature, please file a bug clearly describing the problem and the alternatives you tried before submitting a PR.

## Code of Conduct

Participation in the OpenContainers community is governed by [OpenContainer's Code of Conduct][code-of-conduct].

## Security

If you find an issue, please follow the [security][security] protocol to report it.

# Copyright and license

Copyright © 2019, 2020 OCI Contributors
Copyright © 2016 Docker, Inc.
All rights reserved, except as follows.
Code is released under the [Apache 2.0 license](LICENSE).
This `README.md` file and the [`CONTRIBUTING.md`](CONTRIBUTING.md) file are licensed under the Creative Commons Attribution 4.0 International License under the terms and conditions set forth in the file [`LICENSE.docs`](LICENSE.docs).
You may obtain a duplicate copy of the same license, titled CC BY-SA 4.0, at http://creativecommons.org/licenses/by-sa/4.0/.

[security]: https://github.com/opencontainers/org/blob/master/security
[code-of-conduct]: https://github.com/opencontainers/org/blob/master/CODE_OF_CONDUCT.md

---

### Overview (`vendor/github.com/pkg/browser/README.md`)

# browser
    import "github.com/pkg/browser"

Package browser provides helpers to open files, readers, and urls in a browser window.

The choice of which browser is started is entirely client dependant.





## Variables
``` go
var Stderr io.Writer = os.Stderr
```
Stderr is the io.Writer to which executed commands write standard error.

``` go
var Stdout io.Writer = os.Stdout
```
Stdout is the io.Writer to which executed commands write standard output.


## func OpenFile
``` go
func OpenFile(path string) error
```
OpenFile opens new browser window for the file path.


## func OpenReader
``` go
func OpenReader(r io.Reader) error
```
OpenReader consumes the contents of r and presents the
results in a new browser window.


## func OpenURL
``` go
func OpenURL(url string) error
```
OpenURL opens a new browser window pointing to url.









- - -
Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md)

---

### Overview (`vendor/github.com/prometheus/otlptranslator/README.md`)

# OTLP Prometheus Translator

A Go library for converting [OpenTelemetry Protocol (OTLP)](https://opentelemetry.io/docs/specs/otlp/) metric and attribute names to [Prometheus](https://prometheus.io/)-compliant formats. This is an internal library for both Prometheus and Open Telemetry, without any stability guarantees for external usage.

Part of the [Prometheus](https://prometheus.io/) ecosystem, following the [OpenTelemetry to Prometheus compatibility specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/compatibility/prometheus_and_openmetrics.md).

## Features

- **Metric Name and Label Translation**: Convert OTLP metric names and attributes to Prometheus-compliant format
- **Unit Handling**: Translate OTLP units to Prometheus unit conventions
- **Type-Aware Suffixes**: Optionally append `_total`, `_ratio` based on metric type
- **Namespace Support**: Add configurable namespace prefixes
- **UTF-8 Support**: Choose between Prometheus legacy scheme compliant metric/label names (`[a-zA-Z0-9:_]`) or untranslated metric/label names
- **Translation Strategy Configuration**: Select a translation strategy with a standard set of strings.

## Installation

```bash
go get github.com/prometheus/otlptranslator
```

## Quick Start

```go
package main

import (
    "fmt"
    "github.com/prometheus/otlptranslator"
)

func main() {
    // Create a metric namer using traditional Prometheus name translation, with suffixes added and UTF-8 disallowed.
    strategy := otlptranslator.UnderscoreEscapingWithSuffixes
    namer := otlptranslator.NewMetricNamer("myapp", strategy)

    // Translate OTLP metric to Prometheus format
    metric := otlptranslator.Metric{
        Name: "http.server.request.duration",
        Unit: "s",
        Type: otlptranslator.MetricTypeHistogram,
    }
    fmt.Println(namer.Build(metric)) // Output: myapp_http_server_request_duration_seconds

    // Translate label names
    labelNamer := otlptranslator.LabelNamer{UTF8Allowed: false}
    fmt.Println(labelNamer.Build("http.method")) // Output: http_method
}
```

## Usage Examples

### Metric Name Translation

```go
namer := otlptranslator.MetricNamer{WithMetricSuffixes: true, UTF8Allowed: false}

// Counter gets _total suffix
counter := otlptranslator.Metric{
    Name: "requests.count", Unit: "1", Type: otlptranslator.MetricTypeMonotonicCounter,
}
fmt.Println(namer.Build(counter)) // requests_count_total

// Gauge with unit conversion
gauge := otlptranslator.Metric{
    Name: "memory.usage", Unit: "By", Type: otlptranslator.MetricTypeGauge,
}
fmt.Println(namer.Build(gauge)) // memory_usage_bytes

// Dimensionless gauge gets _ratio suffix
ratio := otlptranslator.Metric{
    Name: "cpu.utilization", Unit: "1", Type: otlptranslator.MetricTypeGauge,
}
fmt.Println(namer.Build(ratio)) // cpu_utilization_ratio
```

### Label Translation

```go
labelNamer := otlptranslator.LabelNamer{UTF8Allowed: false}

labelNamer.Build("http.method")           // http_method
labelNamer.Build("123invalid")            // key_123invalid
labelNamer.Build("_private")              // key_private
labelNamer.Build("__reserved__")          // __reserved__ (preserved)
labelNamer.Build("label@with$symbols")    // label_with_symbols
```

### Unit Translation

```go
unitNamer := otlptranslator.UnitNamer{UTF8Allowed: false}

unitNamer.Build("s")           // seconds
unitNamer.Build("By")          // bytes
unitNamer.Build("requests/s")  // requests_per_second
unitNamer.Build("1")           // "" (dimensionless)
```

### Configuration Options

```go
// Prometheus-compliant mode - supports [a-zA-Z0-9:_]
compliantNamer := otlptranslator.MetricNamer{UTF8Allowed: false, WithMetricSuffixes: true}

// Transparent pass-through mode, aka "NoTranslation"
utf8Namer := otlptranslator.MetricNamer{UTF8Allowed: true, WithMetricSuffixes: false}
utf8Namer = otlptranslator.NewMetricNamer("", otlpTranslator.NoTranslation)

// With namespace and suffixes
productionNamer := otlptranslator.MetricNamer{
    Namespace:          "myservice",
    WithMetricSuffixes: true,
    UTF8Allowed:        false,
}
```

## License

Licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.

---

### Overview (`vendor/github.com/prometheus/procfs/README.md`)

# procfs

This package provides functions to retrieve system, kernel, and process
metrics from the pseudo-filesystems /proc and /sys.

*WARNING*: This package is a work in progress. Its API may still break in
backwards-incompatible ways without warnings. Use it at your own risk.

[](https://pkg.go.dev/github.com/prometheus/procfs)
[](https://circleci.com/gh/prometheus/procfs/tree/master)
[](https://goreportcard.com/report/github.com/prometheus/procfs)

## Usage

The procfs library is organized by packages based on whether the gathered data is coming from
/proc, /sys, or both.  Each package contains an `FS` type which represents the path to either /proc, 
/sys, or both.  For example, cpu statistics are gathered from
`/proc/stat` and are available via the root procfs package.  First, the proc filesystem mount
point is initialized, and then the stat information is read.

```go
fs, err := procfs.NewFS("/proc")
stats, err := fs.Stat()
```

Some sub-packages such as `blockdevice`, require access to both the proc and sys filesystems.

```go
    fs, err := blockdevice.NewFS("/proc", "/sys")
    stats, err := fs.ProcDiskstats()
```

## Package Organization

The packages in this project are organized according to (1) whether the data comes from the `/proc` or
`/sys` filesystem and (2) the type of information being retrieved.  For example, most process information
can be gathered from the functions in the root `procfs` package.  Information about block devices such as disk drives
is available in the `blockdevices` sub-package.

## Building and Testing

The procfs library is intended to be built as part of another application, so there are no distributable binaries.  
However, most of the API includes unit tests which can be run with `make test`.

### Updating Test Fixtures

The procfs library includes a set of test fixtures which include many example files from
the `/proc` and `/sys` filesystems.  These fixtures are included as a [ttar](https://github.com/ideaship/ttar) file
which is extracted automatically during testing.  To add/update the test fixtures, first
ensure the `testdata/fixtures` directory is up to date by removing the existing directory and then
extracting the ttar file using `make testdata/fixtures/.unpacked` or just `make test`.

```bash
rm -rf testdata/fixtures
make test
```

Next, make the required changes to the extracted files in the `testdata/fixtures` directory.  When
the changes are complete, run `make update_fixtures` to create a new `fixtures.ttar` file
based on the updated `fixtures` directory.  And finally, verify the changes using
`git diff testdata/fixtures.ttar`.

---

### Overview (`vendor/github.com/sirupsen/logrus/README.md`)

# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [](https://github.com/sirupsen/logrus/actions?query=workflow%3ACI) [](https://pkg.go.dev/github.com/sirupsen/logrus)

Logrus is a structured logger for Go (golang), completely API compatible with
the standard library logger.

**Logrus is in maintenance mode.** The project focuses on security, bug fixes,
and performance improvements. New features are not planned, aside from changes
required to provide interoperability with other logging ecosystems (e.g., Go's
[log/slog](https://pkg.go.dev/log/slog)).

I believe Logrus' biggest contribution is to have played a part in today's
widespread use of structured logging in Golang. There doesn't seem to be a
reason to do a major, breaking iteration into Logrus V2, since the fantastic Go
community has built those independently. Many fantastic alternatives have sprung
up. Logrus would look like those, had it been re-designed with what we know
about structured logging in Go today. Check out, for example,
[Zerolog][zerolog], [Zap][zap], and [Apex][apex].

[zerolog]: https://github.com/rs/zerolog
[zap]: https://github.com/uber-go/zap
[apex]: https://github.com/apex/log

Nicely color-coded in development (when a TTY is attached, otherwise just
plain text):



With `logrus.SetFormatter(&logrus.JSONFormatter{})`, for easy parsing by logstash
or Splunk:

```json lines
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
{"level":"warning","msg":"The group's number increased tremendously!","number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
{"animal":"walrus","level":"info","msg":"A giant walrus appears!","size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.","size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
```

With the default `logrus.SetFormatter(&logrus.TextFormatter{})` when a TTY is not
attached, the output is compatible with the
[logfmt](https://pkg.go.dev/github.com/kr/logfmt) format:

```bash
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" animal=orca err="It's over 9000!" number=100 omg=true size=9009
```

To ensure this behaviour even if a TTY is attached, set your formatter as follows:

```go
logrus.SetFormatter(&logrus.TextFormatter{
    DisableColors: true,
    FullTimestamp: true,
})
```

#### Logging Method Name

If you wish to add the calling method as a field, instruct the logger via:

```go
logrus.SetReportCaller(true)
```

This adds the caller as 'method' like so:

```json
{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by","time":"2014-03-10 19:57:38.562543129 -0400 EDT"}
```

```bash
time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin
```

Note that this does add measurable overhead - the cost will depend on the version of Go, but is
between 20 and 40% in recent tests with 1.6 and 1.7.  You can validate this in your
environment via benchmarks:

```bash
go test -bench=ReportCaller
```

#### Case-sensitivity

The organization's name was [changed to lower-case][1]. If you are getting import
conflicts due to case sensitivity, please use the lower-case import:
`github.com/sirupsen/logrus`.

[1]: https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276

#### Example

The simplest way to use Logrus is simply the package-level exported logger:

```go
package main

import "github.com/sirupsen/logrus"

func main() {
  logrus.WithFields(logrus.Fields{
    "animal": "walrus",
  }).Info("A walrus appears")
}
```

Note that it's completely api-compatible with the stdlib logger, so you can
replace your `log` imports everywhere with `log "github.com/sirupsen/logrus"`
and you'll now have the flexibility of Logrus. You can customize it all you
want:

```go
package main

import (
  "os"

  log "github.com/sirupsen/logrus"
)

func init() {
  // Log as JSON instead of the default ASCII formatter.
  log.SetFormatter(&log.JSONFormatter{})

  // Output to stdout instead of the default stderr
  // Can be any io.Writer, see below for File example
  log.SetOutput(os.Stdout)

  // Only log the warning severity or above.
  log.SetLevel(log.WarnLevel)
}

func main() {
  log.WithFields(log.Fields{
    "animal": "walrus",
    "size":   10,
  }).Info("A group of walrus emerges from the ocean")

  log.WithFields(log.Fields{
    "omg":    true,
    "number": 122,
  }).Warn("The group's number increased tremendously!")

  log.WithFields(log.Fields{
    "omg":    true,
    "number": 100,
  }).Fatal("The ice breaks!")

  // A common pattern is to re-use fields between logging statements by re-using
  // the logrus.Entry returned from WithFields()
  contextLogger := log.WithFields(log.Fields{
    "common": "this is a common field",
    "other": "I also should be logged always",
  })

  contextLogger.Info("I'll be logged with common and other field")
  contextLogger.Info("Me too")
}
```

For more advanced usage such as logging to multiple locations from the same
application, you can also create an instance of the `logrus` Logger:

```go
package main

import (
  "os"

  "github.com/sirupsen/logrus"
)

// Create a new instance of the logger. You can have any number of instances.
var logger = logrus.New()

func main() {
  // The API for setting attributes is a little different than the package level
  // exported logger. See Godoc. 
  logger.Out = os.Stdout

  // You could set this to any `io.Writer` such as a file
  // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  // if err == nil {
  //  logger.Out = file
  // } else {
  //  logger.Info("Failed to log to file, using default stderr")
  // }

  logger.WithFields(logrus.Fields{
    "animal": "walrus",
    "size":   10,
  }).Info("A group of walrus emerges from the ocean")
}
```

#### Fields

Logrus encourages careful, structured logging through logging fields instead of
long, unparseable error messages. For example, instead of: `logrus.Fatalf("Failed
to send event %s to topic %s with key %d")`, you should log the much more
discoverable:

```go
logrus.WithFields(logrus.Fields{
  "event": event,
  "topic": topic,
  "key": key,
}).Fatal("Failed to send event")
```

We've found this API forces you to think about logging in a way that produces
much more useful logging messages. We've been in countless situations where just
a single added field to a log statement that was already there would've saved us
hours. The `WithFields` call is optional.

In general, with Logrus using any of the `printf`-family functions should be
seen as a hint you should add a field, however, you can still use the
`printf`-family functions with Logrus.

#### Default Fields

Often it's helpful to have fields _always_ attached to log statements in an
application or parts of one. For example, you may want to always log the
`request_id` and `user_ip` in the context of a request. Instead of writing
`logger.WithFields(logrus.Fields{"request_id": request_id, "user_ip": user_ip})` on
every line, you can create a `logrus.Entry` to pass around instead:

```go
requestLogger := logger.WithFields(logrus.Fields{"request_id": request_id, "user_ip": user_ip})
requestLogger.Info("something happened on that request") // will log request_id and user_ip
requestLogger.Warn("something not great happened")
```

#### Hooks

You can add hooks for logging levels. For example to send errors to an exception
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
multiple places simultaneously, e.g. syslog.

Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
`init`:

```go
package main

import (
  "log/syslog"

  "github.com/sirupsen/logrus"
  airbrake "gopkg.in/gemnasium/logrus-airbrake-hook.v2"
  logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
)

func init() {

  // Use the Airbrake hook to report errors that have Error severity or above to
  // an exception tracker. You can create custom hooks, see the Hooks section.
  logrus.AddHook(airbrake.NewHook(123, "xyz", "production"))

  hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
  if err != nil {
    logrus.Error("Unable to connect to local syslog daemon")
  } else {
    logrus.AddHook(hook)
  }
}
```

Note: Syslog hooks also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).

A list of currently known service hooks can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks)


#### Level logging

Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic.

```go
logrus.Trace("Something very low level.")
logrus.Debug("Useful debugging information.")
logrus.Info("Something noteworthy happened!")
logrus.Warn("You should probably take a look at this.")
logrus.Error("Something failed but I'm not quitting.")
// Calls os.Exit(1) after logging
logrus.Fatal("Bye.")
// Calls panic() after logging
logrus.Panic("I'm bailing.")
```

You can set the logging level on a `Logger`, then it will only log entries with
that severity or anything above it:

```go
// Will log anything that is info or above (warn, error, fatal, panic). Default.
logrus.SetLevel(logrus.InfoLevel)
```

It may be useful to set `logrus.Level = logrus.DebugLevel` in a debug or verbose
environment if your application has that.

Note: If you want different log levels for global (`logrus.SetLevel(...)`) and syslog logging, please check the [syslog hook README](hooks/syslog/README.md#different-log-levels-for-local-and-remote-logging).

#### Entries

Besides the fields added with `WithField` or `WithFields` some fields are
automatically added to all logging events:

1. `time`. The timestamp when the entry was created.
2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
   the `AddFields` call. E.g. `Failed to send event.`
3. `level`. The logging level. E.g. `info`.

#### Environments

Logrus has no notion of environment.

If you wish for hooks and formatters to only be used in specific environments,
you should handle that yourself. For example, if your application has a global
variable `Environment`, which is a string representation of the environment you
could do:

```go
import (
  "github.com/sirupsen/logrus"
)

func init() {
  // do something here to set environment depending on an environment variable
  // or command-line flag
  if Environment == "production" {
    logrus.SetFormatter(&logrus.JSONFormatter{})
  } else {
    // The TextFormatter is default, you don't actually have to do this.
    logrus.SetFormatter(&logrus.TextFormatter{})
  }
}
```

This configuration is how `logrus` was intended to be used, but JSON in
production is mostly only useful if you do log aggregation with tools like
Splunk or Logstash.

#### Formatters

The built-in logging formatters are:

* [`logrus.TextFormatter`](https://pkg.go.dev/github.com/sirupsen/logrus#TextFormatter)
  logs the event in colors if the logger output is a TTY, otherwise without colors.
  * To force colored output when there is no TTY, set the `ForceColors`
    field to `true`.  To force no colored output even if there is a TTY  set the
    `DisableColors` field to `true`.
  * On modern Windows terminals with ANSI (Virtual Terminal) support, TextFormatter
    automatically enables colored output.
  * If your environment does not support ANSI escape sequences, wrap the logger output
    using [github.com/mattn/go-colorable](https://github.com/mattn/go-colorable)
    and set `ForceColors` (or `CLICOLOR_FORCE=1`) to enable colors through the wrapper.
  * When colors are enabled, levels are truncated to 4 characters by default. To disable
    truncation set the `DisableLevelTruncation` field to `true`.
  * When outputting to a TTY, it's often helpful to visually scan down a column where all the levels are the same width. Setting the `PadLevelText` field to `true` enables this behavior, by adding padding to the level text.
* [`logrus.JSONFormatter`](https://pkg.go.dev/github.com/sirupsen/logrus#JSONFormatter)
  logs fields as JSON.

Third-party logging formatters:

* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine.
* [`GELF`](https://github.com/fabienm/go-logrus-formatters). Formats entries so they comply to Graylog's [GELF 1.1 specification](http://docs.graylog.org/en/2.4/pages/gelf.html).
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the Power of Zalgo.
* [`nested-logrus-formatter`](https://github.com/antonfisher/nested-logrus-formatter). Converts logrus fields to a nested structure.
* [`powerful-logrus-formatter`](https://github.com/zput/zxcTool). get fileName, log's line number and the latest function's name when print log; Save log to files.
* [`caption-json-formatter`](https://github.com/nolleh/caption_json_formatter). logrus's message json formatter with human-readable caption added.
* [`easy-logrus-formatter`](https://github.com/WeiZhixiong/easy-logrus-formatter). Provide a user-friendly formatter for logrus.
* [`redactrus`](https://github.com/ibreakthecloud/redactrus). Redacts sensitive information like password, apikeys, email, etc. from logs.

You can define your formatter by implementing the `Formatter` interface,
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
`Fields` type (`map[string]any`) with all your fields as well as the
default ones (see Entries section above):

```go
type MyJSONFormatter struct{}

logrus.SetFormatter(new(MyJSONFormatter))

func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
  // Note this doesn't include Time, Level and Message which are available on
  // the Entry. Consult `godoc` on information about those fields or read the
  // source of the official loggers.
  serialized, err := json.Marshal(entry.Data)
    if err != nil {
      return nil, fmt.Errorf("Failed to marshal fields to JSON, %w", err)
    }
  return append(serialized, '\n'), nil
}
```

#### Logger as an `io.Writer`

Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.

```go
w := logger.Writer()
defer w.Close()

srv := http.Server{
    // create a stdlib log.Logger that writes to
    // logrus.Logger.
    ErrorLog: log.New(w, "", 0),
}
```

Each line written to that writer will be printed the usual way, using formatters
and hooks. The level for those entries is `info`.

This means that we can override the standard library logger easily:

```go
logger := logrus.New()
logger.Formatter = &logrus.JSONFormatter{}

// Use logrus for standard log output
// Note that `log` here references stdlib's log
// Not logrus imported under the name `log`.
log.SetOutput(logger.Writer())
```

#### Rotation

Log rotation is not provided with Logrus. Log rotation should be done by an
external program (like `logrotate(8)`) that can compress and delete old log
entries. It should not be a feature of the application-level logger.

#### Tools

| Tool | Description |
| ---- | ----------- |
|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will be generated with different configs in different environments.|
|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) |

#### Testing

Logrus has a built-in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:

* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just adds the `test` hook
* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):

```go
import(
  "testing"

  "github.com/sirupsen/logrus"
  "github.com/sirupsen/logrus/hooks/test"
  "github.com/stretchr/testify/assert"
)

func TestSomething(t*testing.T){
  logger, hook := test.NewNullLogger()
  logger.Error("Helloerror")

  assert.Equal(t, 1, len(hook.Entries))
  assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level)
  assert.Equal(t, "Helloerror", hook.LastEntry().Message)

  hook.Reset()
  assert.Nil(t, hook.LastEntry())
}
```

#### Fatal handlers

Logrus can register one or more functions that will be called when any `fatal`
level message is logged. The registered handlers will be executed before
logrus performs an `os.Exit(1)`. This behavior may be helpful if callers need
to gracefully shut down. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted.

```go
// ...
handler := func() {
  // gracefully shut down something...
}
logrus.RegisterExitHandler(handler)
// ...
```

#### Thread safety

By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs.
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.

Situations when locking is not needed include:

* You have no hooks registered, or hooks calling is already thread-safe.

* Writing to logger.Out is already thread-safe, for example:

  1) logger.Out is protected by locks.

  2) logger.Out is an os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allows multi-thread/multi-process writing)

     (Refer to <http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/>)

---

### Overview (`vendor/github.com/spf13/cobra/README.md`)

<div align="center">
<a href="https://cobra.dev">
<img width="512" height="535" alt="cobra-logo" src="https://github.com/user-attachments/assets/c8bf9aad-b5ae-41d3-8899-d83baec10af8" />
</a>
</div>

Cobra is a library for creating powerful modern CLI applications.

<a href="https://cobra.dev">Visit Cobra.dev for extensive documentation</a> 


Cobra is used in many Go projects such as [Kubernetes](https://kubernetes.io/),
[Hugo](https://gohugo.io), and [GitHub CLI](https://github.com/cli/cli) to
name a few. [This list](site/content/projects_using_cobra.md) contains a more extensive list of projects using Cobra.

[](https://github.com/spf13/cobra/actions?query=workflow%3ATest)
[](https://pkg.go.dev/github.com/spf13/cobra)
[](https://goreportcard.com/report/github.com/spf13/cobra)
[](https://gophers.slack.com/archives/CD3LP1199)
<hr>
<div align="center" markdown="1">
   <sup>Supported by:</sup>
   <br>
   <br>
   <a href="https://www.warp.dev/cobra">
      <img alt="Warp sponsorship" width="400" src="https://github.com/user-attachments/assets/ab8dd143-b0fd-4904-bdc5-dd7ecac94eae">
   </a>

### [Warp, the AI terminal for devs](https://www.warp.dev/cobra)
[Try Cobra in Warp today](https://www.warp.dev/cobra)<br>

</div>
<hr>

# Overview

Cobra is a library providing a simple interface to create powerful modern CLI
interfaces similar to git & go tools.

Cobra provides:
* Easy subcommand-based CLIs: `app server`, `app fetch`, etc.
* Fully POSIX-compliant flags (including short & long versions)
* Nested subcommands
* Global, local and cascading flags
* Intelligent suggestions (`app srver`... did you mean `app server`?)
* Automatic help generation for commands and flags
* Grouping help for subcommands
* Automatic help flag recognition of `-h`, `--help`, etc.
* Automatically generated shell autocomplete for your application (bash, zsh, fish, powershell)
* Automatically generated man pages for your application
* Command aliases so you can change things without breaking them
* The flexibility to define your own help, usage, etc.
* Optional seamless integration with [viper](https://github.com/spf13/viper) for 12-factor apps

# Concepts

Cobra is built on a structure of commands, arguments & flags.

**Commands** represent actions, **Args** are things and **Flags** are modifiers for those actions.

The best applications read like sentences when used, and as a result, users
intuitively know how to interact with them.

The pattern to follow is
`APPNAME VERB NOUN --ADJECTIVE`
    or
`APPNAME COMMAND ARG --FLAG`.

A few good real world examples may better illustrate this point.

In the following example, 'server' is a command, and 'port' is a flag:

    hugo server --port=1313

In this command we are telling Git to clone the url bare.

    git clone URL --bare

## Commands

Command is the central point of the application. Each interaction that
the application supports will be contained in a Command. A command can
have children commands and optionally run an action.

In the example above, 'server' is the command.

[More about cobra.Command](https://pkg.go.dev/github.com/spf13/cobra#Command)

## Flags

A flag is a way to modify the behavior of a command. Cobra supports
fully POSIX-compliant flags as well as the Go [flag package](https://golang.org/pkg/flag/).
A Cobra command can define flags that persist through to children commands
and flags that are only available to that command.

In the example above, 'port' is the flag.

Flag functionality is provided by the [pflag
library](https://github.com/spf13/pflag), a fork of the flag standard library
which maintains the same interface while adding POSIX compliance.

# Installing
Using Cobra is easy. First, use `go get` to install the latest version
of the library.

```
go get -u github.com/spf13/cobra@latest
```

Next, include Cobra in your application:

```go
import "github.com/spf13/cobra"
```

# Usage
`cobra-cli` is a command line program to generate cobra applications and command files.
It will bootstrap your application scaffolding to rapidly
develop a Cobra-based application. It is the easiest way to incorporate Cobra into your application.

It can be installed by running:

```
go install github.com/spf13/cobra-cli@latest
```

For complete details on using the Cobra-CLI generator, please read [The Cobra Generator README](https://github.com/spf13/cobra-cli/blob/main/README.md)

For complete details on using the Cobra library, please read [The Cobra User Guide](site/content/user_guide.md).

# License

Cobra is released under the Apache 2.0 license. See [LICENSE.txt](LICENSE.txt)

---

### Overview (`vendor/github.com/spf13/pflag/README.md`)

[](https://travis-ci.org/spf13/pflag)
[](https://goreportcard.com/report/github.com/spf13/pflag)
[](https://godoc.org/github.com/spf13/pflag)

## Description

pflag is a drop-in replacement for Go's flag package, implementing
POSIX/GNU-style --flags.

pflag is compatible with the [GNU extensions to the POSIX recommendations
for command-line options][1]. For a more precise description, see the
"Command-line flag syntax" section below.

[1]: http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html

pflag is available under the same style of BSD license as the Go language,
which can be found in the LICENSE file.

## Installation

pflag is available using the standard `go get` command.

Install by running:

    go get github.com/spf13/pflag

Run tests by running:

    go test github.com/spf13/pflag

## Usage

pflag is a drop-in replacement of Go's native flag package. If you import
pflag under the name "flag" then all code should continue to function
with no changes.

``` go
import flag "github.com/spf13/pflag"
```

There is one exception to this: if you directly instantiate the Flag struct
there is one more field "Shorthand" that you will need to set.
Most code never instantiates this struct directly, and instead uses
functions such as String(), BoolVar(), and Var(), and is therefore
unaffected.

Define flags using flag.String(), Bool(), Int(), etc.

This declares an integer flag, -flagname, stored in the pointer ip, with type *int.

``` go
var ip *int = flag.Int("flagname", 1234, "help message for flagname")
```

If you like, you can bind the flag to a variable using the Var() functions.

``` go
var flagvar int
func init() {
    flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")
}
```

Or you can create custom flags that satisfy the Value interface (with
pointer receivers) and couple them to flag parsing by

``` go
flag.Var(&flagVal, "name", "help message for flagname")
```

For such flags, the default value is just the initial value of the variable.

After all flags are defined, call

``` go
flag.Parse()
```

to parse the command line into the defined flags.

Flags may then be used directly. If you're using the flags themselves,
they are all pointers; if you bind to variables, they're values.

``` go
fmt.Println("ip has value ", *ip)
fmt.Println("flagvar has value ", flagvar)
```

There are helper functions available to get the value stored in a Flag if you have a FlagSet but find
it difficult to keep up with all of the pointers in your code.
If you have a pflag.FlagSet with a flag called 'flagname' of type int you
can use GetInt() to get the int value. But notice that 'flagname' must exist
and it must be an int. GetString("flagname") will fail.

``` go
i, err := flagset.GetInt("flagname")
```

After parsing, the arguments after the flag are available as the
slice flag.Args() or individually as flag.Arg(i).
The arguments are indexed from 0 through flag.NArg()-1.

The pflag package also defines some new functions that are not in flag,
that give one-letter shorthands for flags. You can use these by appending
'P' to the name of any function that defines a flag.

``` go
var ip = flag.IntP("flagname", "f", 1234, "help message")
var flagvar bool
func init() {
	flag.BoolVarP(&flagvar, "boolname", "b", true, "help message")
}
flag.VarP(&flagVal, "varname", "v", "help message")
```

Shorthand letters can be used with single dashes on the command line.
Boolean shorthand flags can be combined with other shorthand flags.

The default set of command-line flags is controlled by
top-level functions.  The FlagSet type allows one to define
independent sets of flags, such as to implement subcommands
in a command-line interface. The methods of FlagSet are
analogous to the top-level functions for the command-line
flag set.

## Setting no option default values for flags

After you create a flag it is possible to set the pflag.NoOptDefVal for
the given flag. Doing this changes the meaning of the flag slightly. If
a flag has a NoOptDefVal and the flag is set on the command line without
an option the flag will be set to the NoOptDefVal. For example given:

``` go
var ip = flag.IntP("flagname", "f", 1234, "help message")
flag.Lookup("flagname").NoOptDefVal = "4321"
```

Would result in something like

| Parsed Arguments | Resulting Value |
| -------------    | -------------   |
| --flagname=1357  | ip=1357         |
| --flagname       | ip=4321         |
| [nothing]        | ip=1234         |

## Command line flag syntax

```
--flag    // boolean flags, or flags with no option default values
--flag x  // only on flags without a default value
--flag=x
```

Unlike the flag package, a single dash before an option means something
different than a double dash. Single dashes signify a series of shorthand
letters for flags. All but the last shorthand letter must be boolean flags
or a flag with a default value

```
// boolean or flags where the 'no option default value' is set
-f
-f=true
-abc
but
-b true is INVALID

// non-boolean and flags without a 'no option default value'
-n 1234
-n=1234
-n1234

// mixed
-abcs "hello"
-absd="hello"
-abcs1234
```

Flag parsing stops after the terminator "--". Unlike the flag package,
flags can be interspersed with arguments anywhere on the command line
before this terminator.

Integer flags accept 1234, 0664, 0x1234 and may be negative.
Boolean flags (in their long form) accept 1, 0, t, f, true, false,
TRUE, FALSE, True, False.
Duration flags accept any input valid for time.ParseDuration.

## Mutating or "Normalizing" Flag names

It is possible to set a custom flag name 'normalization function.' It allows flag names to be mutated both when created in the code and when used on the command line to some 'normalized' form. The 'normalized' form is used for comparison. Two examples of using the custom normalization func follow.

**Example #1**: You want -, _, and . in flags to compare the same. aka --my-flag == --my_flag == --my.flag

``` go
func wordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName {
	from := []string{"-", "_"}
	to := "."
	for _, sep := range from {
		name = strings.Replace(name, sep, to, -1)
	}
	return pflag.NormalizedName(name)
}

myFlagSet.SetNormalizeFunc(wordSepNormalizeFunc)
```

**Example #2**: You want to alias two flags. aka --old-flag-name == --new-flag-name

``` go
func aliasNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName {
	switch name {
	case "old-flag-name":
		name = "new-flag-name"
		break
	}
	return pflag.NormalizedName(name)
}

myFlagSet.SetNormalizeFunc(aliasNormalizeFunc)
```

## Deprecating a flag or its shorthand
It is possible to deprecate a flag, or just its shorthand. Deprecating a flag/shorthand hides it from help text and prints a usage message when the deprecated flag/shorthand is used.

**Example #1**: You want to deprecate a flag named "badflag" as well as inform the users what flag they should use instead.
```go
// deprecate a flag by specifying its name and a usage message
flags.MarkDeprecated("badflag", "please use --good-flag instead")
```
This hides "badflag" from help text, and prints `Flag --badflag has been deprecated, please use --good-flag instead` when "badflag" is used.

**Example #2**: You want to keep a flag name "noshorthandflag" but deprecate its shortname "n".
```go
// deprecate a flag shorthand by specifying its flag name and a usage message
flags.MarkShorthandDeprecated("noshorthandflag", "please use --noshorthandflag only")
```
This hides the shortname "n" from help text, and prints `Flag shorthand -n has been deprecated, please use --noshorthandflag only` when the shorthand "n" is used.

Note that usage message is essential here, and it should not be empty.

## Hidden flags
It is possible to mark a flag as hidden, meaning it will still function as normal, however will not show up in usage/help text.

**Example**: You have a flag named "secretFlag" that you need for internal use only and don't want it showing up in help text, or for its usage text to be available.
```go
// hide a flag by specifying its name
flags.MarkHidden("secretFlag")
```

## Disable sorting of flags
`pflag` allows you to disable sorting of flags for help and usage message.

**Example**:
```go
flags.BoolP("verbose", "v", false, "verbose output")
flags.String("coolflag", "yeaah", "it's really cool flag")
flags.Int("usefulflag", 777, "sometimes it's very useful")
flags.SortFlags = false
flags.PrintDefaults()
```
**Output**:
```
  -v, --verbose           verbose output
      --coolflag string   it's really cool flag (default "yeaah")
      --usefulflag int    sometimes it's very useful (default 777)
```


## Supporting Go flags when using pflag
In order to support flags defined using Go's `flag` package, they must be added to the `pflag` flagset. This is usually necessary
to support flags defined by third-party dependencies (e.g. `golang/glog`).

**Example**: You want to add the Go flags to the `CommandLine` flagset
```go
import (
	goflag "flag"
	flag "github.com/spf13/pflag"
)

var ip *int = flag.Int("flagname", 1234, "help message for flagname")

func main() {
	flag.CommandLine.AddGoFlagSet(goflag.CommandLine)
	flag.Parse()
}
```

### Using pflag with go test
`pflag` does not parse the shorthand versions of go test's built-in flags (i.e., those starting with `-test.`).
For more context, see issues [#63](https://github.com/spf13/pflag/issues/63) and [#238](https://github.com/spf13/pflag/issues/238) for more details.

For example, if you use pflag in your `TestMain` function and call `pflag.Parse()` after defining your custom flags, running a test like this:
```bash
go test /your/tests -run ^YourTest -v --your-test-pflags
```
will result in the `-v` flag being ignored. This happens because of the way pflag handles flag parsing, skipping over go test's built-in shorthand flags.
To work around this, you can use the `ParseSkippedFlags` function, which ensures that go test's flags are parsed separately using the standard flag package.

**Example**: You want to parse go test flags that are otherwise ignore by `pflag.Parse()`
```go
import (
	goflag "flag"
	flag "github.com/spf13/pflag"
)

var ip *int = flag.Int("flagname", 1234, "help message for flagname")

func main() {
	flag.CommandLine.AddGoFlagSet(goflag.CommandLine)
    flag.ParseSkippedFlags(os.Args[1:], goflag.CommandLine)
	flag.Parse()
}
```

## More info

You can see the full reference documentation of the pflag package
[at godoc.org][3], or through go's standard documentation system by
running `godoc -http=:6060` and browsing to
[http://localhost:6060/pkg/github.com/spf13/pflag][2] after
installation.

[2]: http://localhost:6060/pkg/github.com/spf13/pflag
[3]: http://godoc.org/github.com/spf13/pflag

---

### Overview (`vendor/go.opentelemetry.io/otel/attribute/README.md`)

# Attribute

[](https://pkg.go.dev/go.opentelemetry.io/otel/attribute)

---

### Overview (`vendor/go.opentelemetry.io/otel/baggage/README.md`)

# Baggage

[](https://pkg.go.dev/go.opentelemetry.io/otel/baggage)

---

### Overview (`vendor/go.opentelemetry.io/otel/codes/README.md`)

# Codes

[](https://pkg.go.dev/go.opentelemetry.io/otel/codes)

---

### Overview (`vendor/go.opentelemetry.io/otel/log/README.md`)

# Log API

[](https://pkg.go.dev/go.opentelemetry.io/otel/log)

---

### Overview (`vendor/go.opentelemetry.io/otel/metric/README.md`)

# Metric API

[](https://pkg.go.dev/go.opentelemetry.io/otel/metric)

---

### Overview (`vendor/go.opentelemetry.io/otel/propagation/README.md`)

# Propagation

[](https://pkg.go.dev/go.opentelemetry.io/otel/propagation)

---

### Overview (`vendor/go.opentelemetry.io/otel/sdk/README.md`)

# SDK

[](https://pkg.go.dev/go.opentelemetry.io/otel/sdk)

---

### Overview (`vendor/go.opentelemetry.io/otel/trace/README.md`)

# Trace API

[](https://pkg.go.dev/go.opentelemetry.io/otel/trace)

---

### Overview (`vendor/go.yaml.in/yaml/v2/README.md`)

# YAML support for the Go language

Introduction
------------

The yaml package enables Go programs to comfortably encode and decode YAML
values. It was developed within [Canonical](https://www.canonical.com) as
part of the [juju](https://juju.ubuntu.com) project, and is based on a
pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML)
C library to parse and generate YAML data quickly and reliably.

Compatibility
-------------

The yaml package supports most of YAML 1.1 and 1.2, including support for
anchors, tags, map merging, etc. Multi-document unmarshalling is not yet
implemented, and base-60 floats from YAML 1.1 are purposefully not
supported since they're a poor design and are gone in YAML 1.2.

Installation and usage
----------------------

The import path for the package is *go.yaml.in/yaml/v2*.

To install it, run:

    go get go.yaml.in/yaml/v2

API documentation
-----------------

See: <https://pkg.go.dev/go.yaml.in/yaml/v2>

API stability
-------------

The package API for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in).


License
-------

The yaml package is licensed under the Apache License 2.0. Please see the LICENSE file for details.


Example
-------

```Go
package main

import (
        "fmt"
        "log"

        "go.yaml.in/yaml/v2"
)

var data = `
a: Easy!
b:
  c: 2
  d: [3, 4]
`

// Note: struct fields must be public in order for unmarshal to
// correctly populate the data.
type T struct {
        A string
        B struct {
                RenamedC int   `yaml:"c"`
                D        []int `yaml:",flow"`
        }
}

func main() {
        t := T{}
    
        err := yaml.Unmarshal([]byte(data), &t)
        if err != nil {
                log.Fatalf("error: %v", err)
        }
        fmt.Printf("--- t:\n%v\n\n", t)
    
        d, err := yaml.Marshal(&t)
        if err != nil {
                log.Fatalf("error: %v", err)
        }
        fmt.Printf("--- t dump:\n%s\n\n", string(d))
    
        m := make(map[interface{}]interface{})
    
        err = yaml.Unmarshal([]byte(data), &m)
        if err != nil {
                log.Fatalf("error: %v", err)
        }
        fmt.Printf("--- m:\n%v\n\n", m)
    
        d, err = yaml.Marshal(&m)
        if err != nil {
                log.Fatalf("error: %v", err)
        }
        fmt.Printf("--- m dump:\n%s\n\n", string(d))
}
```

This example will generate the following output:

```
--- t:
{Easy! {2 [3 4]}}

--- t dump:
a: Easy!
b:
  c: 2
  d: [3, 4]


--- m:
map[a:Easy! b:map[c:2 d:[3 4]]]

--- m dump:
a: Easy!
b:
  c: 2
  d:
  - 3
  - 4
```

---

### Overview (`vendor/go.yaml.in/yaml/v3/README.md`)

go.yaml.in/yaml
===============

YAML Support for the Go Language


## Introduction

The `yaml` package enables [Go](https://go.dev/) programs to comfortably encode
and decode [YAML](https://yaml.org/) values.

It was originally developed within [Canonical](https://www.canonical.com) as
part of the [juju](https://juju.ubuntu.com) project, and is based on a pure Go
port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) C library to
parse and generate YAML data quickly and reliably.


## Project Status

This project started as a fork of the extremely popular [go-yaml](
https://github.com/go-yaml/yaml/)
project, and is being maintained by the official [YAML organization](
https://github.com/yaml/).

The YAML team took over ongoing maintenance and development of the project after
discussion with go-yaml's author, @niemeyer, following his decision to
[label the project repository as "unmaintained"](
https://github.com/go-yaml/yaml/blob/944c86a7d2/README.md) in April 2025.

We have put together a team of dedicated maintainers including representatives
of go-yaml's most important downstream projects.

We will strive to earn the trust of the various go-yaml forks to switch back to
this repository as their upstream.

Please [contact us](https://cloud-native.slack.com/archives/C08PPAT8PS7) if you
would like to contribute or be involved.


## Compatibility

The `yaml` package supports most of YAML 1.2, but preserves some behavior from
1.1 for backwards compatibility.

Specifically, v3 of the `yaml` package:

* Supports YAML 1.1 bools (`yes`/`no`, `on`/`off`) as long as they are being
  decoded into a typed bool value.
  Otherwise they behave as a string.
  Booleans in YAML 1.2 are `true`/`false` only.
* Supports octals encoded and decoded as `0777` per YAML 1.1, rather than
  `0o777` as specified in YAML 1.2, because most parsers still use the old
  format.
  Octals in the `0o777` format are supported though, so new files work.
* Does not support base-60 floats.
  These are gone from YAML 1.2, and were actually never supported by this
  package as it's clearly a poor choice.


## Installation and Usage

The import path for the package is *go.yaml.in/yaml/v3*.

To install it, run:

```bash
go get go.yaml.in/yaml/v3
```


## API Documentation

See: <https://pkg.go.dev/go.yaml.in/yaml/v3>


## API Stability

The package API for yaml v3 will remain stable as described in [gopkg.in](
https://gopkg.in).


## Example

```go
package main

import (
	"fmt"
	"log"

	"go.yaml.in/yaml/v3"
)

var data = `
a: Easy!
b:
  c: 2
  d: [3, 4]
`

// Note: struct fields must be public in order for unmarshal to
// correctly populate the data.
type T struct {
	A string
	B struct {
		RenamedC int   `yaml:"c"`
		D	[]int `yaml:",flow"`
	}
}

func main() {
	t := T{}

	err := yaml.Unmarshal([]byte(data), &t)
	if err != nil {
		log.Fatalf("error: %v", err)
	}
	fmt.Printf("--- t:\n%v\n\n", t)

	d, err := yaml.Marshal(&t)
	if err != nil {
		log.Fatalf("error: %v", err)
	}
	fmt.Printf("--- t dump:\n%s\n\n", string(d))

	m := make(map[interface{}]interface{})

	err = yaml.Unmarshal([]byte(data), &m)
	if err != nil {
		log.Fatalf("error: %v", err)
	}
	fmt.Printf("--- m:\n%v\n\n", m)

	d, err = yaml.Marshal(&m)
	if err != nil {
		log.Fatalf("error: %v", err)
	}
	fmt.Printf("--- m dump:\n%s\n\n", string(d))
}
```

This example will generate the following output:

```
--- t:
{Easy! {2 [3 4]}}

--- t dump:
a: Easy!
b:
  c: 2
  d: [3, 4]


--- m:
map[a:Easy! b:map[c:2 d:[3 4]]]

--- m dump:
a: Easy!
b:
  c: 2
  d:
  - 3
  - 4
```


## License

The yaml package is licensed under the MIT and Apache License 2.0 licenses.
Please see the LICENSE file for details.

---

### Overview (`vendor/golang.org/x/oauth2/README.md`)

# OAuth2 for Go

[](https://pkg.go.dev/golang.org/x/oauth2)
[](https://travis-ci.org/golang/oauth2)

oauth2 package contains a client implementation for OAuth 2.0 spec.

See pkg.go.dev for further documentation and examples.

* [pkg.go.dev/golang.org/x/oauth2](https://pkg.go.dev/golang.org/x/oauth2)
* [pkg.go.dev/golang.org/x/oauth2/google](https://pkg.go.dev/golang.org/x/oauth2/google)

## Policy for new endpoints

We no longer accept new provider-specific packages in this repo if all
they do is add a single endpoint variable. If you just want to add a
single endpoint, add it to the
[pkg.go.dev/golang.org/x/oauth2/endpoints](https://pkg.go.dev/golang.org/x/oauth2/endpoints)
package.

## Report Issues / Send Patches

The main issue tracker for the oauth2 repository is located at
https://github.com/golang/oauth2/issues.

This repository uses Gerrit for code changes. To learn how to submit changes to
this repository, see https://go.dev/doc/contribute.

The git repository is https://go.googlesource.com/oauth2.

Note:

* Excluding trivial changes, all contributions should be connected to an existing issue.
* API changes must go through the [change proposal process](https://go.dev/s/proposal-process) before they can be accepted.
* The code owners are listed at [dev.golang.org/owners](https://dev.golang.org/owners#:~:text=x/oauth2).

---

### Overview (`vendor/cloud.google.com/go/compute/metadata/README.md`)

# Compute API

[](https://pkg.go.dev/cloud.google.com/go/compute/metadata)

This is a utility library for communicating with Google Cloud metadata service
on Google Cloud.

## Install

```bash
go get cloud.google.com/go/compute/metadata
```

## Go Version Support

See the [Go Versions Supported](https://github.com/googleapis/google-cloud-go#go-versions-supported)
section in the root directory's README.

## Contributing

Contributions are welcome. Please, see the [CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md)
document for details.

Please note that this project is released with a Contributor Code of Conduct.
By participating in this project you agree to abide by its terms. See
[Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md#contributor-code-of-conduct)
for more information.

---

### Overview (`vendor/github.com/alicebob/miniredis/v2/README.md`)

# Miniredis

Pure Go Redis test server, used in Go unittests.


##

Sometimes you want to test code which uses Redis, without making it a full-blown
integration test.
Miniredis implements (parts of) the Redis server, to be used in unittests. It
enables a simple, cheap, in-memory, Redis replacement, with a real TCP interface. Think of it as the Redis version of `net/http/httptest`.

It saves you from using mock code, and since the redis server lives in the
test process you can query for values directly, without going through the server
stack.

There are no dependencies on external binaries, so you can easily integrate it in automated build processes.

Be sure to import v2:
```
import "github.com/alicebob/miniredis/v2"
```

## Commands

Implemented commands:

 - Connection (complete)
   - AUTH -- see RequireAuth()
   - ECHO
   - HELLO -- see RequireUserAuth()
   - PING
   - SELECT
   - SWAPDB
   - QUIT
 - Key
   - COPY
   - DEL
   - EXISTS
   - EXPIRE
   - EXPIREAT
   - EXPIRETIME
   - KEYS
   - MOVE
   - PERSIST
   - PEXPIRE
   - PEXPIREAT
   - PEXPIRETIME
   - PTTL
   - RANDOMKEY -- see m.Seed(...)
   - RENAME
   - RENAMENX
   - SCAN
   - TOUCH
   - TTL
   - TYPE
   - UNLINK
 - Transactions (complete)
   - DISCARD
   - EXEC
   - MULTI
   - UNWATCH
   - WATCH
 - Server
   - DBSIZE
   - FLUSHALL
   - FLUSHDB
   - TIME -- returns time.Now() or value set by SetTime()
   - COMMAND -- partly
   - INFO -- partly, returns only "clients" section with one field "connected_clients"
 - String keys (complete)
   - APPEND
   - BITCOUNT
   - BITOP
   - BITPOS
   - DECR
   - DECRBY
   - GET
   - GETBIT
   - GETRANGE
   - GETSET
   - GETDEL
   - GETEX
   - INCR
   - INCRBY
   - INCRBYFLOAT
   - MGET
   - MSET
   - MSETNX
   - PSETEX
   - SET
   - SETBIT
   - SETEX
   - SETNX
   - SETRANGE
   - STRLEN
 - Hash keys (complete)
   - HDEL
   - HEXISTS
   - HGET
   - HGETALL
   - HINCRBY
   - HINCRBYFLOAT
   - HKEYS
   - HLEN
   - HMGET
   - HMSET
   - HRANDFIELD
   - HSET
   - HSETNX
   - HSTRLEN
   - HVALS
   - HSCAN
 - List keys (complete)
   - BLPOP
   - BRPOP
   - BRPOPLPUSH
   - LINDEX
   - LINSERT
   - LLEN
   - LPOP
   - LPUSH
   - LPUSHX
   - LRANGE
   - LREM
   - LSET
   - LTRIM
   - RPOP
   - RPOPLPUSH
   - RPUSH
   - RPUSHX
   - LMOVE
   - BLMOVE
 - Pub/Sub (complete)
   - PSUBSCRIBE
   - PUBLISH
   - PUBSUB
   - PUNSUBSCRIBE
   - SUBSCRIBE
   - UNSUBSCRIBE
 - Set keys (complete)
   - SADD
   - SCARD
   - SDIFF
   - SDIFFSTORE
   - SINTER
   - SINTERSTORE
   - SINTERCARD
   - SISMEMBER
   - SMEMBERS
   - SMISMEMBER
   - SMOVE
   - SPOP -- see m.Seed(...)
   - SRANDMEMBER -- see m.Seed(...)
   - SREM
   - SSCAN
   - SUNION
   - SUNIONSTORE
 - Sorted Set keys (complete)
   - ZADD
   - ZCARD
   - ZCOUNT
   - ZINCRBY
   - ZINTER
   - ZINTERSTORE
   - ZLEXCOUNT
   - ZPOPMIN
   - ZPOPMAX
   - ZRANDMEMBER
   - ZRANGE
   - ZRANGEBYLEX
   - ZRANGEBYSCORE
   - ZRANK
   - ZREM
   - ZREMRANGEBYLEX
   - ZREMRANGEBYRANK
   - ZREMRANGEBYSCORE
   - ZREVRANGE
   - ZREVRANGEBYLEX
   - ZREVRANGEBYSCORE
   - ZREVRANK
   - ZSCORE
   - ZUNION
   - ZUNIONSTORE
   - ZSCAN
 - Stream keys
   - XACK
   - XADD
   - XAUTOCLAIM
   - XCLAIM
   - XDEL
   - XGROUP CREATE
   - XGROUP CREATECONSUMER
   - XGROUP DESTROY
   - XGROUP DELCONSUMER
   - XINFO STREAM -- partly
   - XINFO GROUPS
   - XINFO CONSUMERS -- partly
   - XLEN
   - XRANGE
   - XREAD
   - XREADGROUP
   - XREVRANGE
   - XPENDING
   - XTRIM
 - Scripting
   - EVAL
   - EVALSHA
   - SCRIPT LOAD
   - SCRIPT EXISTS
   - SCRIPT FLUSH
 - GEO
   - GEOADD
   - GEODIST
   - ~~GEOHASH~~
   - GEOPOS
   - GEORADIUS
   - GEORADIUS_RO
   - GEORADIUSBYMEMBER
   - GEORADIUSBYMEMBER_RO
 - Cluster
   - CLUSTER SLOTS
   - CLUSTER KEYSLOT
   - CLUSTER NODES
 - HyperLogLog (complete)
   - PFADD
   - PFCOUNT
   - PFMERGE


## TTLs, key expiration, and time

Since miniredis is intended to be used in unittests TTLs don't decrease
automatically. You can use `TTL()` to get the TTL (as a time.Duration) of a
key. It will return 0 when no TTL is set.

`m.FastForward(d)` can be used to decrement all TTLs. All TTLs which become <=
0 will be removed.

EXPIREAT and PEXPIREAT values will be
converted to a duration. For that you can either set m.SetTime(t) to use that
time as the base for the (P)EXPIREAT conversion, or don't call SetTime(), in
which case time.Now() will be used.

SetTime() also sets the value returned by TIME, which defaults to time.Now().
It is not updated by FastForward, only by SetTime.

## Randomness and Seed()

Miniredis will use `math/rand`'s global RNG for randomness unless a seed is
provided by calling `m.Seed(...)`. If a seed is provided, then miniredis will
use its own RNG based on that seed.

Commands which use randomness are: RANDOMKEY, SPOP, and SRANDMEMBER.

## Example

``` Go

import (
    ...
    "github.com/alicebob/miniredis/v2"
    ...
)

func TestSomething(t *testing.T) {
	s := miniredis.RunT(t)

	// Optionally set some keys your code expects:
	s.Set("foo", "bar")
	s.HSet("some", "other", "key")

	// Run your code and see if it behaves.
	// An example using the redigo library from "github.com/gomodule/redigo/redis":
	c, err := redis.Dial("tcp", s.Addr())
	_, err = c.Do("SET", "foo", "bar")

	// Optionally check values in redis...
	if got, err := s.Get("foo"); err != nil || got != "bar" {
		t.Error("'foo' has the wrong value")
	}
	// ... or use a helper for that:
	s.CheckGet(t, "foo", "bar")

	// TTL and expiration:
	s.Set("foo", "bar")
	s.SetTTL("foo", 10*time.Second)
	s.FastForward(11 * time.Second)
	if s.Exists("foo") {
		t.Fatal("'foo' should not have existed anymore")
	}
}
```

## Not supported

Commands which will probably not be implemented:

 - CLUSTER (all)
    - ~~CLUSTER *~~
    - ~~READONLY~~
    - ~~READWRITE~~
 - Key
    - ~~DUMP~~
    - ~~MIGRATE~~
    - ~~OBJECT~~
    - ~~RESTORE~~
    - ~~WAIT~~
 - Scripting
    - ~~FCALL / FCALL_RO *~~
    - ~~FUNCTION *~~
    - ~~SCRIPT DEBUG~~
    - ~~SCRIPT KILL~~
 - Server
    - ~~BGSAVE~~
    - ~~BGWRITEAOF~~
    - ~~CLIENT *~~
    - ~~CONFIG *~~
    - ~~DEBUG *~~
    - ~~LASTSAVE~~
    - ~~MONITOR~~
    - ~~ROLE~~
    - ~~SAVE~~
    - ~~SHUTDOWN~~
    - ~~SLAVEOF~~
    - ~~SLOWLOG~~
    - ~~SYNC~~


## &c.

Integration tests are run against Redis 7.2.4. The [./integration](./integration/) subdir
compares miniredis against a real redis instance.

The Redis 6 RESP3 protocol is supported. If there are problems, please open
an issue.

If you want to test Redis Sentinel have a look at [minisentinel](https://github.com/Bose/minisentinel).

A changelog is kept at [CHANGELOG.md](https://github.com/alicebob/miniredis/blob/master/CHANGELOG.md).

[](https://pkg.go.dev/github.com/alicebob/miniredis/v2)

---

### Overview (`vendor/github.com/cenkalti/backoff/v5/README.md`)

# Exponential Backoff [![GoDoc][godoc image]][godoc]

This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client].

[Exponential backoff][exponential backoff wiki]
is an algorithm that uses feedback to multiplicatively decrease the rate of some process,
in order to gradually find an acceptable rate.
The retries exponentially increase and stop increasing when a certain threshold is met.

## Usage

Import path is `github.com/cenkalti/backoff/v5`. Please note the version part at the end.

For most cases, use `Retry` function. See [example_test.go][example] for an example.

If you have specific needs, copy `Retry` function (from [retry.go][retry-src]) into your code and modify it as needed.

## Contributing

* I would like to keep this library as small as possible.
* Please don't send a PR without opening an issue and discussing it first.
* If proposed change is not a common use case, I will probably not accept it.

[godoc]: https://pkg.go.dev/github.com/cenkalti/backoff/v5
[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png

[google-http-java-client]: https://github.com/google/google-http-java-client/blob/da1aa993e90285ec18579f1553339b00e19b3ab5/google-http-client/src/main/java/com/google/api/client/util/ExponentialBackOff.java
[exponential backoff wiki]: http://en.wikipedia.org/wiki/Exponential_backoff

[retry-src]: https://github.com/cenkalti/backoff/blob/v5/retry.go
[example]: https://github.com/cenkalti/backoff/blob/v5/example_test.go

---

### Overview (`vendor/github.com/cespare/xxhash/v2/README.md`)

# xxhash

[](https://pkg.go.dev/github.com/cespare/xxhash/v2)
[](https://github.com/cespare/xxhash/actions/workflows/test.yml)

xxhash is a Go implementation of the 64-bit [xxHash] algorithm, XXH64. This is a
high-quality hashing algorithm that is much faster than anything in the Go
standard library.

This package provides a straightforward API:

```
func Sum64(b []byte) uint64
func Sum64String(s string) uint64
type Digest struct{ ... }
    func New() *Digest
```

The `Digest` type implements hash.Hash64. Its key methods are:

```
func (*Digest) Write([]byte) (int, error)
func (*Digest) WriteString(string) (int, error)
func (*Digest) Sum64() uint64
```

The package is written with optimized pure Go and also contains even faster
assembly implementations for amd64 and arm64. If desired, the `purego` build tag
opts into using the Go code even on those architectures.

[xxHash]: http://cyan4973.github.io/xxHash/

## Compatibility

This package is in a module and the latest code is in version 2 of the module.
You need a version of Go with at least "minimal module compatibility" to use
github.com/cespare/xxhash/v2:

* 1.9.7+ for Go 1.9
* 1.10.3+ for Go 1.10
* Go 1.11 or later

I recommend using the latest release of Go.

## Benchmarks

Here are some quick benchmarks comparing the pure-Go and assembly
implementations of Sum64.

| input size | purego    | asm       |
| ---------- | --------- | --------- |
| 4 B        |  1.3 GB/s |  1.2 GB/s |
| 16 B       |  2.9 GB/s |  3.5 GB/s |
| 100 B      |  6.9 GB/s |  8.1 GB/s |
| 4 KB       | 11.7 GB/s | 16.7 GB/s |
| 10 MB      | 12.0 GB/s | 17.3 GB/s |

These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C
CPU using the following commands under Go 1.19.2:

```
benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$')
benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')
```

## Projects using this package

- [InfluxDB](https://github.com/influxdata/influxdb)
- [Prometheus](https://github.com/prometheus/prometheus)
- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
- [FreeCache](https://github.com/coocood/freecache)
- [FastCache](https://github.com/VictoriaMetrics/fastcache)
- [Ristretto](https://github.com/dgraph-io/ristretto)
- [Badger](https://github.com/dgraph-io/badger)

---

### Overview (`vendor/github.com/go-jose/go-jose/v4/README.md`)

# Go JOSE

[](https://pkg.go.dev/github.com/go-jose/go-jose/v4)
[](https://pkg.go.dev/github.com/go-jose/go-jose/v4/jwt)
[](https://raw.githubusercontent.com/go-jose/go-jose/master/LICENSE)

Package jose aims to provide an implementation of the Javascript Object Signing
and Encryption set of standards. This includes support for JSON Web Encryption,
JSON Web Signature, and JSON Web Token standards.

## Overview

The implementation follows the
[JSON Web Encryption](https://dx.doi.org/10.17487/RFC7516) (RFC 7516),
[JSON Web Signature](https://dx.doi.org/10.17487/RFC7515) (RFC 7515), and
[JSON Web Token](https://dx.doi.org/10.17487/RFC7519) (RFC 7519) specifications.
Tables of supported algorithms are shown below. The library supports both
the compact and JWS/JWE JSON Serialization formats, and has optional support for
multiple recipients. It also comes with a small command-line utility
([`jose-util`](https://pkg.go.dev/github.com/go-jose/go-jose/jose-util))
for dealing with JOSE messages in a shell.

**Note**: We use a forked version of the `encoding/json` package from the Go
standard library which uses case-sensitive matching for member names (instead
of [case-insensitive matching](https://www.ietf.org/mail-archive/web/json/current/msg03763.html)).
This is to avoid differences in interpretation of messages between go-jose and
libraries in other languages.

### Versions

The forthcoming Version 5 will be released with several breaking API changes,
and will require Golang's `encoding/json/v2`, which is currently requires 
Go 1.25 built with GOEXPERIMENT=jsonv2.

Version 4 is the current stable version:

    import "github.com/go-jose/go-jose/v4"

It supports at least the current and previous Golang release. Currently it
requires Golang 1.24.

Version 3 is only receiving critical security updates. Migration to Version 4 is recommended.

Versions 1 and 2 are obsolete, but can be found in the old repository, [square/go-jose](https://github.com/square/go-jose).

### Supported algorithms

See below for a table of supported algorithms. Algorithm identifiers match
the names in the [JSON Web Algorithms](https://dx.doi.org/10.17487/RFC7518)
standard where possible. The Godoc reference has a list of constants.

| Key encryption         | Algorithm identifier(s)                        |
|:-----------------------|:-----------------------------------------------|
| RSA-PKCS#1v1.5         | RSA1_5                                         |
| RSA-OAEP               | RSA-OAEP, RSA-OAEP-256                         |
| AES key wrap           | A128KW, A192KW, A256KW                         |
| AES-GCM key wrap       | A128GCMKW, A192GCMKW, A256GCMKW                |
| ECDH-ES + AES key wrap | ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW |
| ECDH-ES (direct)       | ECDH-ES<sup>1</sup>                            |
| Direct encryption      | dir<sup>1</sup>                                |

<sup>1. Not supported in multi-recipient mode</sup>

| Signing / MAC     | Algorithm identifier(s) |
|:------------------|:------------------------|
| RSASSA-PKCS#1v1.5 | RS256, RS384, RS512     |
| RSASSA-PSS        | PS256, PS384, PS512     |
| HMAC              | HS256, HS384, HS512     |
| ECDSA             | ES256, ES384, ES512     |
| Ed25519           | EdDSA<sup>2</sup>       |

<sup>2. Only available in version 2 of the package</sup>

| Content encryption | Algorithm identifier(s)                     |
|:-------------------|:--------------------------------------------|
| AES-CBC+HMAC       | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 |
| AES-GCM            | A128GCM, A192GCM, A256GCM                   |

| Compression        | Algorithm identifiers(s) |
|:-------------------|--------------------------|
| DEFLATE (RFC 1951) | DEF                      |

### Supported key types

See below for a table of supported key types. These are understood by the
library, and can be passed to corresponding functions such as `NewEncrypter` or
`NewSigner`. Each of these keys can also be wrapped in a JWK if desired, which
allows attaching a key id.

| Algorithm(s)      | Corresponding types                                                                                                                  |
|:------------------|--------------------------------------------------------------------------------------------------------------------------------------|
| RSA               | *[rsa.PublicKey](https://pkg.go.dev/crypto/rsa/#PublicKey), *[rsa.PrivateKey](https://pkg.go.dev/crypto/rsa/#PrivateKey)             |
| ECDH, ECDSA       | *[ecdsa.PublicKey](https://pkg.go.dev/crypto/ecdsa/#PublicKey), *[ecdsa.PrivateKey](https://pkg.go.dev/crypto/ecdsa/#PrivateKey)     |
| EdDSA<sup>1</sup> | [ed25519.PublicKey](https://pkg.go.dev/crypto/ed25519#PublicKey), [ed25519.PrivateKey](https://pkg.go.dev/crypto/ed25519#PrivateKey) |
| AES, HMAC         | []byte                                                                                                                               |

<sup>1. Only available in version 2 or later of the package</sup>

## Examples

[](https://pkg.go.dev/github.com/go-jose/go-jose/v4)
[](https://pkg.go.dev/github.com/go-jose/go-jose/v4/jwt)

Examples can be found in the Godoc
reference for this package. The
[`jose-util`](https://github.com/go-jose/go-jose/tree/main/jose-util)
subdirectory also contains a small command-line utility which might be useful
as an example as well.

---

### Overview (`vendor/github.com/golang-jwt/jwt/v5/README.md`)

# jwt-go

[](https://github.com/golang-jwt/jwt/actions/workflows/build.yml)
[![Go
Reference](https://pkg.go.dev/badge/github.com/golang-jwt/jwt/v5.svg)](https://pkg.go.dev/github.com/golang-jwt/jwt/v5)
[](https://coveralls.io/github/golang-jwt/jwt?branch=main)

A [go](http://www.golang.org) (or 'golang' for search engine friendliness)
implementation of [JSON Web
Tokens](https://datatracker.ietf.org/doc/html/rfc7519).

Starting with [v4.0.0](https://github.com/golang-jwt/jwt/releases/tag/v4.0.0)
this project adds Go module support, but maintains backward compatibility with
older `v3.x.y` tags and upstream `github.com/dgrijalva/jwt-go`. See the
[`MIGRATION_GUIDE.md`](./MIGRATION_GUIDE.md) for more information. Version
v5.0.0 introduces major improvements to the validation of tokens, but is not
entirely backward compatible. 

> After the original author of the library suggested migrating the maintenance
> of `jwt-go`, a dedicated team of open source maintainers decided to clone the
> existing library into this repository. See
> [dgrijalva/jwt-go#462](https://github.com/dgrijalva/jwt-go/issues/462) for a
> detailed discussion on this topic.


**SECURITY NOTICE:** Some older versions of Go have a security issue in the
crypto/elliptic. The recommendation is to upgrade to at least 1.15 See issue
[dgrijalva/jwt-go#216](https://github.com/dgrijalva/jwt-go/issues/216) for more
detail.

**SECURITY NOTICE:** It's important that you [validate the `alg` presented is
what you
expect](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/).
This library attempts to make it easy to do the right thing by requiring key
types to match the expected alg, but you should take the extra step to verify it in
your usage.  See the examples provided.

### Supported Go versions

Our support of Go versions is aligned with Go's [version release
policy](https://golang.org/doc/devel/release#policy). So we will support a major
version of Go until there are two newer major releases. We no longer support
building jwt-go with unsupported Go versions, as these contain security
vulnerabilities that will not be fixed.

## What the heck is a JWT?

JWT.io has [a great introduction](https://jwt.io/introduction) to JSON Web
Tokens.

In short, it's a signed JSON object that does something useful (for example,
authentication).  It's commonly used for `Bearer` tokens in Oauth 2.  A token is
made of three parts, separated by `.`'s.  The first two parts are JSON objects,
that have been [base64url](https://datatracker.ietf.org/doc/html/rfc4648)
encoded.  The last part is the signature, encoded the same way.

The first part is called the header.  It contains the necessary information for
verifying the last part, the signature.  For example, which encryption method
was used for signing and what key was used.

The part in the middle is the interesting bit.  It's called the Claims and
contains the actual stuff you care about.  Refer to [RFC
7519](https://datatracker.ietf.org/doc/html/rfc7519) for information about
reserved keys and the proper way to add your own.

## What's in the box?

This library supports the parsing and verification as well as the generation and
signing of JWTs.  Current supported signing algorithms are HMAC SHA, RSA,
RSA-PSS, and ECDSA, though hooks are present for adding your own.

## Installation Guidelines

1. To install the jwt package, you first need to have
   [Go](https://go.dev/doc/install) installed, then you can use the command
   below to add `jwt-go` as a dependency in your Go program.

```sh
go get -u github.com/golang-jwt/jwt/v5
```

2. Import it in your code:

```go
import "github.com/golang-jwt/jwt/v5"
```

## Usage

A detailed usage guide, including how to sign and verify tokens can be found on
our [documentation website](https://golang-jwt.github.io/jwt/usage/create/).

## Examples

See [the project documentation](https://pkg.go.dev/github.com/golang-jwt/jwt/v5)
for examples of usage:

* [Simple example of parsing and validating a
  token](https://pkg.go.dev/github.com/golang-jwt/jwt/v5#example-Parse-Hmac)
* [Simple example of building and signing a
  token](https://pkg.go.dev/github.com/golang-jwt/jwt/v5#example-New-Hmac)
* [Directory of
  Examples](https://pkg.go.dev/github.com/golang-jwt/jwt/v5#pkg-examples)

## Compliance

This library was last reviewed to comply with [RFC
7519](https://datatracker.ietf.org/doc/html/rfc7519) dated May 2015 with a few
notable differences:

* In order to protect against accidental use of [Unsecured
  JWTs](https://datatracker.ietf.org/doc/html/rfc7519#section-6), tokens using
  `alg=none` will only be accepted if the constant
  `jwt.UnsafeAllowNoneSignatureType` is provided as the key.

## Project Status & Versioning

This library is considered production ready.  Feedback and feature requests are
appreciated.  The API should be considered stable.  There should be very few
backward-incompatible changes outside of major version updates (and only with
good reason).

This project uses [Semantic Versioning 2.0.0](http://semver.org).  Accepted pull
requests will land on `main`.  Periodically, versions will be tagged from
`main`.  You can find all the releases on [the project releases
page](https://github.com/golang-jwt/jwt/releases).

**BREAKING CHANGES:** A full list of breaking changes is available in
`VERSION_HISTORY.md`.  See [`MIGRATION_GUIDE.md`](./MIGRATION_GUIDE.md) for more information on updating
your code.

## Extensions

This library publishes all the necessary components for adding your own signing
methods or key functions.  Simply implement the `SigningMethod` interface and
register a factory method using `RegisterSigningMethod` or provide a
`jwt.Keyfunc`.

A common use case would be integrating with different 3rd party signature
providers, like key management services from various cloud providers or Hardware
Security Modules (HSMs) or to implement additional standards.

| Extension | Purpose                                                                                                  | Repo                                       |
| --------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
| GCP       | Integrates with multiple Google Cloud Platform signing tools (AppEngine, IAM API, Cloud KMS)             | https://github.com/someone1/gcp-jwt-go     |
| AWS       | Integrates with AWS Key Management Service, KMS                                                          | https://github.com/matelang/jwt-go-aws-kms |
| JWKS      | Provides support for JWKS ([RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517)) as a `jwt.Keyfunc` | https://github.com/MicahParks/keyfunc      |

*Disclaimer*: Unless otherwise specified, these integrations are maintained by
third parties and should not be considered as a primary offer by any of the
mentioned cloud providers

## More

Go package documentation can be found [on
pkg.go.dev](https://pkg.go.dev/github.com/golang-jwt/jwt/v5). Additional
documentation can be found on [our project
page](https://golang-jwt.github.io/jwt/).

The command line utility included in this project (cmd/jwt) provides a
straightforward example of token creation and parsing as well as a useful tool
for debugging your own integration. You'll also find several implementation
examples in the documentation.

[golang-jwt](https://github.com/orgs/golang-jwt) incorporates a modified version
of the JWT logo, which is distributed under the terms of the [MIT
License](https://github.com/jsonwebtoken/jsonwebtoken.github.io/blob/master/LICENSE.txt).

---

### Overview (`vendor/github.com/klauspost/compress/fse/README.md`)

# Finite State Entropy

This package provides Finite State Entropy encoding and decoding.
            
Finite State Entropy (also referenced as [tANS](https://en.wikipedia.org/wiki/Asymmetric_numeral_systems#tANS)) 
encoding provides a fast near-optimal symbol encoding/decoding
for byte blocks as implemented in [zstandard](https://github.com/facebook/zstd).

This can be used for compressing input with a lot of similar input values to the smallest number of bytes.
This does not perform any multi-byte [dictionary coding](https://en.wikipedia.org/wiki/Dictionary_coder) as LZ coders,
but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding. 

* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/fse)

## News

 * Feb 2018: First implementation released. Consider this beta software for now.

# Usage

This package provides a low level interface that allows to compress single independent blocks. 

Each block is separate, and there is no built in integrity checks. 
This means that the caller should keep track of block sizes and also do checksums if needed.  

Compressing a block is done via the [`Compress`](https://godoc.org/github.com/klauspost/compress/fse#Compress) function.
You must provide input and will receive the output and maybe an error.

These error values can be returned:

| Error               | Description                                                                 |
|---------------------|-----------------------------------------------------------------------------|
| `<nil>`             | Everything ok, output is returned                                           |
| `ErrIncompressible` | Returned when input is judged to be too hard to compress                    |
| `ErrUseRLE`         | Returned from the compressor when the input is a single byte value repeated |
| `(error)`           | An internal error occurred.                                                 |

As can be seen above there are errors that will be returned even under normal operation so it is important to handle these.

To reduce allocations you can provide a [`Scratch`](https://godoc.org/github.com/klauspost/compress/fse#Scratch) object 
that can be re-used for successive calls. Both compression and decompression accepts a `Scratch` object, and the same 
object can be used for both.   

Be aware, that when re-using a `Scratch` object that the *output* buffer is also re-used, so if you are still using this
you must set the `Out` field in the scratch to nil. The same buffer is used for compression and decompression output.

Decompressing is done by calling the [`Decompress`](https://godoc.org/github.com/klauspost/compress/fse#Decompress) function.
You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
your input was likely corrupted. 

It is important to note that a successful decoding does *not* mean your output matches your original input. 
There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.

For more detailed usage, see examples in the [godoc documentation](https://godoc.org/github.com/klauspost/compress/fse#pkg-examples).

# Performance

A lot of factors are affecting speed. Block sizes and compressibility of the material are primary factors.  
All compression functions are currently only running on the calling goroutine so only one core will be used per block.  

The compressor is significantly faster if symbols are kept as small as possible. The highest byte value of the input
is used to reduce some of the processing, so if all your input is above byte value 64 for instance, it may be 
beneficial to transpose all your input values down by 64.   

With moderate block sizes around 64k speed are typically 200MB/s per core for compression and 
around 300MB/s decompression speed. 

The same hardware typically does Huffman (deflate) encoding at 125MB/s and decompression at 100MB/s. 

# Plans

At one point, more internals will be exposed to facilitate more "expert" usage of the components. 

A streaming interface is also likely to be implemented. Likely compatible with [FSE stream format](https://github.com/Cyan4973/FiniteStateEntropy/blob/dev/programs/fileio.c#L261).  

# Contributing

Contributions are always welcome. Be aware that adding public functions will require good justification and breaking 
changes will likely not be accepted. If in doubt open an issue before writing the PR.

---

### Overview (`vendor/github.com/klauspost/compress/huff0/README.md`)

# Huff0 entropy compression

This package provides Huff0 encoding and decoding as used in zstd.
            
[Huff0](https://github.com/Cyan4973/FiniteStateEntropy#new-generation-entropy-coders), 
a Huffman codec designed for modern CPU, featuring OoO (Out of Order) operations on multiple ALU 
(Arithmetic Logic Unit), achieving extremely fast compression and decompression speeds.

This can be used for compressing input with a lot of similar input values to the smallest number of bytes.
This does not perform any multi-byte [dictionary coding](https://en.wikipedia.org/wiki/Dictionary_coder) as LZ coders,
but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding. 

* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/huff0)

## News

This is used as part of the [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and decompression package.

This ensures that most functionality is well tested.

# Usage

This package provides a low level interface that allows to compress single independent blocks. 

Each block is separate, and there is no built in integrity checks. 
This means that the caller should keep track of block sizes and also do checksums if needed.  

Compressing a block is done via the [`Compress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Compress1X) and 
[`Compress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Compress4X) functions.
You must provide input and will receive the output and maybe an error.

These error values can be returned:

| Error               | Description                                                                 |
|---------------------|-----------------------------------------------------------------------------|
| `<nil>`             | Everything ok, output is returned                                           |
| `ErrIncompressible` | Returned when input is judged to be too hard to compress                    |
| `ErrUseRLE`         | Returned from the compressor when the input is a single byte value repeated |
| `ErrTooBig`         | Returned if the input block exceeds the maximum allowed size (128 Kib)      |
| `(error)`           | An internal error occurred.                                                 |


As can be seen above some of there are errors that will be returned even under normal operation so it is important to handle these.

To reduce allocations you can provide a [`Scratch`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch) object 
that can be re-used for successive calls. Both compression and decompression accepts a `Scratch` object, and the same 
object can be used for both.   

Be aware, that when re-using a `Scratch` object that the *output* buffer is also re-used, so if you are still using this
you must set the `Out` field in the scratch to nil. The same buffer is used for compression and decompression output.

The `Scratch` object will retain state that allows to re-use previous tables for encoding and decoding.  

## Tables and re-use

Huff0 allows for reusing tables from the previous block to save space if that is expected to give better/faster results. 

The Scratch object allows you to set a [`ReusePolicy`](https://godoc.org/github.com/klauspost/compress/huff0#ReusePolicy) 
that controls this behaviour. See the documentation for details. This can be altered between each block.

Do however note that this information is *not* stored in the output block and it is up to the users of the package to
record whether [`ReadTable`](https://godoc.org/github.com/klauspost/compress/huff0#ReadTable) should be called,
based on the boolean reported back from the CompressXX call. 

If you want to store the table separate from the data, you can access them as `OutData` and `OutTable` on the 
[`Scratch`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch) object.

## Decompressing

The first part of decoding is to initialize the decoding table through [`ReadTable`](https://godoc.org/github.com/klauspost/compress/huff0#ReadTable).
This will initialize the decoding tables. 
You can supply the complete block to `ReadTable` and it will return the data part of the block 
which can be given to the decompressor. 

Decompressing is done by calling the [`Decompress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress1X) 
or [`Decompress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress4X) function.

For concurrently decompressing content with a fixed table a stateless [`Decoder`](https://godoc.org/github.com/klauspost/compress/huff0#Decoder) can be requested which will remain correct as long as the scratch is unchanged. The capacity of the provided slice indicates the expected output size.

You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
your input was likely corrupted. 

It is important to note that a successful decoding does *not* mean your output matches your original input. 
There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.

# Contributing

Contributions are always welcome. Be aware that adding public functions will require good justification and breaking 
changes will likely not be accepted. If in doubt open an issue before writing the PR.

---

### Overview (`vendor/github.com/klauspost/compress/zstd/README.md`)

# zstd 

[Zstandard](https://facebook.github.io/zstd/) is a real-time compression algorithm, providing high compression ratios. 
It offers a very wide range of compression / speed trade-off, while being backed by a very fast decoder.
A high performance compression algorithm is implemented. For now focused on speed. 

This package provides [compression](#Compressor) to and [decompression](#Decompressor) of Zstandard content. 

This package is pure Go. Use `noasm` and `nounsafe` to disable relevant features.

The `zstd` package is provided as open source software using a Go standard license.

Currently the package is heavily optimized for 64 bit processors and will be significantly slower on 32 bit processors.

For seekable zstd streams, see [this excellent package](https://github.com/SaveTheRbtz/zstd-seekable-format-go).

## Installation

Install using `go get -u github.com/klauspost/compress`. The package is located in `github.com/klauspost/compress/zstd`.

[](https://pkg.go.dev/github.com/klauspost/compress/zstd)

## Compressor

### Status: 

STABLE - there may always be subtle bugs, a wide variety of content has been tested and the library is actively 
used by several projects. This library is being [fuzz-tested](https://github.com/klauspost/compress-fuzz) for all updates.

There may still be specific combinations of data types/size/settings that could lead to edge cases, 
so as always, testing is recommended.  

For now, a high speed (fastest) and medium-fast (default) compressor has been implemented. 

* The "Fastest" compression ratio is roughly equivalent to zstd level 1. 
* The "Default" compression ratio is roughly equivalent to zstd level 3 (default).
* The "Better" compression ratio is roughly equivalent to zstd level 7.
* The "Best" compression ratio is roughly equivalent to zstd level 11.

In terms of speed, it is typically 2x as fast as the stdlib deflate/gzip in its fastest mode. 
The compression ratio compared to stdlib is around level 3, but usually 3x as fast.

 
### Usage

An Encoder can be used for either compressing a stream via the
`io.WriteCloser` interface supported by the Encoder or as multiple independent
tasks via the `EncodeAll` function.
Smaller encodes are encouraged to use the EncodeAll function.
Use `NewWriter` to create a new instance that can be used for both.

To create a writer with default options, do like this:

```Go
// Compress input to output.
func Compress(in io.Reader, out io.Writer) error {
    enc, err := zstd.NewWriter(out)
    if err != nil {
        return err
    }
    _, err = io.Copy(enc, in)
    if err != nil {
        enc.Close()
        return err
    }
    return enc.Close()
}
```

Now you can encode by writing data to `enc`. The output will be finished writing when `Close()` is called.
Even if your encode fails, you should still call `Close()` to release any resources that may be held up.  

The above is fine for big encodes. However, whenever possible try to *reuse* the writer.

To reuse the encoder, you can use the `Reset(io.Writer)` function to change to another output. 
This will allow the encoder to reuse all resources and avoid wasteful allocations. 

Currently stream encoding has 'light' concurrency, meaning up to 2 goroutines can be working on part 
of a stream. This is independent of the `WithEncoderConcurrency(n)`, but that is likely to change 
in the future. So if you want to limit concurrency for future updates, specify the concurrency
you would like.

If you would like stream encoding to be done without spawning async goroutines, use `WithEncoderConcurrency(1)`
which will compress input as each block is completed, blocking on writes until each has completed.

You can specify your desired compression level using `WithEncoderLevel()` option. Currently only pre-defined 
compression settings can be specified.

#### Future Compatibility Guarantees

This will be an evolving project. When using this package it is important to note that both the compression efficiency and speed may change.

The goal will be to keep the default efficiency at the default zstd (level 3). 
However the encoding should never be assumed to remain the same, 
and you should not use hashes of compressed output for similarity checks.

The Encoder can be assumed to produce the same output from the exact same code version.
However, the may be modes in the future that break this, 
although they will not be enabled without an explicit option.   

This encoder is not designed to (and will probably never) output the exact same bitstream as the reference encoder.

Also note, that the cgo decompressor currently does not [report all errors on invalid input](https://github.com/DataDog/zstd/issues/59),
[omits error checks](https://github.com/DataDog/zstd/issues/61), [ignores checksums](https://github.com/DataDog/zstd/issues/43) 
and seems to ignore concatenated streams, even though [it is part of the spec](https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#frames).

#### Blocks

For compressing small blocks, the returned encoder has a function called `EncodeAll(src, dst []byte) []byte`.

`EncodeAll` will encode all input in src and append it to dst.
This function can be called concurrently. 
Each call will only run on a same goroutine as the caller.

Encoded blocks can be concatenated and the result will be the combined input stream.
Data compressed with EncodeAll can be decoded with the Decoder, using either a stream or `DecodeAll`.

Especially when encoding blocks you should take special care to reuse the encoder. 
This will effectively make it run without allocations after a warmup period. 
To make it run completely without allocations, supply a destination buffer with space for all content.   

```Go
import "github.com/klauspost/compress/zstd"

// Create a writer that caches compressors.
// For this operation type we supply a nil Reader.
var encoder, _ = zstd.NewWriter(nil)

// Compress a buffer. 
// If you have a destination buffer, the allocation in the call can also be eliminated.
func Compress(src []byte) []byte {
    return encoder.EncodeAll(src, make([]byte, 0, len(src)))
} 
```

You can control the maximum number of concurrent encodes using the `WithEncoderConcurrency(n)` 
option when creating the writer.

Using the Encoder for both a stream and individual blocks concurrently is safe. 

### Performance

I have collected some speed examples to compare speed and compression against other compressors.

* `file` is the input file.
* `out` is the compressor used. `zskp` is this package. `zstd` is the Datadog cgo library. `gzstd/gzkp` is gzip standard and this library.
* `level` is the compression level used. For `zskp` level 1 is "fastest", level 2 is "default"; 3 is "better", 4 is "best".
* `insize`/`outsize` is the input/output size.
* `millis` is the number of milliseconds used for compression.
* `mb/s` is megabytes (2^20 bytes) per second.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Decompressor

Status: STABLE - there may still be subtle bugs, but a wide variety of content has been tested.

This library is being continuously [fuzz-tested](https://github.com/klauspost/compress-fuzz),
kindly supplied by [fuzzit.dev](https://fuzzit.dev/). 
The main purpose of the fuzz testing is to ensure that it is not possible to crash the decoder, 
or run it past its limits with ANY input provided.  
 
### Usage

The package has been designed for two main usages, big streams of data and smaller in-memory buffers. 
There are two main usages of the package for these. Both of them are accessed by creating a `Decoder`.

For streaming use a simple setup could look like this:

```Go
import "github.com/klauspost/compress/zstd"

func Decompress(in io.Reader, out io.Writer) error {
    d, err := zstd.NewReader(in)
    if err != nil {
        return err
    }
    defer d.Close()
    
    // Copy content...
    _, err = io.Copy(out, d)
    return err
}
```

It is important to use the "Close" function when you no longer need the Reader to stop running goroutines, 
when running with default settings.
Goroutines will exit once an error has been returned, including `io.EOF` at the end of a stream.

Streams are decoded concurrently in 4 asynchronous stages to give the best possible throughput.
However, if you prefer synchronous decompression, use `WithDecoderConcurrency(1)` which will decompress data 
as it is being requested only.

For decoding buffers, it could look something like this:

```Go
import "github.com/klauspost/compress/zstd"

// Create a reader that caches decompressors.
// For this operation type we supply a nil Reader.
var decoder, _ = zstd.NewReader(nil, zstd.WithDecoderConcurrency(0))

// Decompress a buffer. We don't supply a destination buffer,
// so it will be allocated by the decoder.
func Decompress(src []byte) ([]byte, error) {
    return decoder.DecodeAll(src, nil)
} 
```

Both of these cases should provide the functionality needed. 
The decoder can be used for *concurrent* decompression of multiple buffers.
By default 4 decompressors will be created. 

It will only allow a certain number of concurrent operations to run. 
To tweak that yourself use the `WithDecoderConcurrency(n)` option when creating the decoder.
It is possible to use `WithDecoderConcurrency(0)` to create GOMAXPROCS decoders.

### Dictionaries

Data compressed with [dictionaries](https://github.com/facebook/zstd#the-case-for-small-data-compression) can be decompressed.

Dictionaries are added individually to Decoders.
Dictionaries are generated by the `zstd --train` command and contains an initial state for the decoder.
To add a dictionary use the `WithDecoderDicts(dicts ...[]byte)` option with the dictionary data.
Several dictionaries can be added at once.

The dictionary will be used automatically for the data that specifies them.
A re-used Decoder will still contain the dictionaries registered.

When registering multiple dictionaries with the same ID, the last one will be used.

It is possible to use dictionaries when compressing data.

To enable a dictionary use `WithEncoderDict(dict []byte)`. Here only one dictionary will be used 
and it will likely be used even if it doesn't improve compression. 

The used dictionary must be used to decompress the content.

For any real gains, the dictionary should be built with similar data. 
If an unsuitable dictionary is used the output may be slightly larger than using no dictionary.
Use the [zstd commandline tool](https://github.com/facebook/zstd/releases) to build a dictionary from sample data.
For information see [zstd dictionary information](https://github.com/facebook/zstd#the-case-for-small-data-compression). 

For now there is a fixed startup performance penalty for compressing content with dictionaries. 
This will likely be improved over time. Just be aware to test performance when implementing.  

### Allocation-less operation

The decoder has been designed to operate without allocations after a warmup. 

This means that you should *store* the decoder for best performance. 
To re-use a stream decoder, use the `Reset(r io.Reader) error` to switch to another stream.
A decoder can safely be re-used even if the previous stream failed.

To release the resources, you must call the `Close()` function on a decoder.
After this it can *no longer be reused*, but all running goroutines will be stopped.
So you *must* use this if you will no longer need the Reader.

For decompressing smaller buffers a single decoder can be used.
When decoding buffers, you can supply a destination slice with length 0 and your expected capacity.
In this case no unneeded allocations should be made. 

### Concurrency

The buffer decoder does everything on the same goroutine and does nothing concurrently.
It can however decode several buffers concurrently. Use `WithDecoderConcurrency(n)` to limit that.

The stream decoder will create goroutines that:

1) Reads input and splits the input into blocks.
2) Decompression of literals.
3) Decompression of sequences.
4) Reconstruction of output stream.

So effectively this also means the decoder will "read ahead" and prepare data to always be available for output.

The concurrency level will, for streams, determine how many blocks ahead the compression will start.

Since "blocks" are quite dependent on the output of the previous block stream decoding will only have limited concurrency.

In practice this means that concurrency is often limited to utilizing about 3 cores effectively.
  
### Benchmarks

The first two are streaming decodes and the last are smaller inputs. 

Running on AMD Ryzen 9 3950X 16-Core Processor. AMD64 assembly used.

```
/* Detailed source-code truncated for AI context efficiency. */
```

This reflects the performance around May 2022, but this may be out of date.

## Zstd inside ZIP files

It is possible to use zstandard to compress individual files inside zip archives.
While this isn't widely supported it can be useful for internal files.

To support the compression and decompression of these files you must register a compressor and decompressor.

It is highly recommended registering the (de)compressors on individual zip Reader/Writer and NOT
use the global registration functions. The main reason for this is that 2 registrations from 
different packages will result in a panic.

It is a good idea to only have a single compressor and decompressor, since they can be used for multiple zip
files concurrently, and using a single instance will allow reusing some resources.

See [this example](https://pkg.go.dev/github.com/klauspost/compress/zstd#example-ZipCompressor) for 
how to compress and decompress files inside zip archives.

# Contributions

Contributions are always welcome. 
For new features/fixes, remember to add tests and for performance enhancements include benchmarks.

For general feedback and experience reports, feel free to open an issue or write me on [Twitter](https://twitter.com/sh0dan).

This package includes the excellent [`github.com/cespare/xxhash`](https://github.com/cespare/xxhash) package Copyright (c) 2016 Caleb Spare.

---

### Overview (`vendor/github.com/prometheus/client_golang/prometheus/README.md`)

See [](https://pkg.go.dev/github.com/prometheus/client_golang/prometheus).

---

### Overview (`vendor/github.com/redis/go-redis/v9/README.md`)

# Redis client for Go

[](https://github.com/redis/go-redis/actions)
[](https://pkg.go.dev/github.com/redis/go-redis/v9?tab=doc)
[](https://redis.uptrace.dev/)
[](https://codecov.io/github/redis/go-redis)
[](https://discord.gg/rWtp5Aj)

> go-redis is brought to you by :star: [**uptrace/uptrace**](https://github.com/uptrace/uptrace).
> Uptrace is an open-source APM tool that supports distributed tracing, metrics, and logs. You can
> use it to monitor applications and set up automatic alerts to receive notifications via email,
> Slack, Telegram, and others.
>
> See [OpenTelemetry](https://github.com/redis/go-redis/tree/master/example/otel) example which
> demonstrates how you can use Uptrace to monitor go-redis.

## How do I Redis?

[Learn for free at Redis University](https://university.redis.com/)

[Build faster with the Redis Launchpad](https://launchpad.redis.com/)

[Try the Redis Cloud](https://redis.com/try-free/)

[Dive in developer tutorials](https://developer.redis.com/)

[Join the Redis community](https://redis.com/community/)

[Work at Redis](https://redis.com/company/careers/jobs/)

## Documentation

- [English](https://redis.uptrace.dev)
- [简体中文](https://redis.uptrace.dev/zh/)

## Resources

- [Discussions](https://github.com/redis/go-redis/discussions)
- [Chat](https://discord.gg/rWtp5Aj)
- [Reference](https://pkg.go.dev/github.com/redis/go-redis/v9)
- [Examples](https://pkg.go.dev/github.com/redis/go-redis/v9#pkg-examples)

## Ecosystem

- [Redis Mock](https://github.com/go-redis/redismock)
- [Distributed Locks](https://github.com/bsm/redislock)
- [Redis Cache](https://github.com/go-redis/cache)
- [Rate limiting](https://github.com/go-redis/redis_rate)

This client also works with [Kvrocks](https://github.com/apache/incubator-kvrocks), a distributed
key value NoSQL database that uses RocksDB as storage engine and is compatible with Redis protocol.

## Features

- Redis commands except QUIT and SYNC.
- Automatic connection pooling.
- [Pub/Sub](https://redis.uptrace.dev/guide/go-redis-pubsub.html).
- [Pipelines and transactions](https://redis.uptrace.dev/guide/go-redis-pipelines.html).
- [Scripting](https://redis.uptrace.dev/guide/lua-scripting.html).
- [Redis Sentinel](https://redis.uptrace.dev/guide/go-redis-sentinel.html).
- [Redis Cluster](https://redis.uptrace.dev/guide/go-redis-cluster.html).
- [Redis Ring](https://redis.uptrace.dev/guide/ring.html).
- [Redis Performance Monitoring](https://redis.uptrace.dev/guide/redis-performance-monitoring.html).
- [Redis Probabilistic [RedisStack]](https://redis.io/docs/data-types/probabilistic/)

## Installation

go-redis supports 2 last Go versions and requires a Go version with
[modules](https://github.com/golang/go/wiki/Modules) support. So make sure to initialize a Go
module:

```shell
go mod init github.com/my/repo
```

Then install go-redis/**v9**:

```shell
go get github.com/redis/go-redis/v9
```

## Quickstart

```go
import (
    "context"
    "fmt"

    "github.com/redis/go-redis/v9"
)

var ctx = context.Background()

func ExampleClient() {
    rdb := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "", // no password set
        DB:       0,  // use default DB
    })

    err := rdb.Set(ctx, "key", "value", 0).Err()
    if err != nil {
        panic(err)
    }

    val, err := rdb.Get(ctx, "key").Result()
    if err != nil {
        panic(err)
    }
    fmt.Println("key", val)

    val2, err := rdb.Get(ctx, "key2").Result()
    if err == redis.Nil {
        fmt.Println("key2 does not exist")
    } else if err != nil {
        panic(err)
    } else {
        fmt.Println("key2", val2)
    }
    // Output: key value
    // key2 does not exist
}
```

The above can be modified to specify the version of the RESP protocol by adding the `protocol`
option to the `Options` struct:

```go
    rdb := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "", // no password set
        DB:       0,  // use default DB
        Protocol: 3, // specify 2 for RESP 2 or 3 for RESP 3
    })

```

### Connecting via a redis url

go-redis also supports connecting via the
[redis uri specification](https://github.com/redis/redis-specifications/tree/master/uri/redis.txt).
The example below demonstrates how the connection can easily be configured using a string, adhering
to this specification.

```go
import (
    "github.com/redis/go-redis/v9"
)

func ExampleClient() *redis.Client {
    url := "redis://user:password@localhost:6379/0?protocol=3"
    opts, err := redis.ParseURL(url)
    if err != nil {
        panic(err)
    }

    return redis.NewClient(opts)
}

```


### Advanced Configuration

go-redis supports extending the client identification phase to allow projects to send their own custom client identification.

#### Default Client Identification

By default, go-redis automatically sends the client library name and version during the connection process. This feature is available in redis-server as of version 7.2. As a result, the command is "fire and forget", meaning it should fail silently, in the case that the redis server does not support this feature.

#### Disabling Identity Verification

When connection identity verification is not required or needs to be explicitly disabled, a `DisableIdentity` configuration option exists.
Initially there was a typo and the option was named `DisableIndentity` instead of `DisableIdentity`. The misspelled option is marked as Deprecated and will be removed in V10 of this library.
Although both options will work at the moment, the correct option is `DisableIdentity`. The deprecated option will be removed in V10 of this library, so please use the correct option name to avoid any issues.

To disable verification, set the `DisableIdentity` option to `true` in the Redis client options:

```go
rdb := redis.NewClient(&redis.Options{
    Addr:            "localhost:6379",
    Password:        "",
    DB:              0,
    DisableIdentity: true, // Disable set-info on connect
})
```

#### Unstable RESP3 Structures for RediSearch Commands
When integrating Redis with application functionalities using RESP3, it's important to note that some response structures aren't final yet. This is especially true for more complex structures like search and query results. We recommend using RESP2 when using the search and query capabilities, but we plan to stabilize the RESP3-based API-s in the coming versions. You can find more guidance in the upcoming release notes.

To enable unstable RESP3, set the option in your client configuration:

```go
redis.NewClient(&redis.Options{
			UnstableResp3: true,
		})
```
**Note:** When UnstableResp3 mode is enabled, it's necessary to use RawResult() and RawVal() to retrieve a raw data.
          Since, raw response is the only option for unstable search commands Val() and Result() calls wouldn't have any affect on them:

```go
res1, err := client.FTSearchWithArgs(ctx, "txt", "foo bar", &redis.FTSearchOptions{}).RawResult()
val1 := client.FTSearchWithArgs(ctx, "txt", "foo bar", &redis.FTSearchOptions{}).RawVal()
```

## Contributing

Please see [out contributing guidelines](CONTRIBUTING.md) to help us improve this library!

## Look and feel

Some corner cases:

```go
// SET key value EX 10 NX
set, err := rdb.SetNX(ctx, "key", "value", 10*time.Second).Result()

// SET key value keepttl NX
set, err := rdb.SetNX(ctx, "key", "value", redis.KeepTTL).Result()

// SORT list LIMIT 0 2 ASC
vals, err := rdb.Sort(ctx, "list", &redis.Sort{Offset: 0, Count: 2, Order: "ASC"}).Result()

// ZRANGEBYSCORE zset -inf +inf WITHSCORES LIMIT 0 2
vals, err := rdb.ZRangeByScoreWithScores(ctx, "zset", &redis.ZRangeBy{
    Min: "-inf",
    Max: "+inf",
    Offset: 0,
    Count: 2,
}).Result()

// ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3 AGGREGATE SUM
vals, err := rdb.ZInterStore(ctx, "out", &redis.ZStore{
    Keys: []string{"zset1", "zset2"},
    Weights: []int64{2, 3}
}).Result()

// EVAL "return {KEYS[1],ARGV[1]}" 1 "key" "hello"
vals, err := rdb.Eval(ctx, "return {KEYS[1],ARGV[1]}", []string{"key"}, "hello").Result()

// custom command
res, err := rdb.Do(ctx, "set", "key", "value").Result()
```

## Run the test

go-redis will start a redis-server and run the test cases.

The paths of redis-server bin file and redis config file are defined in `main_test.go`:

```go
var (
	redisServerBin, _  = filepath.Abs(filepath.Join("testdata", "redis", "src", "redis-server"))
	redisServerConf, _ = filepath.Abs(filepath.Join("testdata", "redis", "redis.conf"))
)
```

For local testing, you can change the variables to refer to your local files, or create a soft link
to the corresponding folder for redis-server and copy the config file to `testdata/redis/`:

```shell
ln -s /usr/bin/redis-server ./go-redis/testdata/redis/src
cp ./go-redis/testdata/redis.conf ./go-redis/testdata/redis/
```

Lastly, run:

```shell
go test
```

Another option is to run your specific tests with an already running redis. The example below, tests
against a redis running on port 9999.:

```shell
REDIS_PORT=9999 go test <your options>
```

## See also

- [Golang ORM](https://bun.uptrace.dev) for PostgreSQL, MySQL, MSSQL, and SQLite
- [Golang PostgreSQL](https://bun.uptrace.dev/postgres/)
- [Golang HTTP router](https://bunrouter.uptrace.dev/)
- [Golang ClickHouse ORM](https://github.com/uptrace/go-clickhouse)

## Contributors

Thanks to all the people who already contributed!

<a href="https://github.com/redis/go-redis/graphs/contributors">
  <img src="https://contributors-img.web.app/image?repo=redis/go-redis" />
</a>

---

### Overview (`vendor/go.opentelemetry.io/contrib/detectors/gcp/README.md`)

# GCP Resource detector

The GCP resource detector supports detecting resources on:

* Google Compute Engine (GCE)
* Google Kubernetes Engine (GKE)
* Google App Engine (GAE)
* Cloud Run
* Cloud Run jobs
* Cloud Functions

## Usage

```golang
ctx := context.Background()
// Detect your resources
res, err := resource.New(ctx,
    // Use the GCP resource detector!
    resource.WithDetectors(gcp.NewDetector()),
    // Keep the default detectors
    resource.WithTelemetrySDK(),
    // Add your own custom attributes to identify your application
    resource.WithAttributes(
        semconv.ServiceNameKey.String("my-application"),
        semconv.ServiceNamespaceKey.String("my-company-frontend-team"),
    ),
)
if err != nil {
    // Handle err
}
// Use the resource in your tracerprovider (or meterprovider)
tp := trace.NewTracerProvider(
    // ... other options
    trace.WithResource(res),
)
```

## Setting Kubernetes attributes

Previous iterations of GCP resource detection attempted to detect
`container.name`, `k8s.pod.name` and `k8s.namespace.name`.  When using this detector,
you should use this in your Pod Spec to set these using
[`OTEL_RESOURCE_ATTRIBUTES`](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/resource/sdk.md#specifying-resource-information-via-an-environment-variable):

```yaml
env:
- name: POD_NAME
  valueFrom:
    fieldRef:
      fieldPath: metadata.name
- name: NAMESPACE_NAME
  valueFrom:
    fieldRef:
      fieldPath: metadata.namespace
- name: CONTAINER_NAME
  value: my-container-name
- name: OTEL_RESOURCE_ATTRIBUTES
  value: k8s.pod.name=$(POD_NAME),k8s.namespace.name=$(NAMESPACE_NAME),k8s.container.name=$(CONTAINER_NAME)

```
To have a detector unpack the `OTEL_RESOURCE_ATTRIBUTES` envvar, use the `WithFromEnv` option:

```golang
...
// Detect your resources
res, err := resource.New(ctx,
    resource.WithDetectors(gcp.NewDetector()),
    resource.WithTelemetrySDK(),
    resource.WithFromEnv(), // unpacks OTEL_RESOURCE_ATTRIBUTES
    // Add your own custom attributes to identify your application
    resource.WithAttributes(
        semconv.ServiceNameKey.String("my-application"),
        semconv.ServiceNamespaceKey.String("my-company-frontend-team"),
    ),
)
...
```

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/prometheus/README.md`)

# Prometheus Exporter

[](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/prometheus)

---

### Overview (`vendor/go.opentelemetry.io/otel/log/embedded/README.md`)

# Log Embedded

[](https://pkg.go.dev/go.opentelemetry.io/otel/log/embedded)

---

### Overview (`vendor/go.opentelemetry.io/otel/log/noop/README.md`)

# Log Noop

[](https://pkg.go.dev/go.opentelemetry.io/otel/log/noop)

---

### Overview (`vendor/go.opentelemetry.io/otel/metric/embedded/README.md`)

# Metric Embedded

[](https://pkg.go.dev/go.opentelemetry.io/otel/metric/embedded)

---

### Overview (`vendor/go.opentelemetry.io/otel/metric/noop/README.md`)

# Metric Noop

[](https://pkg.go.dev/go.opentelemetry.io/otel/metric/noop)

---

### Overview (`vendor/go.opentelemetry.io/otel/sdk/instrumentation/README.md`)

# SDK Instrumentation

[](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/instrumentation)

---

### Overview (`vendor/go.opentelemetry.io/otel/sdk/log/README.md`)

# Log SDK

[](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/log)

---

### Overview (`vendor/go.opentelemetry.io/otel/sdk/metric/README.md`)

# Metric SDK

[](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric)

---

### Overview (`vendor/go.opentelemetry.io/otel/sdk/resource/README.md`)

# SDK Resource

[](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/resource)

---

### Overview (`vendor/go.opentelemetry.io/otel/sdk/trace/README.md`)

# SDK Trace

[](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace)

---

### Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.10.0/README.md`)

# Semconv v1.10.0

[](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.10.0)

---

### Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.12.0/README.md`)

# Semconv v1.12.0

[](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.12.0)

---

### Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.24.0/README.md`)

# Semconv v1.24.0

[](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.24.0)

---

### Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.30.0/README.md`)

# Semconv v1.30.0

[](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.30.0)

---

### Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.37.0/README.md`)

# Semconv v1.37.0

[](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.37.0)

---

### Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.4.0/README.md`)

# Semconv v1.4.0

[](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.4.0)

---

### Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.40.0/README.md`)

# Semconv v1.40.0

[](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.40.0)

---

### Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.41.0/README.md`)

# Semconv v1.41.0

[](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.41.0)

---

### Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.43.0/README.md`)

# Semconv v1.43.0

[](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.43.0)

---

### Overview (`vendor/go.opentelemetry.io/otel/trace/embedded/README.md`)

# Trace Embedded

[](https://pkg.go.dev/go.opentelemetry.io/otel/trace/embedded)

---

### Overview (`vendor/go.opentelemetry.io/otel/trace/noop/README.md`)

# Trace Noop

[](https://pkg.go.dev/go.opentelemetry.io/otel/trace/noop)

---

### Overview (`vendor/golang.org/x/net/http2/README.md`)

This package (golang.org/x/net/http2) is the original source of truth
of the Go HTTP/2 implementation.

As of Go 1.27, the source of truth has moved to the standard library
package net/http/internal/http2.
All new feature development should happen in that package.
Only critical bug fixes and security fixes will be backported to x/net.

The x/net package contains two implementations of the HTTP/2 transport and server:

The original implementation (no longer the source of truth).

A reimplementation of the x/net/http2 APIs in terms of net/http.
This is called "the wrapping implementation", since it wraps net/http.

The original implementation is used when the Go version is less than 1.27.

The wrapping implementation is used when the Go version is at least 1.27.
The build tag "http2legacy" may be set to use the original implementation.

---

### Overview (`vendor/golang.org/x/sys/unix/README.md`)

# Building `sys/unix`

The sys/unix package provides access to the raw system call interface of the
underlying operating system. See: https://godoc.org/golang.org/x/sys/unix

Porting Go to a new architecture/OS combination or adding syscalls, types, or
constants to an existing architecture/OS pair requires some manual effort;
however, there are tools that automate much of the process.

## Build Systems

There are currently two ways we generate the necessary files. We are currently
migrating the build system to use containers so the builds are reproducible.
This is being done on an OS-by-OS basis. Please update this documentation as
components of the build system change.

### Old Build System (currently for `GOOS != "linux"`)

The old build system generates the Go files based on the C header files
present on your system. This means that files
for a given GOOS/GOARCH pair must be generated on a system with that OS and
architecture. This also means that the generated code can differ from system
to system, based on differences in the header files.

To avoid this, if you are using the old build system, only generate the Go
files on an installation with unmodified header files. It is also important to
keep track of which version of the OS the files were generated from (ex.
Darwin 14 vs Darwin 15). This makes it easier to track the progress of changes
and have each OS upgrade correspond to a single change.

To build the files for your current OS and architecture, make sure GOOS and
GOARCH are set correctly and run `mkall.sh`. This will generate the files for
your specific system. Running `mkall.sh -n` shows the commands that will be run.

Requirements: bash, go

### New Build System (currently for `GOOS == "linux"`)

The new build system uses a Docker container to generate the go files directly
from source checkouts of the kernel and various system libraries. This means
that on any platform that supports Docker, all the files using the new build
system can be generated at once, and generated files will not change based on
what the person running the scripts has installed on their computer.

The OS specific files for the new build system are located in the `${GOOS}`
directory, and the build is coordinated by the `${GOOS}/mkall.go` program. When
the kernel or system library updates, modify the Dockerfile at
`${GOOS}/Dockerfile` to checkout the new release of the source.

To build all the files under the new build system, you must be on an amd64/Linux
system and have your GOOS and GOARCH set accordingly. Running `mkall.sh` will
then generate all of the files for all of the GOOS/GOARCH pairs in the new build
system. Running `mkall.sh -n` shows the commands that will be run.

Requirements: bash, go, docker

## Component files

This section describes the various files used in the code generation process.
It also contains instructions on how to modify these files to add a new
architecture/OS or to add additional syscalls, types, or constants. Note that
if you are using the new build system, the scripts/programs cannot be called normally.
They must be called from within the docker container.

### asm files

The hand-written assembly file at `asm_${GOOS}_${GOARCH}.s` implements system
call dispatch. There are three entry points:
```
  func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
  func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
  func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
```
The first and second are the standard ones; they differ only in how many
arguments can be passed to the kernel. The third is for low-level use by the
ForkExec wrapper. Unlike the first two, it does not call into the scheduler to
let it know that a system call is running.

When porting Go to a new architecture/OS, this file must be implemented for
each GOOS/GOARCH pair.

### mksysnum

Mksysnum is a Go program located at `${GOOS}/mksysnum.go` (or `mksysnum_${GOOS}.go`
for the old system). This program takes in a list of header files containing the
syscall number declarations and parses them to produce the corresponding list of
Go numeric constants. See `zsysnum_${GOOS}_${GOARCH}.go` for the generated
constants.

Adding new syscall numbers is mostly done by running the build on a sufficiently
new installation of the target OS (or updating the source checkouts for the
new build system). However, depending on the OS, you may need to update the
parsing in mksysnum.

### mksyscall.go

The `syscall.go`, `syscall_${GOOS}.go`, `syscall_${GOOS}_${GOARCH}.go` are
hand-written Go files which implement system calls (for unix, the specific OS,
or the specific OS/Architecture pair respectively) that need special handling
and list `//sys` comments giving prototypes for ones that can be generated.

The mksyscall.go program takes the `//sys` and `//sysnb` comments and converts
them into syscalls. This requires the name of the prototype in the comment to
match a syscall number in the `zsysnum_${GOOS}_${GOARCH}.go` file. The function
prototype can be exported (capitalized) or not.

Adding a new syscall often just requires adding a new `//sys` function prototype
with the desired arguments and a capitalized name so it is exported. However, if
you want the interface to the syscall to be different, often one will make an
unexported `//sys` prototype, and then write a custom wrapper in
`syscall_${GOOS}.go`.

### types files

For each OS, there is a hand-written Go file at `${GOOS}/types.go` (or
`types_${GOOS}.go` on the old system). This file includes standard C headers and
creates Go type aliases to the corresponding C types. The file is then fed
through godef to get the Go compatible definitions. Finally, the generated code
is fed though mkpost.go to format the code correctly and remove any hidden or
private identifiers. This cleaned-up code is written to
`ztypes_${GOOS}_${GOARCH}.go`.

The hardest part about preparing this file is figuring out which headers to
include and which symbols need to be `#define`d to get the actual data
structures that pass through to the kernel system calls. Some C libraries
preset alternate versions for binary compatibility and translate them on the
way in and out of system calls, but there is almost always a `#define` that can
get the real ones.
See `types_darwin.go` and `linux/types.go` for examples.

To add a new type, add in the necessary include statement at the top of the
file (if it is not already there) and add in a type alias line. Note that if
your type is significantly different on different architectures, you may need
some `#if/#elif` macros in your include statements.

### mkerrors.sh

This script is used to generate the system's various constants. This doesn't
just include the error numbers and error strings, but also the signal numbers
and a wide variety of miscellaneous constants. The constants come from the list
of include files in the `includes_${uname}` variable. A regex then picks out
the desired `#define` statements, and generates the corresponding Go constants.
The error numbers and strings are generated from `#include <errno.h>`, and the
signal numbers and strings are generated from `#include <signal.h>`. All of
these constants are written to `zerrors_${GOOS}_${GOARCH}.go` via a C program,
`_errors.c`, which prints out all the constants.

To add a constant, add the header that includes it to the appropriate variable.
Then, edit the regex (if necessary) to match the desired constant. Avoid making
the regex too broad to avoid matching unintended constants.

### internal/mkmerge

This program is used to extract duplicate const, func, and type declarations
from the generated architecture-specific files listed below, and merge these
into a common file for each OS.

The merge is performed in the following steps:
1. Construct the set of common code that is identical in all architecture-specific files.
2. Write this common code to the merged file.
3. Remove the common code from all architecture-specific files.


## Generated files

### `zerrors_${GOOS}_${GOARCH}.go`

A file containing all of the system's generated error numbers, error strings,
signal numbers, and constants. Generated by `mkerrors.sh` (see above).

### `zsyscall_${GOOS}_${GOARCH}.go`

A file containing all the generated syscalls for a specific GOOS and GOARCH.
Generated by `mksyscall.go` (see above).

### `zsysnum_${GOOS}_${GOARCH}.go`

A list of numeric constants for all the syscall number of the specific GOOS
and GOARCH. Generated by mksysnum (see above).

### `ztypes_${GOOS}_${GOARCH}.go`

A file containing Go types for passing into (or returning from) syscalls.
Generated by godefs and the types file (see above).

---

### Overview (`vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/README.md`)

# Azure Core Client Module for Go

[](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azcore)
[](https://dev.azure.com/azure-sdk/public/_build/latest?definitionId=1843&branchName=main)
[](https://img.shields.io/azure-devops/coverage/azure-sdk/public/1843/main)

The `azcore` module provides a set of common interfaces and types for Go SDK client modules.
These modules follow the [Azure SDK Design Guidelines for Go](https://azure.github.io/azure-sdk/golang_introduction.html).

## Getting started

This project uses [Go modules](https://github.com/golang/go/wiki/Modules) for versioning and dependency management.

Typically, you will not need to explicitly install `azcore` as it will be installed as a client module dependency.
To add the latest version to your `go.mod` file, execute the following command.

```bash
go get github.com/Azure/azure-sdk-for-go/sdk/azcore
```

General documentation and examples can be found on [pkg.go.dev](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azcore).

## Contributing
This project welcomes contributions and suggestions. Most contributions require
you to agree to a Contributor License Agreement (CLA) declaring that you have
the right to, and actually do, grant us the rights to use your contribution.
For details, visit [https://cla.microsoft.com](https://cla.microsoft.com).

When you submit a pull request, a CLA-bot will automatically determine whether
you need to provide a CLA and decorate the PR appropriately (e.g., label,
comment). Simply follow the instructions provided by the bot. You will only
need to do this once across all repos using our CLA.

This project has adopted the
[Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information, see the
[Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any
additional questions or comments.

---

### Overview (`vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md`)

# Azure Identity Client Module for Go

The Azure Identity module provides Microsoft Entra ID ([formerly Azure Active Directory](https://learn.microsoft.com/entra/fundamentals/new-name)) token authentication support across the Azure SDK. It includes a set of `TokenCredential` implementations, which can be used with Azure SDK clients supporting token authentication.

[](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity)
| [Microsoft Entra ID documentation](https://learn.microsoft.com/entra/identity/)
| [Source code](https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/azidentity)

# Getting started

## Install the module

This project uses [Go modules](https://github.com/golang/go/wiki/Modules) for versioning and dependency management.

Install the Azure Identity module:

```sh
go get -u github.com/Azure/azure-sdk-for-go/sdk/azidentity
```

## Prerequisites

- an [Azure subscription](https://azure.microsoft.com/free/)
- Go 1.18

### Authenticating during local development

When debugging and executing code locally, developers typically use their own accounts to authenticate calls to Azure services. The `azidentity` module supports authenticating through developer tools to simplify local development.

#### Authenticating via the Azure CLI

`DefaultAzureCredential` and `AzureCLICredential` can authenticate as the user
signed in to the [Azure CLI](https://learn.microsoft.com/cli/azure). To sign in to the Azure CLI, run `az login`. On a system with a default web browser, the Azure CLI will launch the browser to authenticate a user.

When no default browser is available, `az login` will use the device code
authentication flow. This can also be selected manually by running `az login --use-device-code`.

#### Authenticate via the Azure Developer CLI

Developers coding outside of an IDE can also use the [Azure Developer CLI](https://aka.ms/azure-dev) to authenticate. Applications using the `DefaultAzureCredential` or the `AzureDeveloperCLICredential` can use the account logged in to the Azure Developer CLI to authenticate calls in their application when running locally.

To authenticate with the Azure Developer CLI, run `azd auth login`. On a system with a default web browser, `azd` will launch the browser to authenticate. On systems without a default web browser, run `azd auth login --use-device-code` to use the device code authentication flow.

## Key concepts

### Credentials

A credential is a type which contains or can obtain the data needed for a
service client to authenticate requests. Service clients across the Azure SDK
accept a credential instance when they are constructed, and use that credential
to authenticate requests.

The `azidentity` module focuses on OAuth authentication with Microsoft Entra ID. It offers a variety of credential types capable of acquiring a Microsoft Entra access token. See [Credential Types](#credential-types "Credential Types") for a list of this module's credential types.

### DefaultAzureCredential

`DefaultAzureCredential` simplifies authentication while developing apps that deploy to Azure by combining credentials used in Azure hosting environments with credentials used in local development. For more information, see [DefaultAzureCredential overview][dac_overview].

## Managed Identity

`DefaultAzureCredential` and `ManagedIdentityCredential` support
[managed identity authentication](https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview)
in any hosting environment which supports managed identities, such as (this list is not exhaustive):
* [Azure App Service](https://learn.microsoft.com/azure/app-service/overview-managed-identity)
* [Azure Arc](https://learn.microsoft.com/azure/azure-arc/servers/managed-identity-authentication)
* [Azure Cloud Shell](https://learn.microsoft.com/azure/cloud-shell/msi-authorization)
* [Azure Kubernetes Service](https://learn.microsoft.com/azure/aks/use-managed-identity)
* [Azure Service Fabric](https://learn.microsoft.com/azure/service-fabric/concepts-managed-identity)
* [Azure Virtual Machines](https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/how-to-use-vm-token)

## Examples

- [Authenticate with DefaultAzureCredential](#authenticate-with-defaultazurecredential "Authenticate with DefaultAzureCredential")
- [Define a custom authentication flow with ChainedTokenCredential](#define-a-custom-authentication-flow-with-chainedtokencredential "Define a custom authentication flow with ChainedTokenCredential")
- [Specify a user-assigned managed identity for DefaultAzureCredential](#specify-a-user-assigned-managed-identity-for-defaultazurecredential)

### Authenticate with DefaultAzureCredential

This example demonstrates authenticating a client from the `armresources` module with `DefaultAzureCredential`.

```go
cred, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
  // handle error
}

client := armresources.NewResourceGroupsClient("subscription ID", cred, nil)
```

### Specify a user-assigned managed identity for DefaultAzureCredential

To configure `DefaultAzureCredential` to authenticate a user-assigned managed identity, set the environment variable `AZURE_CLIENT_ID` to the identity's client ID.

### Define a custom authentication flow with `ChainedTokenCredential`

`DefaultAzureCredential` is generally the quickest way to get started developing apps for Azure. For more advanced scenarios, `ChainedTokenCredential` links multiple credential instances to be tried sequentially when authenticating. It will try each chained credential in turn until one provides a token or fails to authenticate due to an error.

The following example demonstrates creating a credential, which will attempt to authenticate using managed identity. It will fall back to authenticating via the Azure CLI when a managed identity is unavailable.

```go
managed, err := azidentity.NewManagedIdentityCredential(nil)
if err != nil {
  // handle error
}
azCLI, err := azidentity.NewAzureCLICredential(nil)
if err != nil {
  // handle error
}
chain, err := azidentity.NewChainedTokenCredential([]azcore.TokenCredential{managed, azCLI}, nil)
if err != nil {
  // handle error
}

client := armresources.NewResourceGroupsClient("subscription ID", chain, nil)
```

## Credential Types

### Credential chains

|Credential|Usage|Reference
|-|-|-
|[DefaultAzureCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#DefaultAzureCredential)|Simplified authentication experience for getting started developing Azure apps|[DefaultAzureCredential overview][dac_overview]|
|[ChainedTokenCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#ChainedTokenCredential)|Define custom authentication flows, composing multiple credentials|[ChainedTokenCredential overview][ctc_overview]|

### Authenticating Azure-Hosted Applications

|Credential|Usage
|-|-
|[EnvironmentCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#EnvironmentCredential)|Authenticate a service principal or user configured by environment variables
|[ManagedIdentityCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#ManagedIdentityCredential)|Authenticate the managed identity of an Azure resource
|[WorkloadIdentityCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#WorkloadIdentityCredential)|Authenticate a workload identity on Kubernetes

### Authenticating Service Principals

|Credential|Usage
|-|-
|[AzurePipelinesCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#AzurePipelinesCredential)|Authenticate an Azure Pipelines [service connection](https://learn.microsoft.com/azure/devops/pipelines/library/service-endpoints?view=azure-devops&tabs=yaml)
|[ClientAssertionCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#ClientAssertionCredential)|Authenticate a service principal with a signed client assertion
|[ClientCertificateCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#ClientCertificateCredential)|Authenticate a service principal with a certificate
|[ClientSecretCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#ClientSecretCredential)|Authenticate a service principal with a secret

### Authenticating Users

|Credential|Usage
|-|-
|[InteractiveBrowserCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#InteractiveBrowserCredential)|Interactively authenticate a user with the default web browser
|[DeviceCodeCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#DeviceCodeCredential)|Interactively authenticate a user on a device with limited UI
|[UsernamePasswordCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#UsernamePasswordCredential)|Authenticate a user with a username and password

### Authenticating via Development Tools

|Credential|Usage
|-|-
|[AzureCLICredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#AzureCLICredential)|Authenticate as the user signed in to the Azure CLI
|[AzureDeveloperCLICredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#AzureDeveloperCLICredential)|Authenticates as the user signed in to the Azure Developer CLI

## Environment Variables

`DefaultAzureCredential` and `EnvironmentCredential` can be configured with environment variables. Each type of authentication requires values for specific variables:

#### Service principal with secret

|variable name|value
|-|-
|`AZURE_CLIENT_ID`|ID of a Microsoft Entra application
|`AZURE_TENANT_ID`|ID of the application's Microsoft Entra tenant
|`AZURE_CLIENT_SECRET`|one of the application's client secrets

#### Service principal with certificate

|variable name|value
|-|-
|`AZURE_CLIENT_ID`|ID of a Microsoft Entra application
|`AZURE_TENANT_ID`|ID of the application's Microsoft Entra tenant
|`AZURE_CLIENT_CERTIFICATE_PATH`|path to a certificate file including private key
|`AZURE_CLIENT_CERTIFICATE_PASSWORD`|password of the certificate file, if any

#### Username and password

|variable name|value
|-|-
|`AZURE_CLIENT_ID`|ID of a Microsoft Entra application
|`AZURE_USERNAME`|a username (usually an email address)
|`AZURE_PASSWORD`|that user's password

Configuration is attempted in the above order. For example, if values for a
client secret and certificate are both present, the client secret will be used.

## Token caching

Token caching is an `azidentity` feature that allows apps to:

* Cache tokens in memory (default) or on disk (opt-in).
* Improve resilience and performance.
* Reduce the number of requests made to Microsoft Entra ID to obtain access tokens.

For more details, see the [token caching documentation](https://aka.ms/azsdk/go/identity/caching).

## Troubleshooting

### Error Handling

Credentials return an `error` when they fail to authenticate or lack data they require to authenticate. For guidance on resolving errors from specific credential types, see the [troubleshooting guide](https://aka.ms/azsdk/go/identity/troubleshoot).

For more details on handling specific Microsoft Entra errors, see the Microsoft Entra [error code documentation](https://learn.microsoft.com/entra/identity-platform/reference-error-codes).

### Logging

This module uses the classification-based logging implementation in `azcore`. To enable console logging for all SDK modules, set `AZURE_SDK_GO_LOGGING` to `all`. Use the `azcore/log` package to control log event output or to enable logs for `azidentity` only. For example:
```go
import azlog "github.com/Azure/azure-sdk-for-go/sdk/azcore/log"

// print log output to stdout
azlog.SetListener(func(event azlog.Event, s string) {
    fmt.Println(s)
})

// include only azidentity credential logs
azlog.SetEvents(azidentity.EventAuthentication)
```

Credentials log basic information only, such as `GetToken` success or failure and errors. These log entries don't contain authentication secrets but may contain sensitive information.

## Next steps

Client and management modules listed on the [Azure SDK releases page](https://azure.github.io/azure-sdk/releases/latest/go.html) support authenticating with `azidentity` credential types. You can learn more about using these libraries in their documentation, which is linked from the release page.

## Provide Feedback

If you encounter bugs or have suggestions, please
[open an issue](https://github.com/Azure/azure-sdk-for-go/issues).

## Contributing

This project welcomes contributions and suggestions. Most contributions require
you to agree to a Contributor License Agreement (CLA) declaring that you have
the right to, and actually do, grant us the rights to use your contribution.
For details, visit [https://cla.microsoft.com](https://cla.microsoft.com).

When you submit a pull request, a CLA-bot will automatically determine whether
you need to provide a CLA and decorate the PR appropriately (e.g., label,
comment). Simply follow the instructions provided by the bot. You will only
need to do this once across all repos using our CLA.

This project has adopted the
[Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information, see the
[Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any
additional questions or comments.


[ctc_overview]: https://aka.ms/azsdk/go/identity/credential-chains#chainedtokencredential-overview
[dac_overview]: https://aka.ms/azsdk/go/identity/credential-chains#defaultazurecredential-overview

---

### Overview (`vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/README.md`)

# GCP Resource detection library

This is a library intended to be used by Upstream OpenTelemetry resource detectors.  It exists within this repository to allow for integration testing of the detection functions in real GCP environments.

---

### Overview (`vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/README.md`)

# OpenTelemetry Google Cloud Monitoring Exporter

[](https://pkg.go.dev/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric)
[![Apache License][license-image]][license-url]

OpenTelemetry Google Cloud Monitoring Exporter allows the user to send collected metrics to Google Cloud.

To get started with instrumentation in Google Cloud, see [Generate traces and metrics with
Go](https://cloud.google.com/stackdriver/docs/instrumentation/setup/go).

To learn more about instrumentation and observability, including opinionated recommendations
for Google Cloud Observability, visit [Instrumentation and
observability](https://cloud.google.com/stackdriver/docs/instrumentation/overview).

[Google Cloud Monitoring](https://cloud.google.com/monitoring) provides visibility into the performance, uptime, and overall health of cloud-powered applications. It collects metrics, events, and metadata from Google Cloud, Amazon Web Services, hosted uptime probes, application instrumentation, and a variety of common application components including Cassandra, Nginx, Apache Web Server, Elasticsearch, and many others. Operations ingests that data and generates insights via dashboards, charts, and alerts. Cloud Monitoring alerting helps you collaborate by integrating with Slack, PagerDuty, and more.

## Setup

Google Cloud Monitoring is a managed service provided by Google Cloud Platform. Google Cloud Monitoring requires to set up "Workspace" in advance. The guide to create a new Workspace is available on [the official document](https://cloud.google.com/monitoring/workspaces/create).

## Authentication

The Google Cloud Monitoring exporter depends upon [`google.FindDefaultCredentials`](https://pkg.go.dev/golang.org/x/oauth2/google?tab=doc#FindDefaultCredentials), so the service account is automatically detected by default, but also the custom credential file (so called `service_account_key.json`) can be detected with specific conditions. Quoting from the document of `google.FindDefaultCredentials`:

* A JSON file whose path is specified by the `GOOGLE_APPLICATION_CREDENTIALS` environment variable.
* A JSON file in a location known to the gcloud command-line tool. On Windows, this is `%APPDATA%/gcloud/application_default_credentials.json`. On other systems, `$HOME/.config/gcloud/application_default_credentials.json`.

When running code locally, you may need to specify a Google Project ID in addition to `GOOGLE_APPLICATION_CREDENTIALS`. This is best done using an environment variable (e.g. `GOOGLE_CLOUD_PROJECT`) and the `metric.WithProjectID` method, e.g.:

```golang
projectID := os.Getenv("GOOGLE_CLOUD_PROJECT")
opts := []mexporter.Option{
    mexporter.WithProjectID(projectID),
}
```

## Useful links

* For more information on OpenTelemetry, visit: https://opentelemetry.io/
* For more about OpenTelemetry Go, visit: https://github.com/open-telemetry/opentelemetry-go
* Learn more about Google Cloud Monitoring at https://cloud.google.com/monitoring

[license-url]: https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/main/LICENSE
[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat

---

### Overview (`vendor/github.com/alicebob/miniredis/v2/fpconv/README.md`)

This is a translation of the actual C code in Redis (7.2) which does the float
-> string conversion.
Strconv does a close enough job, but we can use the exact same logic, so why not.

---

### Overview (`vendor/github.com/alicebob/miniredis/v2/geohash/README.md`)

This is a (selected) copy of github.com/mmcloughlin/geohash with the latitude
range changed from 90 to ~85, to align with the algorithm use by Redis.

---

### Overview (`vendor/github.com/alicebob/miniredis/v2/gopher-json/README.md`)

Copied from https://github.com/layeh/gopher-json and https://github.com/alicebob/gopher-json

---

### Overview (`vendor/github.com/alicebob/miniredis/v2/metro/README.md`)

This is a partial copy of github.com/dgryski/go-metro.

---

### Overview (`vendor/github.com/alicebob/miniredis/v2/size/readme.md`)

Credits to DmitriyVTitov on his package https://github.com/DmitriyVTitov/size

---

### Overview (`vendor/github.com/go-jose/go-jose/v4/json/README.md`)

# Safe JSON

This repository contains a fork of the `encoding/json` package from Go 1.6.

The following changes were made:

* Object deserialization uses case-sensitive member name matching instead of
  [case-insensitive matching](https://www.ietf.org/mail-archive/web/json/current/msg03763.html).
  This is to avoid differences in the interpretation of JOSE messages between
  go-jose and libraries written in other languages.
* When deserializing a JSON object, we check for duplicate keys and reject the
  input whenever we detect a duplicate. Rather than trying to work with malformed
  data, we prefer to reject it right away.

---

### Overview (`vendor/github.com/google/s2a-go/internal/v2/README.md`)

**This directory has the implementation of the S2Av2's gRPC-Go client libraries**

---

### Overview (`vendor/github.com/stretchr/testify/internal/spew/README.md`)

go-spew
=======

[](http://copyfree.org)

Go-spew implements a deep pretty printer for Go data structures to aid in
debugging.  A comprehensive suite of tests with 100% test coverage is provided
to ensure proper functionality.

## License

Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License.

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/README.md`)

# OTLP Trace Exporter

[](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlptrace)

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/stdout/stdoutlog/README.md`)

# STDOUT Log Exporter

[](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/stdout/stdoutlog)

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/stdout/stdoutmetric/README.md`)

# STDOUT Metric Exporter

[](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/stdout/stdoutmetric)

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/README.md`)

# STDOUT Trace Exporter

[](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/stdout/stdouttrace)

---

### Overview (`vendor/go.opentelemetry.io/otel/sdk/internal/x/README.md`)

# Experimental Features

The SDK contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the OpenTelemetry Go SDK prior to stabilization in the specification so that users can start experimenting with them and provide feedback.

These feature may change in backwards incompatible ways as feedback is applied.
See the [Compatibility and Stability](#compatibility-and-stability) section for more information.

## Features

- [Resource](#resource)

### Resource

[OpenTelemetry resource semantic conventions] include many attribute definitions that are defined as experimental.
To have experimental semantic conventions be added by [resource detectors] set the `OTEL_GO_X_RESOURCE` environment variable.
The value set must be the case-insensitive string of `"true"` to enable the feature.
All other values are ignored.



[OpenTelemetry resource semantic conventions]: https://opentelemetry.io/docs/specs/semconv/resource/
[resource detectors]: https://pkg.go.dev/go.opentelemetry.io/otel/sdk/resource#Detector

#### Examples

Enable experimental resource semantic conventions.

```console
export OTEL_GO_X_RESOURCE=true
```

Disable experimental resource semantic conventions.

```console
unset OTEL_GO_X_RESOURCE
```

## Compatibility and Stability

Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability [policy](../../../VERSIONING.md).
These features may be removed or modified in successive version releases, including patch versions.

When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.

---

### Overview (`vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/README.md`)

# Metric SDK Exemplars

[](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric/exemplar)

---

### Overview (`vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/README.md`)

# SDK Metric data

[](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric/metricdata)

---

### Overview (`vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/README.md`)

# SDK Trace test

[](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace/tracetest)

---

### Overview (`vendor/golang.org/x/net/internal/httpcommon/README.md`)

These two packages are identical:

- net/http/internal/httpcommon
- golang.org/x/net/internal/httpcommon

The two are kept in sync manually.
Any change to one should be made in the other.

---

### Overview (`vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/README.md`)

# Azure Blob Storage module for Go
[](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob)
[](https://dev.azure.com/azure-sdk/public/_build/latest?definitionId=2854&branchName=main)
[](https://img.shields.io/azure-devops/coverage/azure-sdk/public/2854/main)

> Service Version: 2023-11-03

Azure Blob Storage is Microsoft's object storage solution for the cloud. Blob
Storage is optimized for storing massive amounts of unstructured data - data that does not adhere to a particular data model or
definition, such as text or binary data. For more information, see [Introduction to Azure Blob Storage](https://learn.microsoft.com/azure/storage/blobs/storage-blobs-introduction).

Use the Azure Blob Storage client module `github.com/Azure/azure-sdk-for-go/sdk/storage/azblob` to:

* Authenticate clients with Azure Blob Storage
* Manipulate containers and blobs in an Azure storage account

Key links:

[Source code][source] | [API reference documentation][docs] | [REST API documentation][rest_docs] | [Product documentation][product_docs] | [Samples][go_samples]

## Getting started

### Prerequisites

- Go, version 1.18 or higher - [Install Go](https://go.dev/doc/install)
- Azure subscription - [Create a free account](https://azure.microsoft.com/free/)
- Azure storage account - To create a storage account, use tools including the [Azure portal][storage_account_create_portal],
[Azure PowerShell][storage_account_create_ps], or the [Azure CLI][storage_account_create_cli].
Here's an example using the Azure CLI:

```bash
az storage account create --name MyStorageAccount --resource-group MyResourceGroup --location westus --sku Standard_LRS
```

### Install the package

Install the Azure Blob Storage client module for Go with [go get][goget]:

```bash
go get github.com/Azure/azure-sdk-for-go/sdk/storage/azblob
```

If you plan to authenticate with Azure Active Directory (recommended), also install the [azidentity][azidentity] module.

```bash
go get github.com/Azure/azure-sdk-for-go/sdk/azidentity
```

### Authenticate the client

To interact with the Azure Blob Storage service, you'll need to create an instance of the `azblob.Client` type.  The [azidentity][azidentity] module makes it easy to add Azure Active Directory support for authenticating Azure SDK clients with their corresponding Azure services.

```go
// create a credential for authenticating with Azure Active Directory
cred, err := azidentity.NewDefaultAzureCredential(nil)
// TODO: handle err

// create an azblob.Client for the specified storage account that uses the above credential
client, err := azblob.NewClient("https://MYSTORAGEACCOUNT.blob.core.windows.net/", cred, nil)
// TODO: handle err
```

Learn more about enabling Azure Active Directory for authentication with Azure Storage:

*  [Authorize access to blobs using Azure Active Directory][storage_ad]

Other options for authentication include connection strings, shared key, shared access signatures (SAS), and anonymous public access. Use the appropriate client constructor function for the authentication mechanism you wish to use. For examples, see:

* [Blob samples][samples]

## Key concepts

Blob Storage is designed for:

- Serving images or documents directly to a browser.
- Storing files for distributed access.
- Streaming video and audio.
- Writing to log files.
- Storing data for backup and restore, disaster recovery, and archiving.
- Storing data for analysis by an on-premises or Azure-hosted service.

Blob Storage offers three types of resources:

- The _storage account_
- One or more _containers_ in a storage account
- One or more _blobs_ in a container

Instances of the `azblob.Client` type provide methods for manipulating containers and blobs within a storage account.
The storage account is specified when the `azblob.Client` is constructed.

### Specialized clients

The Azure Blob Storage client module for Go also provides specialized clients in various subpackages. Use these clients when you need to interact with a specific kind of blob. Learn more about [block blobs, append blobs, and page blobs](https://learn.microsoft.com/rest/api/storageservices/understanding-block-blobs--append-blobs--and-page-blobs).

- [appendblob][append_blob]
- [blockblob][block_blob]
- [pageblob][page_blob]

The [blob][blob] package contains APIs common to all blob types.  This includes APIs for deleting and undeleting a blob, setting metadata, and more.

The [lease][lease] package contains clients for managing leases on blobs and containers. See the [REST API reference](https://learn.microsoft.com/rest/api/storageservices/lease-blob#remarks) for general information on leases.

The [container][container] package contains APIs specific to containers.  This includes APIs for setting access policies or properties, and more.

The [service][service] package contains APIs specific to the Blob service. This includes APIs for manipulating containers, retrieving account information, and more.

The [sas][sas] package contains utilities to aid in the creation and manipulation of shared access signature (SAS) tokens.
See the package's documentation for more information.

### Goroutine safety

We guarantee that all client instance methods are goroutine-safe and independent of each other (see [guideline](https://azure.github.io/azure-sdk/golang_introduction.html#thread-safety)). This ensures that the recommendation to reuse client instances is always safe, even across goroutines.

### Blob metadata

Blob metadata name-value pairs are valid HTTP headers and should adhere to all restrictions governing HTTP headers. Metadata names must be valid HTTP header names, may contain only ASCII characters, and should be treated as case-insensitive. Base64-encode or URL-encode metadata values containing non-ASCII characters.

### Additional concepts

[Client options](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azcore/policy#ClientOptions) |
[Accessing the response](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime#WithCaptureResponse) |
[Handling failures](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azcore#ResponseError) |
[Logging](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azcore/log)


## Examples

### Upload a blob

```go
const (
	account       = "https://MYSTORAGEACCOUNT.blob.core.windows.net/"
	containerName = "sample-container"
	blobName      = "sample-blob"
	sampleFile    = "path/to/sample/file"
)

// authenticate with Azure Active Directory
cred, err := azidentity.NewDefaultAzureCredential(nil)
// TODO: handle error

// create a client for the specified storage account
client, err := azblob.NewClient(account, cred, nil)
// TODO: handle error

// open the file for reading
file, err := os.OpenFile(sampleFile, os.O_RDONLY, 0)
// TODO: handle error
defer file.Close()

// upload the file to the specified container with the specified blob name
_, err = client.UploadFile(context.TODO(), containerName, blobName, file, nil)
// TODO: handle error
```

### Download a blob

```go
// this example accesses a public blob via anonymous access, so no credentials are required
client, err := azblob.NewClientWithNoCredential("https://azurestoragesamples.blob.core.windows.net/", nil)
// TODO: handle error

// create or open a local file where we can download the blob
file, err := os.Create("cloud.jpg")
// TODO: handle error
defer file.Close()

// download the blob
_, err = client.DownloadFile(context.TODO(), "samples", "cloud.jpg", file, nil)
// TODO: handle error
```

### Enumerate blobs

```go
const (
	account       = "https://MYSTORAGEACCOUNT.blob.core.windows.net/"
	containerName = "sample-container"
)

// authenticate with Azure Active Directory
cred, err := azidentity.NewDefaultAzureCredential(nil)
// TODO: handle error

// create a client for the specified storage account
client, err := azblob.NewClient(account, cred, nil)
// TODO: handle error

// blob listings are returned across multiple pages
pager := client.NewListBlobsFlatPager(containerName, nil)

// continue fetching pages until no more remain
for pager.More() {
  // advance to the next page
	page, err := pager.NextPage(context.TODO())
	// TODO: handle error

	// print the blob names for this page
	for _, blob := range page.Segment.BlobItems {
		fmt.Println(*blob.Name)
	}
}
```

## Troubleshooting

All Blob service operations will return an
[*azcore.ResponseError][azcore_response_error] on failure with a
populated `ErrorCode` field. Many of these errors are recoverable.
The [bloberror][blob_error] package provides the possible Storage error codes
along with helper facilities for error handling.

```go
const (
	connectionString = "<connection_string>"
	containerName    = "sample-container"
)

// create a client with the provided connection string
client, err := azblob.NewClientFromConnectionString(connectionString, nil)
// TODO: handle error

// try to delete the container, avoiding any potential race conditions with an in-progress or completed deletion
_, err = client.DeleteContainer(context.TODO(), containerName, nil)

if bloberror.HasCode(err, bloberror.ContainerBeingDeleted, bloberror.ContainerNotFound) {
	// ignore any errors if the container is being deleted or already has been deleted
} else if err != nil {
	// TODO: some other error
}
```

## Next steps

Get started with our [Blob samples][samples]. They contain complete examples of the above snippets and more.

## Contributing

See the [Storage CONTRIBUTING.md][storage_contrib] for details on building,
testing, and contributing to this library.

This project welcomes contributions and suggestions.  Most contributions require
you to agree to a Contributor License Agreement (CLA) declaring that you have
the right to, and actually do, grant us the rights to use your contribution. For
details, visit [cla.microsoft.com][cla].

This project has adopted the [Microsoft Open Source Code of Conduct][coc].
For more information see the [Code of Conduct FAQ][coc_faq]
or contact [opencode@microsoft.com][coc_contact] with any
additional questions or comments.




[source]: https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/storage/azblob
[docs]: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob#section_documentation
[rest_docs]: https://learn.microsoft.com/rest/api/storageservices/blob-service-rest-api
[product_docs]: https://learn.microsoft.com/azure/storage/blobs/storage-blobs-overview
[godevdl]: https://go.dev/dl/
[goget]: https://pkg.go.dev/cmd/go#hdr-Add_dependencies_to_current_module_and_install_them
[go_samples]: https://github.com/Azure-Samples/azure-sdk-for-go-samples/tree/main
[storage_account_docs]: https://learn.microsoft.com/azure/storage/common/storage-account-overview
[storage_account_create_ps]: https://learn.microsoft.com/azure/storage/common/storage-quickstart-create-account?tabs=azure-powershell
[storage_account_create_cli]: https://learn.microsoft.com/azure/storage/common/storage-quickstart-create-account?tabs=azure-cli
[storage_account_create_portal]: https://learn.microsoft.com/azure/storage/common/storage-quickstart-create-account?tabs=azure-portal
[azure_cli]: https://learn.microsoft.com/cli/azure
[azure_sub]: https://azure.microsoft.com/free/
[azidentity]: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity
[storage_ad]: https://learn.microsoft.com/azure/storage/common/storage-auth-aad
[azcore_response_error]: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azcore#ResponseError
[samples]: https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/storage/azblob/examples_test.go
[append_blob]: https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/storage/azblob/appendblob/client.go
[blob]: https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/storage/azblob/blob/client.go
[blob_error]: https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/storage/azblob/bloberror/error_codes.go
[block_blob]: https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/storage/azblob/blockblob/client.go
[container]: https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/storage/azblob/container/client.go
[lease]: https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/storage/azblob/lease
[page_blob]: https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/storage/azblob/pageblob/client.go
[sas]: https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/storage/azblob/sas
[service]: https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/storage/azblob/service/client.go
[storage_contrib]: https://github.com/Azure/azure-sdk-for-go/blob/main/CONTRIBUTING.md
[cla]: https://cla.microsoft.com
[coc]: https://opensource.microsoft.com/codeofconduct/
[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/
[coc_contact]: mailto:opencode@microsoft.com

---

### Overview (`vendor/github.com/klauspost/compress/zstd/internal/xxhash/README.md`)

# xxhash

VENDORED: Go to [github.com/cespare/xxhash](https://github.com/cespare/xxhash) for original package.

xxhash is a Go implementation of the 64-bit [xxHash] algorithm, XXH64. This is a
high-quality hashing algorithm that is much faster than anything in the Go
standard library.

This package provides a straightforward API:

```
func Sum64(b []byte) uint64
func Sum64String(s string) uint64
type Digest struct{ ... }
    func New() *Digest
```

The `Digest` type implements hash.Hash64. Its key methods are:

```
func (*Digest) Write([]byte) (int, error)
func (*Digest) WriteString(string) (int, error)
func (*Digest) Sum64() uint64
```

The package is written with optimized pure Go and also contains even faster
assembly implementations for amd64 and arm64. If desired, the `purego` build tag
opts into using the Go code even on those architectures.

[xxHash]: http://cyan4973.github.io/xxHash/

## Compatibility

This package is in a module and the latest code is in version 2 of the module.
You need a version of Go with at least "minimal module compatibility" to use
github.com/cespare/xxhash/v2:

* 1.9.7+ for Go 1.9
* 1.10.3+ for Go 1.10
* Go 1.11 or later

I recommend using the latest release of Go.

## Benchmarks

Here are some quick benchmarks comparing the pure-Go and assembly
implementations of Sum64.

| input size | purego    | asm       |
| ---------- | --------- | --------- |
| 4 B        |  1.3 GB/s |  1.2 GB/s |
| 16 B       |  2.9 GB/s |  3.5 GB/s |
| 100 B      |  6.9 GB/s |  8.1 GB/s |
| 4 KB       | 11.7 GB/s | 16.7 GB/s |
| 10 MB      | 12.0 GB/s | 17.3 GB/s |

These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C
CPU using the following commands under Go 1.19.2:

```
benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$')
benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')
```

## Projects using this package

- [InfluxDB](https://github.com/influxdata/influxdb)
- [Prometheus](https://github.com/prometheus/prometheus)
- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
- [FreeCache](https://github.com/coocood/freecache)
- [FastCache](https://github.com/VictoriaMetrics/fastcache)

---

### Overview (`vendor/github.com/redis/go-redis/extra/redisotel/v9/README.md`)

# OpenTelemetry instrumentation for go-redis

## Installation

```bash
go get github.com/redis/go-redis/extra/redisotel/v9
```

## Usage

Tracing is enabled by adding a hook:

```go
import (
    "github.com/redis/go-redis/v9"
    "github.com/redis/go-redis/extra/redisotel/v9"
)

rdb := rdb.NewClient(&rdb.Options{...})

// Enable tracing instrumentation.
if err := redisotel.InstrumentTracing(rdb); err != nil {
	panic(err)
}

// Enable metrics instrumentation.
if err := redisotel.InstrumentMetrics(rdb); err != nil {
	panic(err)
}
```

See [example](../../example/otel) and
[Monitoring Go Redis Performance and Errors](https://redis.uptrace.dev/guide/go-redis-monitoring.html)
for details.

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc/README.md`)

# OTLP Log gRPC Exporter

[](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc)

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp/README.md`)

# OTLP Log HTTP Exporter

[](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp)

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/README.md`)

# OTLP Metric gRPC Exporter

[](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc)

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/README.md`)

# OTLP Metric HTTP Exporter

[](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp)

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/README.md`)

# OTLP Trace gRPC Exporter

[](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc)

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/README.md`)

# OTLP Trace HTTP Exporter

[](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp)

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/prometheus/internal/x/README.md`)

# Experimental Features

The `prometheus` exporter contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the `prometheus` exporter prior to stabilization in the specification so that users can start experimenting with them and provide feedback.

These features may change in backwards incompatible ways as feedback is applied.
See the [Compatibility and Stability](#compatibility-and-stability) section for more information.

## Features

- [Observability](#observability)

### Observability

The `prometheus` exporter can be configured to provide observability about itself using OpenTelemetry metrics.

To opt-in, set the environment variable `OTEL_GO_X_OBSERVABILITY` to `true`.

When enabled, the SDK will create the following metrics using the global `MeterProvider`:

- `otel.sdk.exporter.metric_data_point.inflight`
- `otel.sdk.exporter.metric_data_point.exported`
- `otel.sdk.metric_reader.collection.duration`
- `otel.sdk.exporter.operation.duration`

Please see the [Semantic conventions for OpenTelemetry SDK metrics] documentation for more details on these metrics.

[Semantic conventions for OpenTelemetry SDK metrics]: https://github.com/open-telemetry/semantic-conventions/blob/v1.36.0/docs/otel/sdk-metrics.md

## Compatibility and Stability

Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability [policy](../../../../VERSIONING.md).
These features may be removed or modified in successive version releases, including patch versions.

When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.

---

### Overview (`vendor/go.opentelemetry.io/otel/sdk/log/internal/x/README.md`)

# Experimental Features

The Logs SDK contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the OpenTelemetry Go Logs SDK prior to stabilization in the specification so that users can start experimenting with them and provide feedback.

These feature may change in backwards incompatible ways as feedback is applied.
See the [Compatibility and Stability](#compatibility-and-stability) section for more information.

## Features

- [Observability](#observability)

### Observability

The Logs SDK can be configured to provide observability about itself using OpenTelemetry metrics.

To opt-in, set the environment variable `OTEL_GO_X_OBSERVABILITY` to `true`.

When enabled, the SDK will create the following metrics using the global `MeterProvider`:

- `otel.sdk.log.created`
- `otel.sdk.processor.log.queue.capacity`
- `otel.sdk.processor.log.queue.size`
- `otel.sdk.processor.log.processed`

Please see the [Semantic conventions for OpenTelemetry SDK metrics] documentation for more details on these metrics.

[Semantic conventions for OpenTelemetry SDK metrics]: https://github.com/open-telemetry/semantic-conventions/blob/v1.36.0/docs/otel/sdk-metrics.md

## Compatibility and Stability

Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability [policy](../../../../VERSIONING.md).
These features may be removed or modified in successive version releases, including patch versions.

When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.

---

### Overview (`vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/README.md`)

# Experimental Features

The Metric SDK contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the OpenTelemetry Go Metric SDK prior to stabilization in the specification so that users can start experimenting with them and provide feedback.

These feature may change in backwards incompatible ways as feedback is applied.
See the [Compatibility and Stability](#compatibility-and-stability) section for more information.

## Features

- [Metric Export Batch Size](#metric-export-batch-size)

### Metric Export Batch Size

The metric export can be split into batches before exporting by specifying a maximum number of data points per batch.

This experimental feature can be enabled by setting the `OTEL_GO_X_METRIC_EXPORT_BATCH_SIZE` environment variable.
The value MUST be a positive integer.
All other values or an empty value will result in the default behavior of not batching.

#### Examples

Enable metrics to be batched by maximum export batch size of 200.

```console
export OTEL_GO_X_METRIC_EXPORT_BATCH_SIZE=200
```

Disable metric export batching.

```console
unset OTEL_GO_X_METRIC_EXPORT_BATCH_SIZE
```

## Compatibility and Stability

Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability [policy](../../../../VERSIONING.md).
These features may be removed or modified in successive version releases, including patch versions.

When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.

---

### Overview (`vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/README.md`)

# HTTP JSON Error Schema

The `error.proto` represents the HTTP-JSON schema used by Google APIs to convey
error payloads as described by https://cloud.google.com/apis/design/errors#http_mapping.
This package is for internal parsing logic only and should not be used in any
other context.

## Regeneration

To regenerate the protobuf Go code you will need the following:

* A local copy of [googleapis], the absolute path to which should be exported to
the environment variable `GOOGLEAPIS`
* The protobuf compiler [protoc]
* The Go [protobuf plugin]
* The [goimports] tool

From this directory run the following command:
```sh
protoc -I $GOOGLEAPIS -I. --go_out=. --go_opt=module=github.com/googleapis/gax-go/v2/apierror/internal/proto error.proto
goimports -w .
```

Note: the `module` plugin option ensures the generated code is placed in this
directory, and not in several nested directories defined by `go_package` option.

[googleapis]: https://github.com/googleapis/googleapis
[protoc]: https://github.com/protocolbuffers/protobuf#protocol-compiler-installation
[protobuf plugin]: https://developers.google.com/protocol-buffers/docs/reference/go-generated
[goimports]: https://pkg.go.dev/golang.org/x/tools/cmd/goimports

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/stdout/stdoutlog/internal/x/README.md`)

# Experimental Features

The `stdoutlog` exporter contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the `stdoutlog` exporter prior to stabilization in the specification so that users can start experimenting with them and provide feedback.

These features may change in backwards incompatible ways as feedback is applied.
See the [Compatibility and Stability](#compatibility-and-stability) section for more information.

## Features

- [Observability](#observability)

### Observability

The `stdoutlog` exporter can be configured to provide observability about itself using OpenTelemetry metrics.

To opt-in, set the environment variable `OTEL_GO_X_OBSERVABILITY` to `true`.

When enabled, the exporter will create the following metrics using the global `MeterProvider`:

- `otel.sdk.exporter.log.inflight`
- `otel.sdk.exporter.log.exported`
- `otel.sdk.exporter.operation.duration`

Please see the [Semantic conventions for OpenTelemetry SDK metrics] documentation for more details on these metrics.

[Semantic conventions for OpenTelemetry SDK metrics]: https://github.com/open-telemetry/semantic-conventions/blob/v1.36.0/docs/otel/sdk-metrics.md

## Compatibility and Stability

Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability [policy](../../../../../VERSIONING.md).
These features may be removed or modified in successive version releases, including patch versions.

When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/stdout/stdoutmetric/internal/x/README.md`)

# Experimental Features

The `stdoutmetric` exporter contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the `stdoutmetric` exporter prior to stabilization in the specification so that users can start experimenting with them and provide feedback.

These feature may change in backwards incompatible ways as feedback is applied.
See the [Compatibility and Stability](#compatibility-and-stability) section for more information.

## Features

- [Observability](#observability)

### Observability

The `stdoutmetric` exporter provides an observability feature that allows you to monitor the exporter itself.

To opt-in, set the environment variable `OTEL_GO_X_OBSERVABILITY` to `true`.

When enabled, the exporter will create the following metrics using the global `MeterProvider`:

- `otel.sdk.exporter.metric_data_point.inflight`
- `otel.sdk.exporter.metric_data_point.exported`
- `otel.sdk.exporter.operation.duration`

Please see the [Semantic conventions for OpenTelemetry SDK metrics] documentation for more details on these metrics.

[Semantic conventions for OpenTelemetry SDK metrics]: https://github.com/open-telemetry/semantic-conventions/blob/v1.36.0/docs/otel/sdk-metrics.md

## Compatibility and Stability

Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability [policy](../../../../../VERSIONING.md).
These features may be removed or modified in successive version releases, including patch versions.

When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/x/README.md`)

# Experimental Features

The `stdouttrace` exporter contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the `stdouttrace` exporter prior to stabilization in the specification so that users can start experimenting with them and provide feedback.

These features may change in backwards incompatible ways as feedback is applied.
See the [Compatibility and Stability](#compatibility-and-stability) section for more information.

## Features

- [Observability](#observability)

### Observability

The `stdouttrace` exporter can be configured to provide observability about itself using OpenTelemetry metrics.

To opt-in, set the environment variable `OTEL_GO_X_OBSERVABILITY` to `true`.

When enabled, the SDK will create the following metrics using the global `MeterProvider`:

- `otel.sdk.exporter.span.inflight`
- `otel.sdk.exporter.span.exported`
- `otel.sdk.exporter.operation.duration`

Please see the [Semantic conventions for OpenTelemetry SDK metrics] documentation for more details on these metrics.

[Semantic conventions for OpenTelemetry SDK metrics]: https://github.com/open-telemetry/semantic-conventions/blob/v1.36.0/docs/otel/sdk-metrics.md

## Compatibility and Stability

Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability [policy](../../../../../VERSIONING.md).
These features may be removed or modified in successive version releases, including patch versions.

When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc/internal/x/README.md`)

# Experimental Features

The `otlploggrpc` exporter contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the `otlploggrpc` exporter prior to stabilization in the specification so that users can start experimenting with them and provide feedback.

These features may change in backwards incompatible ways as feedback is applied.
See the [Compatibility and Stability](#compatibility-and-stability) section for more information.

## Features

- [Observability](#observability)

### Observability

The `otlploggrpc` exporter can be configured to provide observability about itself using OpenTelemetry metrics.

To opt-in, set the environment variable `OTEL_GO_X_OBSERVABILITY` to `true`.

When enabled, the exporter will create the following metrics using the global `MeterProvider`:

- `otel.sdk.exporter.log.inflight`
- `otel.sdk.exporter.log.exported`
- `otel.sdk.exporter.operation.duration`

Please see the [Semantic conventions for OpenTelemetry SDK metrics] documentation for more details on these metrics.

[Semantic conventions for OpenTelemetry SDK metrics]: https://github.com/open-telemetry/semantic-conventions/blob/v1.36.0/docs/otel/sdk-metrics.md

## Compatibility and Stability

Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability [policy](../../../../../../VERSIONING.md).
These features may be removed or modified in successive version releases, including patch versions.

When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp/internal/x/README.md`)

# Experimental Features

The `otlploghttp` exporter contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the `otlploghttp` exporter prior to stabilization in the specification so that users can start experimenting with them and provide feedback.

These features may change in backwards incompatible ways as feedback is applied.
See the [Compatibility and Stability](#compatibility-and-stability) section for more information.

## Features

- [Observability](#observability)

### Observability

The `otlploghttp` exporter can be configured to provide observability about itself using OpenTelemetry metrics.

To opt-in, set the environment variable `OTEL_GO_X_OBSERVABILITY` to `true`.

When enabled, the exporter will create the following metrics using the global `MeterProvider`:

- `otel.sdk.exporter.log.inflight`
- `otel.sdk.exporter.log.exported`
- `otel.sdk.exporter.operation.duration`

Please see the [Semantic conventions for OpenTelemetry SDK metrics] documentation for more details on these metrics.

[Semantic conventions for OpenTelemetry SDK metrics]: https://github.com/open-telemetry/semantic-conventions/blob/v1.36.0/docs/otel/sdk-metrics.md

## Compatibility and Stability

Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability [policy](../../../../../../VERSIONING.md).
These features may be removed or modified in successive version releases, including patch versions.

When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.

---

### Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/x/README.md`)

# Experimental Features

The `otlptracegrpc` exporter contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the `otlptracegrpc` exporter prior to stabilization in the specification so that users can start experimenting with them and provide feedback.

These feature may change in backwards incompatible ways as feedback is applied.
See the [Compatibility and Stability](#compatibility-and-stability) section for more information.

## Features

- [Observability](#observability)

### Observability

The `otlptracegrpc` exporter provides a observability feature that allows you to monitor the SDK itself.

To opt-in, set the environment variable `OTEL_GO_X_OBSERVABILITY` to `true`.

When enabled, the SDK will create the following metrics using the global `MeterProvider`:

- `otel.sdk.exporter.span.inflight`
- `otel.sdk.exporter.span.exported`
- `otel.sdk.exporter.operation.duration`

Please see the [Semantic conventions for OpenTelemetry SDK metrics] documentation for more details on these metrics.

[Semantic conventions for OpenTelemetry SDK metrics]: https://github.com/open-telemetry/semantic-conventions/blob/v1.37.0/docs/otel/sdk-metrics.md

## Compatibility and Stability

Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability [policy](../../../../../../VERSIONING.md).
These features may be removed or modified in successive version releases, including patch versions.

When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.

---

### Content  Index (`docs/content/_index.md`)

---
description: High-level overview of the Registry
keywords: registry, on-prem, images, tags, repository, distribution
title: Distribution Registry
---

## What it is

The Registry is a stateless, highly scalable server side application that stores
and lets you distribute container images and other content. The Registry is open-source, under the
permissive [Apache license](https://en.wikipedia.org/wiki/Apache_License).

## Why use it

You should use the Registry if you want to:

 * tightly control where your images are being stored
 * fully own your images distribution pipeline
 * integrate image storage and distribution tightly into your in-house development workflow

## Alternatives

Users looking for a zero maintenance, ready-to-go solution are encouraged to
use one of the existing registry services. Many of these provide support and security
scanning, and are free for public repositories. For example:
- [Docker Hub](https://hub.docker.com)
- [Quay.io](https://quay.io/)
- [GitHub Packages](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry)

Cloud infrastructure providers such as [AWS](https://aws.amazon.com/ecr/), [Azure](https://azure.microsoft.com/products/container-registry/), [Google Cloud](https://cloud.google.com/artifact-registry) and [IBM Cloud](https://www.ibm.com/products/container-registry) also have container registry services available at a cost.

## Compatibility

The distribution registry implements the [OCI Distribution Spec](https://github.com/opencontainers/distribution-spec) version 1.0.1.

## Basic commands

Start your registry

```sh
docker run -d -p 5000:5000 --name registry registry:3
```

Pull (or build) some image from the hub

```sh
docker pull ubuntu
```

Tag the image so that it points to your registry

```sh
docker image tag ubuntu localhost:5000/myfirstimage
```

Push it

```sh
docker push localhost:5000/myfirstimage
```

Pull it back

```sh
docker pull localhost:5000/myfirstimage
```

Now stop your registry and remove all data

```sh
docker container stop registry && docker container rm -v registry
```

## Next

You should now read the [detailed introduction about the registry](about),
or jump directly to [deployment instructions](about/deploying).

---

### Content About  Index (`docs/content/about/_index.md`)

---
description: Explains what the Registry is, basic use cases and requirements
keywords: registry, on-prem, images, tags, repository, distribution, use cases, requirements
title: About Registry
---

A registry is a storage and content delivery system, holding named container
images and other content, available in different tagged versions.

  > Example: the image `distribution/registry`, with tags `2.8` and `3.0`.

Users interact with a registry by pushing and pulling images.

  > Example: `docker pull registry-1.docker.io/distribution/registry:3.0`.

Storage itself is delegated to drivers. The default storage driver is the local
posix filesystem, which is suitable for development or small deployments.
Additional cloud-based storage drivers like S3, Microsoft Azure and Google Cloud Storage
are supported.  People looking into using other storage drivers should consider if
the driver they'd like to be supported is S3 compatible like many cloud storage systems
as adding new storage driver support has been put on hold for the time being.

Since securing access to your hosted images is paramount, the Registry natively
supports TLS and basic authentication.

The Registry GitHub repository includes additional information about advanced
authentication and authorization methods. Only very large or public deployments
are expected to extend the Registry in this way.

Finally, the Registry ships with a robust [notification system](notifications),
calling webhooks in response to activity, and both extensive logging and reporting,
mostly useful for large installations that want to collect metrics.

## Understanding image naming

Image names as used in typical docker commands reflect their origin:

 * `docker pull ubuntu` instructs docker to pull an image named `ubuntu` from Docker Hub. This is simply a shortcut for the longer `docker pull docker.io/library/ubuntu` command
 * `docker pull myregistrydomain:port/foo/bar` instructs docker to contact the registry located at `myregistrydomain:port` to find the image `foo/bar`

You can find out more about the various Docker commands dealing with images in
the [Docker engine documentation](https://docs.docker.com/engine/reference/commandline/cli/).

## Use cases

Running your own Registry is a great solution to integrate with and complement
your CI/CD system. In a typical workflow, a commit to your source revision
control system would trigger a build on your CI system, which would then push a
new image to your Registry if the build is successful. A notification from the
Registry would then trigger a deployment on a staging environment, or notify
other systems that a new image is available.

It's also an essential component if you want to quickly deploy a new image over
a large cluster of machines.

Finally, it's the best way to distribute images inside an isolated network.

## Requirements

You absolutely need to be familiar with Docker, specifically with regard to
pushing and pulling images. You must understand the difference between the
daemon and the cli, and at least grasp basic concepts about networking.

Also, while just starting a registry is fairly easy, operating it in a
production environment requires operational skills, just like any other service.
You are expected to be familiar with systems availability and scalability,
logging and log processing, systems monitoring, and security 101. Strong
understanding of http and overall network communications, plus familiarity with
golang are certainly useful as well for advanced operations or hacking.

## Next

Dive into [deploying your registry](deploying)

---

### Content Recipes  Index (`docs/content/recipes/_index.md`)

---
description: Fun stuff to do with your registry
keywords: registry, on-prem, images, tags, repository, distribution, recipes, advanced
title: Recipes overview
---

This list of "recipes" provides end-to-end scenarios for exotic or otherwise advanced use-cases.
These recipes are not useful for most standard set-ups.

## Requirements

Before following these steps, work through the [deployment guide](../about/deploying).

At this point, it's assumed that:

 * you understand Docker security requirements, and how to configure your docker engines properly
 * you have installed Docker Compose
 * it's HIGHLY recommended that you get a certificate from a known CA instead of self-signed certificates
 * inside the current directory, you have a X509 `domain.crt` and `domain.key`, for the CN `myregistrydomain.com`
 * be sure you have stopped and removed any previously running registry (typically `docker container stop registry && docker container rm -v registry`)

## The List

 * [using Apache as an authenticating proxy](apache)
 * [using Nginx as an authenticating proxy](nginx)
 * [running a Registry on macOS](osx-setup-guide)
 * [mirror the Docker Hub](mirror)
 * [start registry via systemd](systemd)

---

### Content Spec  Index (`docs/content/spec/_index.md`)

---
title: "Reference Overview"
description: "Explains registry JSON objects"
keywords: registry, service, images, repository,  json
---

# Docker Registry Reference

* [HTTP API V2](api.md)
* [Storage Driver](../storage-drivers/_index.md)
* [Token Authentication Specification](auth/token.md)
* [Token Authentication Implementation](auth/jwt.md)

---

### Content Storage Drivers  Index (`docs/content/storage-drivers/_index.md`)

---
description: Explains how to use storage drivers
keywords: registry, on-prem, images, tags, repository, distribution, storage drivers, advanced
title: Registry storage driver
---

This document describes the registry storage driver model, implementation, and explains how to contribute new storage drivers.

## Provided drivers

This storage driver package comes bundled with several drivers:

- [inmemory](inmemory): A temporary storage driver using a local inmemory map. This exists solely for reference and testing.
- [filesystem](filesystem): A local storage driver configured to use a directory tree in the local filesystem.
- [s3](s3): A driver storing objects in an Amazon Simple Storage Service (S3) bucket.
- [azure](azure): A driver storing objects in [Microsoft Azure Blob Storage](https://azure.microsoft.com/en-us/services/storage/).
- [gcs](gcs): A driver storing objects in a [Google Cloud Storage](https://cloud.google.com/storage/) bucket.
- oss: *NO LONGER SUPPORTED*
- swift: *NO LONGER SUPPORTED*

## Storage driver API

The storage driver API is designed to model a filesystem-like key/value storage in a manner abstract enough to support a range of drivers from the local filesystem to Amazon S3 or other distributed object storage systems.

Storage drivers are required to implement the `storagedriver.StorageDriver` interface provided in `storagedriver.go`, which includes methods for reading, writing, and deleting content, as well as listing child objects of a specified prefix key.

Storage drivers are intended to be written in Go, providing compile-time
validation of the `storagedriver.StorageDriver` interface.

## Driver selection and configuration

The preferred method of selecting a storage driver is using the `StorageDriverFactory` interface in the `storagedriver/factory` package. These factories provide a common interface for constructing storage drivers with a parameters map. The factory model is based on the [Register](https://golang.org/pkg/database/sql/#Register) and [Open](https://golang.org/pkg/database/sql/#Open) methods in the builtin [database/sql](https://golang.org/pkg/database/sql) package.

Storage driver factories may be registered by name using the
`factory.Register` method, and then later invoked by calling `factory.Create`
with a driver name and parameters map. If no such storage driver can be found,
`factory.Create` returns an `InvalidStorageDriverError`.

## Driver contribution

New storage drivers are not currently being accepted.
See <https://github.com/distribution/distribution/issues/3988> for discussion.

There are forks of this repo that implement custom storage drivers.
These are not supported by the OCI distribution project.
The known forks are:

- Storj DCS: <https://github.com/storj/docker-registry>
- HuaweiCloud OBS: <https://github.com/setoru/distribution/tree/obs>
- us3: <https://github.com/lambertxiao/distribution/tree/main>
- Baidu BOS: <https://github.com/dolfly/distribution/tree/bos>
- HDFS: <https://github.com/haosdent/distribution/tree/master>

### Writing new storage drivers

To create a valid storage driver, one must implement the
`storagedriver.StorageDriver` interface and make sure to expose this driver
via the factory system.

#### Registering

Storage drivers should call `factory.Register` with their driver name in an `init` method, allowing callers of `factory.New` to construct instances of this driver without requiring modification of imports throughout the codebase.

## Testing

Storage driver test suites are provided in
`storagedriver/testsuites/testsuites.go` and may be used for any storage
driver written in Go. Tests can be registered using the `RegisterSuite`
function, which run the same set of tests for any registered drivers.

---

### Content Spec Auth  Index (`docs/content/spec/auth/_index.md`)

---
title: "Distribution Registry Token Authentication"
description: "Distribution Registry v2 authentication schema"
keywords: registry, on-prem, images, tags, repository, distribution, authentication, advanced
---

# Distribution Registry v2 authentication

See the [Token Authentication Specification](token),
[Token Authentication Implementation](jwt),
[Token Scope Documentation](scope),
[OAuth2 Token Authentication](oauth) for more information.

---

### Content Storage Drivers Middleware  Index (`docs/content/storage-drivers/middleware/_index.md`)

---
description: Explains how to use storage middleware
keywords: registry, on-prem, images, tags, repository, distribution, storage drivers, advanced
title: Storage middleware
---

This document describes the registry storage middleware.

## Provided middleware

This storage driver package comes bundled with several middleware options:

- cloudfront
- redirect
- [rewrite](rewrite): Partially rewrites the URL returned by the storage driver.

---

### .Htmltest.Yml (`docs/.htmltest.yml`)

DirectoryPath: "public"
EnforceHTTPS: true
CheckDoctype: true
CheckExternal: true
IgnoreAltMissing: true
IgnoreAltEmpty: true
IgnoreEmptyHref: true
IgnoreInternalEmptyHash: true
IgnoreDirectoryMissingTrailingSlash: true

---

### Dockerhub (`docs/dockerhub.md`)

# Distribution

This repository provides container images for the Open Source Registry implementation for storing and distributing container artifacts in conformance with the
[OCI Distribution Specification](https://github.com/opencontainers/distribution-spec).

<img src="https://raw.githubusercontent.com/distribution/distribution/main/distribution-logo.svg" width="200px" />

[](https://github.com/distribution/distribution/actions/workflows/build.yml?query=workflow%3Abuild)
[](https://github.com/distribution/distribution/actions?query=workflow%3Aconformance)
[](LICENSE)

## Quick start

Run the registry locally with the [default configuration](https://github.com/distribution/distribution/blob/main/cmd/registry/config-dev.yml):
```
docker run -d -p 5000:5000 --restart always --name registry distribution/distribution:edge
```

*NOTE:* in order to run push/pull against the locally run registry you must allow
your docker (containerd) engine to use _insecure_ registry by editing `/etc/docker/daemon.json` and subsequently restarting it
```
{
     "insecure-registries": ["host.docker.internal:5000"]
}
```

Now you are ready to use it:
```
docker pull alpine
docker tag alpine localhost:5000/alpine
docker push localhost:5000/alpine
```

⚠️  Beware the default configuration uses [`filesystem` storage driver](https://github.com/distribution/distribution/blob/main/docs/content/storage-drivers/filesystem.md)
and the above example command does not mount a local filesystem volume into the running container.
If you wish to mount the local filesystem to the `rootdirectory` of the
`filesystem` storage driver run the following command:
```
docker run -d -p 5000:5000 -v $PWD/FS/PATH:/var/lib/registry --restart always --name registry distribution/distribution:edge
```

### Custom configuration

If you don't wan to use the default configuration file, you can supply
your own custom configuration file as follows:
```
docker run -d -p 5000:5000 -v $PWD/PATH/TO/config.yml:/etc/distribution/config.yml --restart always --name registry distribution/distribution:edge
```

## Communication

For async communication and long-running discussions please use issues and pull requests
on the [GitHub repo](https://github.com/distribution/distribution).

For sync communication we have a #distribution channel in the [CNCF Slack](https://slack.cncf.io/)
that everyone is welcome to join and chat about development.

---

### Hugo.Yaml (`docs/hugo.yaml`)

baseURL: https://distribution.github.io/distribution
languageCode: en-us
title: CNCF Distribution
theme: hugo-geekdoc

markup:
  goldmark:
    renderer:
      unsafe: true

pluralizeListTitles: false
enableRobotsTXT: true
taxonomies: [tags]
minify:
  disableHTML: true

# Geekdoc required configuration
pygmentsUseClasses: true
pygmentsCodeFences: true
disablePathToLower: true

params:
  geekdocRepo: "https://github.com/distribution/distribution"
  geekdocEditPath: edit/main/docs
  geekdocLegalNotice: "https://www.linuxfoundation.org/legal/trademark-usage"
  geekdocContentLicense:
    name: CC BY 4.0
    link: https://creativecommons.org/licenses/by/4.0/

---

### Content About Architecture (`docs/content/about/architecture.md`)

---
draft: true
---

# Architecture

## Design
**TODO(stevvooe):** Discuss the architecture of the registry, internally and externally, in a few different deployment scenarios.

### Eventual Consistency

> **NOTE:** This section belongs somewhere, perhaps in a design document. We
> are leaving this here so the information is not lost.

Running the registry on eventually consistent backends has been part of the
design from the beginning. This section covers some of the approaches to
dealing with this reality.

There are a few classes of issues that we need to worry about when
implementing something on top of the storage drivers:

1. Read-After-Write consistency (see this [article on
   s3](http://shlomoswidler.com/2009/12/read-after-write-consistency-in-amazon.html)).
2. [Write-Write Conflicts](http://en.wikipedia.org/wiki/Write%E2%80%93write_conflict).

In reality, the registry must worry about these kinds of errors when doing the
following:

1. Accepting data into a temporary upload file may not have latest data block
   yet (read-after-write).
2. Moving uploaded data into its blob location (write-write race).
3. Modifying the "current" manifest for given tag (write-write race).
4. A whole slew of operations around deletes (read-after-write, delete-write
   races, garbage collection, etc.).

The backend path layout employs a few techniques to avoid these problems:

1. Large writes are done to private upload directories. This alleviates most
   of the corruption potential under multiple writers by avoiding multiple
   writers.
2. Constraints in storage driver implementations, such as support for writing
   after the end of a file to extend it.
3. Digest verification to avoid data corruption.
4. Manifest files are stored by digest and cannot change.
5. All other non-content files (links, hashes, etc.) are written as an atomic
   unit. Anything that requires additions and deletions is broken out into
   separate "files". Last writer still wins.

Unfortunately, one must play this game when trying to build something like
this on top of eventually consistent storage systems. If we run into serious
problems, we can wrap the storagedrivers in a shared consistency layer but
that would increase complexity and hinder registry cluster performance.

---

### Content About Compatibility (`docs/content/about/compatibility.md`)

---
description: describes get by digest pitfall
keywords: registry, manifest, images, tags, repository, distribution, digest
title: Registry compatibility
---

## Synopsis

If a manifest is pulled by _digest_ from a registry 2.3 with Docker Engine 1.9
and older, and the manifest was pushed with Docker Engine 1.10, a security check
causes the Engine to receive a manifest it cannot use and the pull fails.

## Registry manifest support

Historically, the registry has supported a single manifest type
known as _Schema 1_.

With the move toward multiple architecture images, the distribution project
introduced two new manifest types: Schema 2 manifests and manifest lists. Registry
2.3 supports all three manifest types and sometimes performs an on-the-fly
transformation of a manifest before serving the JSON in the response, to
preserve compatibility with older versions of Docker Engine.

This conversion has some implications for pulling manifests by digest and this
document enumerates these implications.

## Content Addressable Storage (CAS)

Manifests are stored and retrieved in the registry by keying off a digest
representing a hash of the contents. One of the advantages provided by CAS is
security: if the contents are changed, then the digest no longer matches.
This prevents any modification of the manifest by a MITM attack or an untrusted
third party.

When a manifest is stored by the registry, this digest is returned in the HTTP
response headers and, if events are configured, delivered within the event. The
manifest can either be retrieved by the tag, or this digest.

For registry versions 2.2.1 and below, the registry always stores and
serves _Schema 1_ manifests. Engine 1.10 first
attempts to send a _Schema 2_ manifest, falling back to sending a
Schema 1 type manifest when it detects that the registry does not
support the new version.

## Registry v2.3

### Manifest push with Docker 1.10

The Engine constructs a _Schema 2_ manifest which the
registry persists to disk.

When the manifest is pulled by digest or tag with Docker Engine 1.10, a
_Schema 2_ manifest is returned. Docker Engine 1.10
understands the new manifest format.

When the manifest is pulled by *tag* with Docker Engine 1.9 and older, the
manifest is converted on-the-fly to _Schema 1_ and sent in the
response. The Docker Engine 1.9 is compatible with this older format.

When the manifest is pulled by _digest_ with Docker Engine 1.9 and older, the
same rewriting process does not happen in the registry. If it did,
the digest would no longer match the hash of the manifest and would violate the
constraints of CAS.

For this reason if a manifest is pulled by _digest_ from a registry 2.3 with Docker
Engine 1.9 and older, and the manifest was pushed with Docker Engine 1.10, a
security check causes the Engine to receive a manifest it cannot use and the
pull fails.

### Manifest push with Docker 1.9 and older

The Docker Engine constructs a _Schema 1_ manifest which the
registry persists to disk.

When the manifest is pulled by digest or tag with any Docker version, a
_Schema 1_ manifest is returned.

---

### Content About Configuration (`docs/content/about/configuration.md`)

---
title: "Configuring a registry"
description: "Explains how to configure a registry"
keywords: registry, on-prem, images, tags, repository, distribution, configuration
---

The Registry configuration is based on a YAML file, detailed below. While it
comes with sane default values out of the box, you should review it exhaustively
before moving your systems to production.

## Override specific configuration options

In a typical setup where you run your registry as a container, you can
specify a configuration variable from the environment by passing `-e` arguments
to your `docker run` stanza or from within a Dockerfile using the `ENV`
instruction.

To override a configuration option, create an environment variable named
`REGISTRY_variable` where `variable` is the name of the configuration option
and the `_` (underscore) represents indention levels. For example, you can
configure the `rootdirectory` of the `filesystem` storage backend:

```yaml
storage:
  filesystem:
    rootdirectory: /var/lib/registry
```

To override this value, set an environment variable like this:

```sh
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/somewhere
```

This variable overrides the `/var/lib/registry` value to the `/somewhere`
directory.

In order to override elements of a list, provide the index of the element
you wish to change as part of the path to that element. For example, to
configure the `hosts` list under `letsencrypt`:

```yaml
http:
  tls:
    letsencrypt:
      hosts: [myregistryaddress.org]
```

The corresponding environment variable would be:

```sh
REGISTRY_HTTP_TLS_LETSENCRYPT_HOSTS_0=registry.example.com
```

> **Note**: Create a base configuration file with environment variables that can
> be configured to tweak individual values. Overriding configuration sections
> with environment variables is not recommended.

### Disable traces export

Currently traces are set to `https://localhost:4318/v1/traces` by default.
You can control this by setting the [environment variable](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#exporter-selection) `OTEL_TRACES_EXPORTER`
to either `none` or your trace collector.

## Overriding the entire configuration file

If the default configuration is not a sound basis for your usage, or if you are
having issues overriding keys from the environment, you can specify an alternate
YAML configuration file by mounting it as a volume in the container.

Typically, create a new configuration file from scratch,named `config.yml`, then
specify it in the `docker run` command:

```bash
$ docker run -d -p 5000:5000 --restart=always --name registry \
             -v `pwd`/config.yml:/etc/distribution/config.yml \
             registry:3
```

Use this
[example YAML file](https://github.com/distribution/distribution/blob/master/cmd/registry/config-example.yml)
as a starting point.

## List of configuration options

These are all configuration options for the registry. Some options in the list
are mutually exclusive. Read the detailed reference information about each
option before finalizing your configuration.

```
/* Detailed source-code truncated for AI context efficiency. */
```

In some instances a configuration option is **optional** but it contains child
options marked as **required**. In these cases, you can omit the parent with
all its children. However, if the parent is included, you must also include all
the children marked **required**.

## `version`

```yaml
version: 0.1
```

The `version` option is **required**. It specifies the configuration's version.
It is expected to remain a top-level field, to allow for a consistent version
check before parsing the remainder of the configuration file.

## `log`

The `log` subsection configures the behavior of the logging system. The logging
system outputs everything to stderr. You can adjust the granularity and format
with this configuration section.

```yaml
log:
  accesslog:
    disabled: true
  level: debug
  formatter: text
  fields:
    service: registry
    environment: staging
```

| Parameter   | Required | Description |
|-------------|----------|-------------|
| `level`     | no       | Sets the sensitivity of logging output. Permitted values are `error`, `warn`, `info`, and `debug`. The default is `info`. |
| `formatter` | no       | This selects the format of logging output. The format primarily affects how keyed attributes for a log line are encoded. Options are `text`, `json`, and `logstash`. The default is `text`. |
| `fields`    | no       | A map of field names to values. These are added to every log line for the context. This is useful for identifying log messages source after being mixed in other systems. |

### `accesslog`

```yaml
accesslog:
  disabled: true
```

Within `log`, `accesslog` configures the behavior of the access logging
system. By default, the access logging system outputs to stdout in
[Combined Log Format](https://httpd.apache.org/docs/2.4/logs.html#combined).
Access logging can be disabled by setting the boolean flag `disabled` to `true`.

## `hooks`

```yaml
hooks:
  - type: mail
    levels:
      - panic
    options:
      smtp:
        addr: smtp.sendhost.com:25
        username: sendername
        password: password
        insecure: true
      from: name@sendhost.com
      to:
        - name@receivehost.com
```

The `hooks` subsection configures the logging hooks' behavior. This subsection
includes a sequence handler which you can use for sending mail, for example.
Refer to `loglevel` to configure the level of messages printed.

## `loglevel`

> **DEPRECATED:** Please use [log](#log) instead.

```yaml
loglevel: debug
```

Permitted values are `error`, `warn`, `info` and `debug`. The default is
`info`.

## `storage`

```
/* Detailed source-code truncated for AI context efficiency. */
```

The `storage` option is **required** and defines which storage backend is in
use. You must configure exactly one backend. If you configure more, the registry
returns an error. You can choose any of these backend storage drivers:

| Storage driver | Description                                                                                                                                                                                                                 |
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `filesystem`   | Uses the local disk to store registry files. It is ideal for development and may be appropriate for some small-scale production applications. See the [driver's reference documentation](../storage-drivers/filesystem.md). |
| `azure`        | Uses Microsoft Azure Blob Storage. See the [driver's reference documentation](../storage-drivers/azure.md).                                                                                                                 |
| `gcs`          | Uses Google Cloud Storage. See the [driver's reference documentation](../storage-drivers/gcs.md).                                                                                                                           |
| `s3`           | Uses Amazon Simple Storage Service (S3) and compatible Storage Services. See the [driver's reference documentation](../storage-drivers/s3.md).                                                                              |

For testing only, you can use the [`inmemory` storage
driver](../storage-drivers/inmemory.md).
If you would like to run a registry from volatile memory, use the
[`filesystem` driver](../storage-drivers/filesystem.md)
on a ramdisk.

If you are deploying a registry on Windows, a Windows volume mounted from the
host is not recommended. Instead, you can use a S3 or Azure backing
data-store. If you do use a Windows volume, the length of the `PATH` to
the mount point must be within the `MAX_PATH` limits (typically 255 characters),
or this error will occur:

```text
mkdir /XXX protocol error and your registry will not function properly.
```

### `maintenance`

Currently, upload purging and read-only mode are the only `maintenance`
functions available.

### `uploadpurging`

Upload purging is a background process that periodically removes orphaned files
from the upload directories of the registry. Upload purging is enabled by
default. To configure upload directory purging, the following parameters must
be set.


| Parameter  | Required | Description                                                                                        |
|------------|----------|----------------------------------------------------------------------------------------------------|
| `enabled`  | yes      | Set to `true` to enable upload purging. Defaults to `true`.                                        |
| `age`      | yes      | Upload directories which are older than this age will be deleted.Defaults to `168h` (1 week).      |
| `interval` | yes      | The interval between upload directory purging. Defaults to `24h`.                                  |
| `dryrun`   | yes      | Set `dryrun` to `true` to obtain a summary of what directories will be deleted. Defaults to `false`.|

> **Note**: `age` and `interval` are strings containing a number with optional
fraction and a unit suffix. Some examples: `45m`, `2h10m`, `168h`.

### `readonly`

If the `readonly` section under `maintenance` has `enabled` set to `true`,
clients will not be allowed to write to the registry. This mode is useful to
temporarily prevent writes to the backend storage so a garbage collection pass
can be run.  Before running garbage collection, the registry should be
restarted with readonly's `enabled` set to true. After the garbage collection
pass finishes, the registry may be restarted again, this time with `readonly`
removed from the configuration (or set to false).

### `delete`

Use the `delete` structure to enable the deletion of image blobs and manifests
by digest. It defaults to false, but it can be enabled by writing the following
on the configuration file:

```yaml
delete:
  enabled: true
```

### `cache`

Use the `cache` structure to enable caching of data accessed in the storage
backend. Currently, the only available cache provides fast access to layer
metadata, which uses the `blobdescriptor` field if configured.

You can set `blobdescriptor` field to `redis` or `inmemory`. If set to `redis`,a
Redis pool caches layer metadata. If set to `inmemory`, an in-memory map caches
layer metadata.

> **NOTE**: Formerly, `blobdescriptor` was known as `layerinfo`. While these
> are equivalent, `layerinfo` has been deprecated.

If `blobdescriptor` is set to `inmemory`, the optional `blobdescriptorsize`
parameter sets a limit on the number of descriptors to store in the cache.
The default value is 10000. If this parameter is set to 0, the cache is allowed
to grow with no size limit.

### `tag`

The `tag` subsection provides configuration to set concurrency limit for tag lookup.
When user calls into the registry to delete the manifest, which in turn then does a
lookup for all tags that reference the deleted manifest. To find the tag references,
the registry will iterate every tag in the repository and read it's link file to check
if it matches the deleted manifest (i.e. to see if uses the same sha256 digest).
So, the more tags in repository, the worse the performance will be (as there will
be more S3 API calls occurring for the tag directory lookups and tag file reads if
using S3 storage driver).

Therefore, add a single flag `concurrencylimit` to set concurrency limit to optimize tag
lookup performance under the `tag` section. When a value is not provided or equal to 0,
`GOMAXPROCS` will be used.

```yaml
tag:
  concurrencylimit: 8
```

### `redirect`

The `redirect` subsection provides configuration for managing redirects from
content backends. For backends that support it, redirecting is enabled by
default. In certain deployment scenarios, you may decide to route all data
through the Registry, rather than redirecting to the backend. This may be more
efficient when using a backend that is not co-located or when a registry
instance is aggressively caching.

To disable redirects, add a single flag `disable`, set to `true`
under the `redirect` section:

```yaml
redirect:
  disable: true
```

## `auth`

```yaml
auth:
  silly:
    realm: silly-realm
    service: silly-service
  token:
    realm: token-realm
    service: token-service
    issuer: registry-token-issuer
    rootcertbundle: /root/certs/bundle
    jwks: /path/to/jwks
    signingalgorithms:
        - EdDSA
        - HS256
        - ES512
  htpasswd:
    realm: basic-realm
    path: /path/to/htpasswd
```

The `auth` option is **optional**. Possible auth providers include:

- [`silly`](#silly)
- [`token`](#token)
- [`htpasswd`](#htpasswd)
- [`none`]

You can configure only one authentication provider.

### `silly`

The `silly` authentication provider is only appropriate for development. It simply checks
for the existence of the `Authorization` header in the HTTP request. It does not
check the header's value. If the header does not exist, the `silly` auth
responds with a challenge response, echoing back the realm, service, and scope
for which access was denied.

The following values are used to configure the response:

| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `realm`   | yes      | The realm in which the registry server authenticates. |
| `service` | yes      | The service being authenticated.                      |

### `token`

Token-based authentication allows you to decouple the authentication system from
the registry. It is an established authentication paradigm with a high degree of
security.

| Parameter            | Required | Description                                           |
|----------------------|----------|-------------------------------------------------------|
| `realm`              | yes      | The realm in which the registry server authenticates. |
| `service`            | yes      | The service being authenticated.                      |
| `issuer`             | yes      | The name of the token issuer. The issuer inserts this into the token so it must match the value configured for the issuer. |
| `rootcertbundle`     | yes      | The absolute path to the root certificate bundle. This bundle contains the public part of the certificates used to sign authentication tokens. |
| `autoredirect`       | no       | When set to `true`, `realm` will be set to the Host header of the request as the domain and a path of `/auth/token/`(or specified by `autoredirectpath`), the `realm` URL Scheme will use `X-Forwarded-Proto` header if set, otherwise it will be set to `https`. |
| `autoredirectpath`   | no       | The path to redirect to if `autoredirect` is set to `true`, default: `/auth/token/`. |
| `signingalgorithms`  | no       | A list of token signing algorithms to use for verifying token signatures. If left empty the default list of signing algorithms is used. Please see below for allowed values and default. |
| `jwks`               | no       | The absolute path to the JSON Web Key Set (JWKS) file. The JWKS file contains the trusted keys used to verify the signature of authentication tokens. |

Available `signingalgorithms`:
- EdDSA
- HS256
- HS384
- HS512
- RS256
- RS384
- RS512
- ES256
- ES384
- ES512
- PS256
- PS384
- PS512

Default `signingalgorithms`:
- EdDSA
- HS256
- HS384
- HS512
- RS256
- RS384
- RS512
- ES256
- ES384
- ES512
- PS256
- PS384
- PS512

Additional notes on `rootcertbundle`:

- The public key of this certificate will be automatically added to the list of known keys.
- The public key will be identified by its JWK Thumbprint. See [RFC 7638](https://datatracker.ietf.org/doc/html/rfc7638) and [RFC 8037](https://datatracker.ietf.org/doc/html/rfc8037) for reference.

For more information about Token based authentication configuration, see the
[specification](../spec/auth/token.md).

### `htpasswd`

The _htpasswd_ authentication backed allows you to configure basic
authentication using an
[Apache htpasswd file](https://httpd.apache.org/docs/2.4/programs/htpasswd.html).
The only supported password format is
[`bcrypt`](https://en.wikipedia.org/wiki/Bcrypt). Entries with other hash types
are ignored. The `htpasswd` file is loaded once, at startup. If the file is
invalid, the registry will display an error and will not start.

> **Warning**: If the `htpasswd` file is missing, the file will be created and provisioned with a default user and automatically generated password.
> The password will be printed to stdout.

> **Warning**: Only use the `htpasswd` authentication scheme with TLS
> configured, since basic authentication sends passwords as part of the HTTP
> header.

| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `realm`   | yes      | The realm in which the registry server authenticates. |
| `path`    | yes      | The path to the `htpasswd` file to load at startup.   |

## `middleware`

The `middleware` structure is **optional**. Use this option to inject middleware at
named hook points. Each middleware must implement the same interface as the
object it is wrapping. For instance, a registry middleware must implement the
`distribution.Namespace` interface, while a repository middleware must implement
`distribution.Repository`, and a storage middleware must implement
`driver.StorageDriver`.

This is an example configuration of the `cloudfront`  middleware, a storage
middleware:

```yaml
middleware:
  registry:
    - name: ARegistryMiddleware
      options:
        foo: bar
  repository:
    - name: ARepositoryMiddleware
      options:
        foo: bar
  storage:
    - name: cloudfront
      options:
        baseurl: https://my.cloudfronted.domain.com/
        privatekey: /path/to/pem
        keypairid: cloudfrontkeypairid
        duration: 3000s
        ipfilteredby: awsregion
        awsregion: us-east-1, use-east-2
        updatefrequency: 12h
        iprangesurl: https://ip-ranges.amazonaws.com/ip-ranges.json
```

Each middleware entry has `name` and `options` entries. The `name` must
correspond to the name under which the middleware registers itself. The
`options` field is a map that details custom configuration required to
initialize the middleware. It is treated as a `map[string]interface{}`. As such,
it supports any interesting structures desired, leaving it up to the middleware
initialization function to best determine how to handle the specific
interpretation of the options.

### `cloudfront`


| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `baseurl` | yes      | The `SCHEME://HOST[/PATH]` at which Cloudfront is served. |
| `privatekey` | yes   | The private key for Cloudfront, provided by AWS.        |
| `keypairid` | yes    | The key pair ID provided by AWS.                         |
| `duration` | no      | An integer and unit for the duration of the Cloudfront session. Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, or `h`. For example, `3000s` is valid, but `3000 s` is not. If you do not specify a `duration` or you specify an integer without a time unit, the duration defaults to `20m` (20 minutes). |
| `ipfilteredby` | no     | A string with the following value `none`, `aws` or `awsregion`. |
| `awsregion` | no        | A comma separated string of AWS regions, only available when `ipfilteredby` is `awsregion`. For example, `us-east-1, us-west-2` |
| `updatefrequency`  | no | The frequency to update AWS IP regions, default: `12h` |
| `iprangesurl` | no      | The URL contains the AWS IP ranges information, default: `https://ip-ranges.amazonaws.com/ip-ranges.json` |


Value of `ipfilteredby` can be:

| Value       | Description                        |
|-------------|------------------------------------|
| `none`      | default, do not filter by IP       |
| `aws`       | IP from AWS goes to S3 directly    |
| `awsregion` | IP from certain AWS regions goes to S3 directly, use together with `awsregion`. |

### `redirect`

You can use the `redirect` storage middleware to specify a custom URL to a
location of a proxy for the layer stored by the S3 storage driver.

| Parameter | Required | Description                                                                                                 |
|-----------|----------|-------------------------------------------------------------------------------------------------------------|
| `baseurl` | yes      | `SCHEME://HOST` at which layers are served. Can also contain port. For example, `https://example.com:5443`. |

## `catalog`

The `catalog` subsection provides configuration to limit the maximum number of
entries returned in a single response from the catalog API endpoint
(`/v2/_catalog`). When a client does not specify the `n` query parameter, at
most 100 entries are returned. When a client requests more than `maxentries`
via the `n` query parameter, the server rejects the request with a
`400 Bad Request` response and a `PAGINATION_NUMBER_INVALID` error.

The catalog endpoint is designed for registry synchronization with search or
other API systems, and serving a request may put significant load on the
backend storage. It is strongly recommended to keep this endpoint behind
heightened privilege and avoid exposing it to the internet.

```yaml
catalog:
  maxentries: 1000
```

| Parameter    | Required | Description                                                                               |
|--------------|----------|-------------------------------------------------------------------------------------------|
| `maxentries` | no       | Overrides the maximum number of entries returned by the catalog endpoint, default: `1000` |

## `tags`

The `tags` subsection provides configuration to limit the maximum number of tags
returned in a single response from the tags API endpoint. When a client requests
more than `maxtags` via the `n` query parameter, the server returns `maxtags`
results along with a `Link` header so the client can paginate to retrieve the
rest.

```yaml
tags: 
  maxtags: 100
```

| Parameter | Required | Description                                                                         |
|-----------|----------|-------------------------------------------------------------------------------------|
| `maxtags` | no       | Overrides the maximum number of tags returned by the tags endpoint, default: `1000` |

## `http`

```yaml
http:
  addr: localhost:5000
  net: tcp
  prefix: /my/nested/registry/
  host: https://myregistryaddress.org:5000
  secret: asecretforlocaldevelopment
  relativeurls: false
  draintimeout: 60s
  tls:
    certificate: /path/to/x509/public
    key: /path/to/x509/private
    clientcas:
      - /path/to/ca.pem
      - /path/to/another/ca.pem
    clientauth: require-and-verify-client-cert
    minimumtls: tls1.2
    ciphersuites:
      - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
      - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    letsencrypt:
      cachefile: /path/to/cache-file
      email: emailused@letsencrypt.com
      hosts: [myregistryaddress.org]
      directoryurl: https://acme-v02.api.letsencrypt.org/directory
  debug:
    addr: localhost:5001
  headers:
    X-Content-Type-Options: [nosniff]
  http2:
    disabled: false
  h2c:
    enabled: false
```

The `http` option details the configuration for the HTTP server that hosts the
registry.

| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `addr`    | no       | The address for which the server should accept connections. The form depends on a network type (see the `net` option). Use `HOST:PORT` for TCP and `FILE` for a UNIX socket. The `addr` field is only optional if socket-activation is used (in which case `addr` and `net` are ignored regardless of if they are specified). |
| `net`     | no       | The network used to create a listening socket. Known networks are `unix` and `tcp`. |
| `prefix`  | no       | If the server does not run at the root path, set this to the value of the prefix. The root path is the section before `v2`. It requires both preceding and trailing slashes, such as in the example `/path/`. |
| `host`    | no       | A fully-qualified URL for an externally-reachable address for the registry. If present, it is used when creating generated URLs. Otherwise, these URLs are derived from client requests. |
| `secret`  | no       | A random piece of data used to sign state that may be stored with the client to protect against tampering. For production environments you should generate a random piece of data using a cryptographically secure random generator. If you omit the secret, the registry will automatically generate a secret when it starts. **If you are building a cluster of registries behind a load balancer, you MUST ensure the secret is the same for all registries.**|
| `relativeurls`| no    | If `true`,  the registry returns relative URLs in Location headers. The client is responsible for resolving the correct URL. **This option is not compatible with Docker 1.7 and earlier.**|
| `draintimeout`| no    | Amount of time to wait for HTTP connections to drain before shutting down after registry receives SIGTERM signal|


### `tls`

The `tls` structure within `http` is **optional**. Use this to configure TLS
for the server. If you already have a web server running on
the same host as the registry, you may prefer to configure TLS on that web server
and proxy connections to the registry server.

| Parameter      | Required | Description                                                                                                                                                                                                                                                                                                                                                                                        |
|----------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `certificate`  | yes  | Absolute path to the x509 certificate file.                                                                                                                                                                                                                                                                                                                                                        |
| `key`          | yes  | Absolute path to the x509 private key file.                                                                                                                                                                                                                                                                                                                                                        |
| `clientcas`    | no   | An array of absolute paths to x509 CA files.                                                                                                                                                                                                                                                                                                                                                       |
| `clientauth`   | no   | Client certificate authentication mode. This setting determines how the server handles client certificates during the TLS handshake. If clientcas is not provided, TLS Client Authentication is disabled, and the mode is ignored. Allowed (request-client-cert, require-any-client-cert, verify-client-cert-if-given, require-and-verify-client-cert). Defaults to require-and-verify-client-cert |
| `minimumtls`   | no   | Minimum TLS version allowed (tls1.0, tls1.1, tls1.2, tls1.3). Defaults to tls1.2                                                                                                                                                                                                                                                                                                                   |
| `ciphersuites` | no   | Cipher suites allowed. Please see below for allowed values and default.                                                                                                                                                                                                                                                                                                                            |

Available cipher suites:
- TLS_RSA_WITH_RC4_128_SHA
- TLS_RSA_WITH_3DES_EDE_CBC_SHA
- TLS_RSA_WITH_AES_128_CBC_SHA
- TLS_RSA_WITH_AES_256_CBC_SHA
- TLS_RSA_WITH_AES_128_CBC_SHA256
- TLS_RSA_WITH_AES_128_GCM_SHA256
- TLS_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
- TLS_ECDHE_RSA_WITH_RC4_128_SHA
- TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256

Default cipher suites:
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_AES_128_GCM_SHA256
- TLS_CHACHA20_POLY1305_SHA256
- TLS_AES_256_GCM_SHA384

### `letsencrypt`

The `letsencrypt` structure within `tls` is **optional**. Use this to configure
TLS certificates provided by
[Let's Encrypt](https://letsencrypt.org/how-it-works/).

>**NOTE**: When using Let's Encrypt, ensure that the outward-facing address is
> accessible on port `443`. The registry defaults to listening on port `5000`.
> If you run the registry as a container, consider adding the flag `-p 443:5000`
> to the `docker run` command or using a similar setting in a cloud
> configuration. You should also set the `hosts` option to the list of hostnames
> that are valid for this registry to avoid trying to get certificates for random
> hostnames due to malicious clients connecting with bogus SNI hostnames. Please
> ensure that you have the `ca-certificates` package installed in order to verify
> letsencrypt certificates.

| Parameter      | Required | Description                                                           |
|----------------|----------|-----------------------------------------------------------------------|
| `cachefile`    | yes      | Absolute path to a file where the Let's Encrypt agent can cache data. |
| `email`        | yes      | The email address used to register with Let's Encrypt.                |
| `hosts`        | no       | The hostnames allowed for Let's Encrypt certificates.                 |
| `directoryurl` | no       | The url to use for the ACME server.                                   |

### `debug`

The `debug` option is **optional** . Use it to configure a debug server that
can be helpful in diagnosing problems. The debug endpoint can be used for
monitoring registry metrics and health, as well as profiling. Sensitive
information may be available via the debug endpoint. Please be certain that
access to the debug endpoint is locked down in a production environment.
The debug endpoint should not be exposed publicly to the internet.
Instead, keep the debug endpoint private or enforce authentication for it.

The `debug` section takes a single required `addr` parameter, which specifies
the `HOST:PORT` on which the debug server should accept connections.

If configured, `notification`, `redis`, and `proxy` statistics are exposed
at `/debug/vars` in JSON format.

#### `prometheus`

```yaml
prometheus:
  enabled: true
  path: /metrics
```

The `prometheus` option defines whether the prometheus metrics are enabled, as well
as the path to access the metrics.

The prometheus metrics cover `storage`, `notification` and `proxy` statistics.


| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `enabled` | no       | Set `true` to enable the prometheus server            |
| `path`    | no       | The path to access the metrics, `/metrics` by default |

The url to access the metrics is `HOST:PORT/path`, where `HOST:PORT` is defined
in `addr` under `debug`.

### `headers`

The `headers` option is **optional** . Use it to specify headers that the HTTP
server should include in responses. This can be used for security headers such
as `Strict-Transport-Security`.

The `headers` option should contain an option for each header to include, where
the parameter name is the header's name, and the parameter value a list of the
header's payload values.

Including `X-Content-Type-Options: [nosniff]` is recommended, so that browsers
will not interpret content as HTML if they are directed to load a page from the
registry. This header is included in the example configuration file.

### `http2`

The `http2` structure within `http` is **optional**. Use this to control HTTP/2 over TLS
settings for the registry.
If `tls` is not configured this option is ignored. To enable HTTP/2 over non TLS connections use `h2c` instead.

| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `disabled` | no      | If `true`, then `http2` support is disabled.          |

### `h2c`

The `h2c` structure within `http` is **optional**. Use this to control H2C (HTTP/2 Cleartext)
settings for the registry.
Useful when deploying the registry behind a load balancer (e.g. Google Cloud Run)

| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `enabled` | no      | If `true`, then `h2c` support is enabled.              |

## `notifications`

```yaml
notifications:
  events:
    includereferences: true
  endpoints:
    - name: alistener
      disabled: false
      url: https://my.listener.com/event
      headers: <http.Header>
      timeout: 1s
      threshold: 10
      backoff: 1s
      ignoredmediatypes:
        - application/octet-stream
      ignore:
        mediatypes:
           - application/octet-stream
        actions:
           - pull
```

The notifications option is **optional** and currently may contain a single
option, `endpoints`.

### `endpoints`

The `endpoints` structure contains a list of named services (URLs) that can
accept event notifications.

| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `name`    | yes      | A human-readable name for the service.                |
| `disabled` | no      | If `true`, notifications are disabled for the service.|
| `url`     | yes      | The URL to which events should be published.          |
| `headers` | yes      | A list of static headers to add to each request. Each header's name is a key beneath `headers`, and each value is a list of payloads for that header name. Values must always be lists. |
| `timeout` | yes      | A value for the HTTP timeout. A positive integer and an optional suffix indicating the unit of time, which may be `ns`, `us`, `ms`, `s`, `m`, or `h`. If you omit the unit of time, `ns` is used. |
| `threshold` | yes    | An integer specifying how long to wait before backing off a failure. |
| `backoff` | yes      | How long the system backs off before retrying after a failure. A positive integer and an optional suffix indicating the unit of time, which may be `ns`, `us`, `ms`, `s`, `m`, or `h`. If you omit the unit of time, `ns` is used. |
| `ignoredmediatypes`|no| A list of target media types to ignore. Events with these target media types are not published to the endpoint. |
| `ignore`  |no| Events with these mediatypes or actions are not published to the endpoint. |

#### `ignore`

| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `mediatypes`|no| A list of target media types to ignore. Events with these target media types are not published to the endpoint. |
| `actions`   |no| A list of actions to ignore. Events with these actions are not published to the endpoint. |

The `mediatypes` and `actions` filters work independently. You can specify:

- Only `mediatypes` to filter by media type.
- Only `actions` to filter by action (e.g., `pull`, `push`, `delete`, `mount`)
- Both to filter events matching either condition (OR logic)
- Neither to receive all events

Common use case: Set `mediatypes: []` with `actions: [pull, delete, mount]` to receive only push events regardless of media type.

### `events`

The `events` structure configures the information provided in event notifications.

| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `includereferences` | no | If `true`, include reference information in manifest events. |

## `redis`

Declare parameters for constructing the `redis` connections. Registry instances
may use the Redis instance for several applications. Currently, it caches
information about immutable blobs. Most of the `redis` options control
how the registry connects to the `redis` instance.

You **must** configure Redis with the **allkeys-lru** eviction policy, because
the registry does not set an expiration value on keys.

Under the hood distribution uses [`go-redis`](https://github.com/redis/go-redis) Go module for
Redis connectivity and its [`UniversalOptions`](https://pkg.go.dev/github.com/redis/go-redis/v9#UniversalOptions)
struct.

To use Redis Sentinel, set `mastername` to the name of the monitored Redis master
and `addrs` to the Sentinel endpoints. Setting `mastername` selects the
Sentinel-backed failover client; without it, multiple addresses select a Redis
Cluster client instead.

```yaml
redis:
  addrs:
    - sentinel1.example.com:26379
    - sentinel2.example.com:26379
    - sentinel3.example.com:26379
  mastername: mymaster
```

The equivalent environment variable for the master name is
`REGISTRY_REDIS_MASTERNAME`. If authentication is required, use `username` and
`password` for Redis, and `sentinelusername` and `sentinelpassword` for Sentinel.

You can optionally specify TLS configuration on top of the `UniversalOptions` settings.

Use these settings to configure Redis TLS:

| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `certificate`  | no   | Absolute path to the x509 client certificate file. Required for mTLS.  |
| `key`          | no   | Absolute path to the x509 client private key file. Required for mTLS.  |
| `rootcas`      | no   | An array of absolute paths to x509 CA files.          |

**Note:** For server-side TLS only (e.g., AWS Elasticache), provide only `rootcas`. For mutual TLS (mTLS), provide both `certificate` and `key` along with optional `rootcas`.

```yaml
# Server-side TLS only (validate server certificate)
redis:
  tls:
    rootcas:
      - /path/to/ca-bundle.crt
  addrs: [localhost:6379]

# Mutual TLS (client and server certificates)
redis:
  tls:
    certificate: /path/to/cert.crt
    key: /path/to/key.pem
    rootcas:
      - /path/to/ca.pem
  addrs: [localhost:6379]
  password: asecret
  db: 0
  dialtimeout: 10ms
  readtimeout: 10ms
  writetimeout: 10ms
  maxidleconns: 16
  poolsize: 64
  connmaxidletime: 300s
```

## `health`

```yaml
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3
  file:
    - file: /path/to/checked/file
      interval: 10s
  http:
    - uri: http://server.to.check/must/return/200
      headers:
        Authorization: [Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==]
      statuscode: 200
      timeout: 3s
      interval: 10s
      threshold: 3
  tcp:
    - addr: redis-server.domain.com:6379
      timeout: 3s
      interval: 10s
      threshold: 3
```

The health option is **optional**, and contains preferences for a periodic
health check on the storage driver's backend storage, as well as optional
periodic checks on local files, HTTP URIs, and/or TCP servers. The results of
the health checks are available at the `/debug/health` endpoint on the debug
HTTP server if the debug HTTP server is enabled (see http section).

### `storagedriver`

The `storagedriver` structure contains options for a health check on the
configured storage driver's backend storage. The health check is only active
when `enabled` is set to `true`.

| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `enabled` | yes      | Set to `true` to enable storage driver health checks or `false` to disable them. |
| `interval`| no       | How long to wait between repetitions of the storage driver health check. A positive integer and an optional suffix indicating the unit of time. The suffix is one of `ns`, `us`, `ms`, `s`, `m`, or `h`. Defaults to `10s` if the value is omitted. If you specify a value but omit the suffix, the value is interpreted as a number of nanoseconds. |
| `threshold`| no      | A positive integer which represents the number of times the check must fail before the state is marked as unhealthy. If not specified, a single failure marks the state as unhealthy. |

### `file`

The `file` structure includes a list of paths to be periodically checked for the\
existence of a file. If a file exists at the given path, the health check will
fail. You can use this mechanism to bring a registry out of rotation by creating
a file.

| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `file`    | yes      | The path to check for existence of a file.            |
| `interval`| no       | How long to wait before repeating the check. A positive integer and an optional suffix indicating the unit of time. The suffix is one of `ns`, `us`, `ms`, `s`, `m`, or `h`. Defaults to `10s` if the value is omitted. If you specify a value but omit the suffix, the value is interpreted as a number of nanoseconds. |

### `http`

The `http` structure includes a list of HTTP URIs to periodically check with
`HEAD` requests. If a `HEAD` request does not complete or returns an unexpected
status code, the health check will fail.

| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `uri`     | yes      | The URI to check.                                     |
| `headers` | no       | Static headers to add to each request. Each header's name is a key beneath `headers`, and each value is a list of payloads for that header name. Values must always be lists. |
| `statuscode` | no    | The expected status code from the HTTP URI. Defaults to `200`. |
| `timeout` | no       | How long to wait before timing out the HTTP request. A positive integer and an optional suffix indicating the unit of time. The suffix is one of `ns`, `us`, `ms`, `s`, `m`, or `h`. If you specify a value but omit the suffix, the value is interpreted as a number of nanoseconds. |
| `interval`| no       | How long to wait before repeating the check. A positive integer and an optional suffix indicating the unit of time. The suffix is one of `ns`, `us`, `ms`, `s`, `m`, or `h`. Defaults to `10s` if the value is omitted. If you specify a value but omit the suffix, the value is interpreted as a number of nanoseconds. |
| `threshold`| no      | The number of times the check must fail before the state is marked as unhealthy. If this field is not specified, a single failure marks the state as unhealthy. |

### `tcp`

The `tcp` structure includes a list of TCP addresses to periodically check using
TCP connection attempts. Addresses must include port numbers. If a connection
attempt fails, the health check will fail.

| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `addr`    | yes      | The TCP address and port to connect to.               |
| `timeout` | no       | How long to wait before timing out the TCP connection. A positive integer and an optional suffix indicating the unit of time. The suffix is one of `ns`, `us`, `ms`, `s`, `m`, or `h`. If you specify a value but omit the suffix, the value is interpreted as a number of nanoseconds. |
| `interval`| no       | How long to wait between repetitions of the check. A positive integer and an optional suffix indicating the unit of time. The suffix is one of `ns`, `us`, `ms`, `s`, `m`, or `h`. Defaults to `10s` if the value is omitted. If you specify a value but omit the suffix, the value is interpreted as a number of nanoseconds. |
| `threshold`| no      | The number of times the check must fail before the state is marked as unhealthy. If this field is not specified, a single failure marks the state as unhealthy. |


## `proxy`

```yaml
proxy:
  remoteurl: https://registry-1.docker.io
  username: [username]
  password: [password]
  ttl: 168h
```

The `proxy` structure allows a registry to be configured as a pull-through cache
to an upstream registry such as Docker Hub. See
[mirror](../recipes/mirror.md)
for more information. Pushing to a registry configured as a pull-through cache
is unsupported.

| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `remoteurl`| yes     | The URL for the repository on Docker Hub.             |
| `ttl`      | no      | Expire proxy cache configured in "storage" after this time. Cache 168h(7 days) by default, set to 0 to disable cache expiration, The suffix is one of `ns`, `us`, `ms`, `s`, `m`, or `h`. If you specify a value but omit the suffix, the value is interpreted as a number of nanoseconds. |

To enable pulling private repositories (e.g. `batman/robin`), specify one of the
following authentication methods for the pull-through cache to authenticate with
the upstream registry via the [v2 Distribution registry authentication
scheme](https://distribution.github.io/distribution/spec/auth/token/).]

### `username` and `password`

The username and password used to authenticate with the upstream registry to
access the private repositories.

### `exec`

Run a custom exec-based [Docker credential helper](https://github.com/docker/docker-credential-helpers)
to retrieve the credentials to authenticate with the upstream registry.

| Parameter | Required | Description                                           |
|-----------|----------|-------------------------------------------------------|
| `command` | yes      | The command to execute.                               |
| `lifetime`| no       | The expiry period of the credentials. The credentials returned by the command is reused through the configured lifetime, then the command will be re-executed to retrieve new credentials. If set to zero, the command will be executed for every request. If not set, the command will only be executed once. |


> **Note**: These private repositories are stored in the proxy cache's storage.
> Take appropriate measures to protect access to the proxy cache.

## `validation`

```yaml
validation:
  disabled: false
```

Use these settings to configure what validation the registry performs on content.

Validation is performed when content is uploaded to the registry. Changing these
settings will not validate content that has already been accepting into the registry.

### `disabled`

The `disabled` flag disables the other options in the `validation`
section. They are enabled by default. This option deprecates the `enabled` flag.

### `manifests`

Use the `manifests` subsection to configure validation of manifests. If
`disabled` is `false`, the validation allows nothing.

#### `urls`

```yaml
validation:
  manifests:
    urls:
      allow:
        - ^https?://([^/]+\.)*example\.com/
      deny:
        - ^https?://www\.example\.com/
```

The `allow` and `deny` options are each a list of
[regular expressions](https://pkg.go.dev/regexp/syntax) that restrict the URLs in
pushed manifests.

If `allow` is unset, pushing a manifest containing URLs fails.

If `allow` is set, pushing a manifest succeeds only if all URLs match
one of the `allow` regular expressions **and** one of the following holds:

1. `deny` is unset.
2. `deny` is set but no URLs within the manifest match any of the `deny` regular
   expressions.

#### `indexes`

By default the registry will validate that all platform images exist when an image
index is uploaded to the registry. Disabling this validatation is experimental
because other tooling that uses the registry may expect the image index to be complete.

```yaml
validation:
  manifests:
    indexes:
      platforms: [all|none|list]
      platformlist:
      - os: linux
        architecture: amd64
```

Use these settings to configure what validation the registry performs on image
index manifests uploaded to the registry.

##### `platforms`

Set `platforms` to `all` (the default) to validate all platform images exist.
The registry will validate that the images referenced by the index exist in the
registry before accepting the image index.

Set `platforms` to `none` to disable all validation that images exist when an
image index manifest is uploaded. This allows image lists to be uploaded to the
registry without their associated images. This setting is experimental because
other tooling that uses the registry may expect the image index to be complete.

Set `platforms` to `list` to selectively validate the existence of platforms
within image index manifests. This setting is experimental because other tooling
that uses the registry may expect the image index to be complete.

##### `platformlist`

When `platforms` is set to `list`, set `platformlist` to an array of
platforms to validate. If a platform is included in this the array and in the images
contained within an index, the registry will validate that the platform specific image
exists in the registry before accepting the index. The registry will not validate the
existence of platform specific images in the index that do not appear in the
`platformlist` array.

This parameter does not validate that the configured platforms are included in every
index. If an image index does not include one of the platform specific images configured
in the `platformlist` array, it may still be accepted by the registry.

Each platform is a map with two keys, `os` and `architecture`, as defined in the
[OCI Image Index specification](https://github.com/opencontainers/image-spec/blob/main/image-index.md#image-index-property-descriptions).

## Example: Development configuration

You can use this simple example for local development:

```yaml
version: 0.1
log:
  level: debug
storage:
    filesystem:
        rootdirectory: /var/lib/registry
http:
    addr: localhost:5000
    secret: asecretforlocaldevelopment
    debug:
        addr: localhost:5001
```

This example configures the registry instance to run on port `5000`, binding to
`localhost`, with the `debug` server enabled. Registry data is stored in the
`/var/lib/registry` directory. Logging is set to `debug` mode, which is the most
verbose.

See
[config-example.yml](https://github.com/distribution/distribution/blob/master/cmd/registry/config-example.yml)
for another simple configuration. Both examples are generally useful for local
development.

## Example: Middleware configuration

This example configures [Amazon Cloudfront](https://aws.amazon.com/cloudfront/)
as the storage middleware in a registry. Middleware allows the registry to serve
layers via a content delivery network (CDN). This reduces requests to the
storage layer.

Cloudfront requires the S3 storage driver.

This is the configuration expressed in YAML:

```yaml
middleware:
  storage:
  - name: cloudfront
    disabled: false
    options:
      baseurl: http://d111111abcdef8.cloudfront.net
      privatekey: /path/to/asecret.pem
      keypairid: asecret
      duration: 60s
```

See the configuration reference for [Cloudfront](#cloudfront) for more
information about configuration options.

{{< hint type=note >}}
Cloudfront keys exist separately from other AWS keys. See
[the documentation on AWS credentials](https://docs.aws.amazon.com/general/latest/gr/aws-security-credentials.html)
for more information.
{{< /hint >}}

---

### Content About Deploying (`docs/content/about/deploying.md`)

---
description: Explains how to deploy a registry
keywords: registry, on-prem, images, tags, repository, distribution, deployment
title: Deploy a registry server
---

Before you can deploy a registry, you need to install Docker on the host.
A registry is an instance of the `registry` image, and runs within Docker.

This topic provides basic information about deploying and configuring a
registry. For an exhaustive list of configuration options, see the
[configuration reference](configuration.md).

If you have an air-gapped datacenter, see
[Considerations for air-gapped registries](#considerations-for-air-gapped-registries).

## Run a local registry

Use a command like the following to start the registry container:

```console
$ docker run -d -p 5000:5000 --restart=always --name registry registry:3
```

The registry is now ready to use.

> **Warning**: These first few examples show registry configurations that are
> only appropriate for testing. A production-ready registry must be protected by
> TLS and should ideally use an access-control mechanism. Keep reading and then
> continue to the [configuration guide](configuration.md) to deploy a
> production-ready registry.

> **Note**: The [default configuration](https://github.com/distribution/distribution/blob/main/cmd/registry/config-dev.yml)
> is designed for development. As such, the log level is set to `debug`. In
> addition, the registry uses [OpenTelemetry](https://opentelemetry.io/docs/what-is-opentelemetry/)
> for logs and trace. OpenTelemetry integration is configured using [standard
> environment variables](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/),
> and will by default attempt to export telemetry traces to an OTLP collector at
> `localhost:4318`. If this is not desired, telemetry can be disabled by adding
> `-e OTEL_TRACES_EXPORTER=none` to the `docker run` command above.

## Copy an image from Docker Hub to your registry

You can pull an image from Docker Hub and push it to your registry. The
following example pulls the `ubuntu:16.04` image from Docker Hub and re-tags it
as `my-ubuntu`, then pushes it to the local registry. Finally, the
`ubuntu:16.04` and `my-ubuntu` images are deleted locally and the
`my-ubuntu` image is pulled from the local registry.

1. Pull the `ubuntu:16.04` image from Docker Hub.

   ```console
   $ docker pull ubuntu:16.04
   ```

2. Tag the image as `localhost:5000/my-ubuntu`. This creates an additional tag
   for the existing image. When the first part of the tag is a hostname and
   port, Docker interprets this as the location of a registry, when pushing.

   ```console
   $ docker tag ubuntu:16.04 localhost:5000/my-ubuntu
   ```

3. Push the image to the local registry running at `localhost:5000`:

   ```console
   $ docker push localhost:5000/my-ubuntu
   ```

4. Remove the locally-cached `ubuntu:16.04` and `localhost:5000/my-ubuntu`
   images, so that you can test pulling the image from your registry. This
   does not remove the `localhost:5000/my-ubuntu` image from your registry.

   ```console
   $ docker image remove ubuntu:16.04
   $ docker image remove localhost:5000/my-ubuntu
   ```

5. Pull the `localhost:5000/my-ubuntu` image from your local registry.

   ```console
   $ docker pull localhost:5000/my-ubuntu
   ```

## Stop a local registry

To stop the registry, use the same `docker container stop` command as with any other
container.

```console
$ docker container stop registry
```

To remove the container, use `docker container rm`.

```console
$ docker container stop registry && docker container rm -v registry
```

## Basic configuration

To configure the container, you can pass additional or modified options to the
`docker run` command.

The following sections provide basic guidelines for configuring your registry.
For more details, see the [registry configuration reference](configuration.md).

### Start the registry automatically

If you want to use the registry as part of your permanent infrastructure, you
should set it to restart automatically when Docker restarts or if it exits.
This example uses the `--restart always` flag to set a restart policy for the
registry.

```console
$ docker run -d \
  -p 5000:5000 \
  --restart=always \
  --name registry \
  registry:3
```

### Customize the published port

If you are already using port 5000, or you want to run multiple local
registries to separate areas of concern, you can customize the registry's
port settings. This example runs the registry on port 5001 and also names it
`registry-test`. Remember, the first part of the `-p` value is the host port
and the second part is the port within the container. Within the container, the
registry listens on port `5000` by default.

```console
$ docker run -d \
  -p 5001:5000 \
  --name registry-test \
  registry:3
```

If you want to change the port the registry listens on within the container, you
can use the environment variable `REGISTRY_HTTP_ADDR` to change it. This command
causes the registry to listen on port 5001 within the container:

```console
$ docker run -d \
  -e REGISTRY_HTTP_ADDR=0.0.0.0:5001 \
  -p 5001:5001 \
  --name registry-test \
  registry:3
```


## Storage customization

### Customize the storage location

By default, your registry data is persisted as a [docker volume](https://docs.docker.com/storage/volumes)
on the host filesystem. If you want to store your registry contents at a specific
location on your host filesystem, such as if you have an SSD or SAN mounted into
a particular directory, you might decide to use a bind mount instead. A bind mount
is more dependent on the filesystem layout of the Docker host, but more performant
in many situations. The following example bind-mounts the host directory
`/mnt/registry` into the registry container at `/var/lib/registry/`.

```console
$ docker run -d \
  -p 5000:5000 \
  --restart=always \
  --name registry \
  -v /mnt/registry:/var/lib/registry \
  registry:3
```

### Customize the storage back-end

By default, the registry stores its data on the local filesystem, whether you
use a bind mount or a volume. You can store the registry data in an Amazon S3
bucket, Google Cloud Platform, or on another storage back-end by using
[storage drivers](../storage-drivers/_index.md). For more information, see
[storage configuration options](configuration.md#storage).

## Run an externally-accessible registry

Running a registry only accessible on `localhost` has limited usefulness. In
order to make your registry accessible to external hosts, you must first secure
it using TLS.

This example is extended in [Run the registry as a
service](#run-the-registry-as-a-service) below.

### Get a certificate

These examples assume the following:

- Your registry URL is `https://myregistry.domain.com/`.
- Your DNS, routing, and firewall settings allow access to the registry's host
  on port 443.
- You have already obtained a certificate from a certificate authority (CA).

If you have been issued an _intermediate_ certificate instead, see
[use an intermediate certificate](#use-an-intermediate-certificate).

1. Create a `certs` directory.

   ```console
   $ mkdir -p certs
   ```

   Copy the `.crt` and `.key` files from the CA into the `certs` directory.
   The following steps assume that the files are named `domain.crt` and
   `domain.key`.

2. Stop the registry if it is currently running.

   ```console
   $ docker container stop registry
   ```

3. Restart the registry, directing it to use the TLS certificate. This command
   bind-mounts the `certs/` directory into the container at `/certs/`, and sets
   environment variables that tell the container where to find the `domain.crt`
   and `domain.key` file. The registry runs on port 443, the default HTTPS port.

   ```console
   $ docker run -d \
     --restart=always \
     --name registry \
     -v "$(pwd)"/certs:/certs \
     -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
     -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
     -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
     -p 443:443 \
     registry:3
   ```

4. Docker clients can now pull from and push to your registry using its
   external address. The following commands demonstrate this:

   ```console
   $ docker pull ubuntu:16.04
   $ docker tag ubuntu:16.04 myregistry.domain.com/my-ubuntu
   $ docker push myregistry.domain.com/my-ubuntu
   $ docker pull myregistry.domain.com/my-ubuntu
   ```

#### Use an intermediate certificate

A certificate issuer may supply you with an *intermediate* certificate. In this
case, you must concatenate your certificate with the intermediate certificate to
form a *certificate bundle*. You can do this using the `cat` command:

```console
cat domain.crt intermediate-certificates.pem > certs/domain.crt
```

You can use the certificate bundle just as you use the `domain.crt` file in
the previous example.

### Support for Let's Encrypt

The registry supports using Let's Encrypt to automatically obtain a
browser-trusted certificate. For more information on Let's Encrypt, see
[https://letsencrypt.org/how-it-works/](https://letsencrypt.org/how-it-works/)
and the relevant section of the
[registry configuration](configuration.md#letsencrypt).

### Use an insecure registry (testing only)

It is possible to use a self-signed certificate, or to use our registry
insecurely. Unless you have set up verification for your self-signed
certificate, this is for testing only. See [run an insecure registry](insecure.md).

## Run the registry as a service

[Swarm services](https://docs.docker.com/engine/swarm/services) provide several advantages over
standalone containers. They use a declarative model, which means that you define
the desired state and Docker works to keep your service in that state. Services
provide automatic load balancing scaling, and the ability to control the
distribution of your service, among other advantages. Services also allow you to
store sensitive data such as TLS certificates in
[secrets](https://docs.docker.com/engine/swarm/secrets).

The storage back-end you use determines whether you use a fully scaled service
or a service with either only a single node or a node constraint.

- If you use a distributed storage driver, such as Amazon S3, you can use a
  fully replicated service. Each worker can write to the storage back-end
  without causing write conflicts.

- If you use a local bind mount or volume, each worker node writes to its
  own storage location, which means that each registry contains a different
  data set. You can solve this problem by using a single-replica service and a
  node constraint to ensure that only a single worker is writing to the bind
  mount.

The following example starts a registry as a single-replica service, which is
accessible on any swarm node on port 80. It assumes you are using the same
TLS certificates as in the previous examples.

First, save the TLS certificate and key as secrets:

```console
$ docker secret create domain.crt certs/domain.crt

$ docker secret create domain.key certs/domain.key
```

Next, add a label to the node where you want to run the registry.
To get the node's name, use `docker node ls`. Substitute your node's name for
`node1` below.

```console
$ docker node update --label-add registry=true node1
```

Next, create the service, granting it access to the two secrets and constraining
it to only run on nodes with the label `registry=true`. Besides the constraint,
you are also specifying that only a single replica should run at a time. The
example bind-mounts `/mnt/registry` on the swarm node to `/var/lib/registry/`
within the container. Bind mounts rely on the pre-existing source directory,
so be sure `/mnt/registry` exists on `node1`. You might need to create it before
running the following `docker service create` command.

By default, secrets are mounted into a service at `/run/secrets/<secret-name>`.

```console
$ docker service create \
  --name registry \
  --secret domain.crt \
  --secret domain.key \
  --constraint 'node.labels.registry==true' \
  --mount type=bind,src=/mnt/registry,dst=/var/lib/registry \
  -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/run/secrets/domain.crt \
  -e REGISTRY_HTTP_TLS_KEY=/run/secrets/domain.key \
  --publish published=443,target=443 \
  --replicas 1 \
  registry:3
```

You can access the service on port 443 of any swarm node. Docker sends the
requests to the node which is running the service.

## Load balancing considerations

One may want to use a load balancer to distribute load, terminate TLS or
provide high availability. While a full load balancing setup is outside the
scope of this document, there are a few considerations that can make the process
smoother.

The most important aspect is that a load balanced cluster of registries must
share the same resources. For the current version of the registry, this means
the following must be the same:

- Storage Driver
- HTTP Secret
- Redis Cache (if configured)

Differences in any of the above cause problems serving requests.
As an example, if you're using the filesystem driver, all registry instances
must have access to the same filesystem root, on
the same machine. For other drivers, such as S3 or Azure, they should be
accessing the same resource and share an identical configuration.
The _HTTP Secret_ coordinates uploads, so also must be the same across
instances. Configuring different redis instances works (at the time
of writing), but is not optimal if the instances are not shared, because
more requests are directed to the backend.

### Important/Required HTTP-Headers

Getting the headers correct is very important. For all responses to any
request under the "/v2/" url space, the `Docker-Distribution-API-Version`
header should be set to the value "registry/2.0", even for a 4xx response.
This header allows the docker engine to quickly resolve authentication realms
and fallback to version 1 registries, if necessary. Confirming this is setup
correctly can help avoid problems with fallback.

In the same train of thought, you must make sure you are properly sending the
`X-Forwarded-Proto`, `X-Forwarded-For`, and `Host` headers to their "client-side"
values. Failure to do so usually makes the registry issue redirects to internal
hostnames or downgrading from https to http.

A properly secured registry should return 401 when the "/v2/" endpoint is hit
without credentials. The response should include a `WWW-Authenticate`
challenge, providing guidance on how to authenticate, such as with basic auth
or a token service. If the load balancer has health checks, it is recommended
to configure it to consider a 401 response as healthy and any other as down.
This secures your registry by ensuring that configuration problems with
authentication don't accidentally expose an unprotected registry. If you're
using a less sophisticated load balancer that doesn't allow one to change
the healthy response code, health checks can be directed at "/", which always
returns a `200 OK` response.

## Restricting access

Except for registries running on secure local networks, registries should always
implement access restrictions.

### Native basic auth

The simplest way to achieve access restriction is through basic authentication
(this is very similar to other web servers' basic authentication mechanism).
This example uses native basic authentication using `htpasswd` to store the
secrets.

{{< hint type=warning >}}
You **cannot** use authentication with authentication schemes that send
credentials as clear text. You must
[configure TLS first](#run-an-externally-accessible-registry) for
authentication to work.
{{< /hint >}}

{{< hint type=warning >}}
The distribution registry **only** supports htpasswd credentials in
bcrypt format, so if you omit the `-B` option when generating the credential
using htpasswd, all authentication attempts will fail.
{{< /hint >}}

1. Create a password file with one entry for the user `testuser`, with password
   `testpassword`:

   ```console
   $ mkdir auth
   $ docker run \
     --entrypoint htpasswd \
     httpd:2 -Bbn testuser testpassword > auth/htpasswd
   ```

   On Windows, make sure the output file is correctly encoded:

   ```powershell
   docker run --rm --entrypoint htpasswd httpd:2 -Bbn testuser testpassword | Set-Content -Encoding ASCII auth/htpasswd
   ```

2. Stop the registry.

   ```console
   $ docker container stop registry
   ```

3. Start the registry with basic authentication.

   ```console
   $ docker run -d \
     -p 5000:5000 \
     --restart=always \
     --name registry \
     -v "$(pwd)"/auth:/auth \
     -e "REGISTRY_AUTH=htpasswd" \
     -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
     -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
     -v "$(pwd)"/certs:/certs \
     -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
     -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
     registry:3
     ```

4. Try to pull an image from the registry, or push an image to the registry.
   These commands fail.

5. Log in to the registry.

   ```console
   $ docker login myregistrydomain.com:5000
   ```

   Provide the username and password from the first step.

   Test that you can now pull an image from the registry or push an image to
   the registry.

{{< hint type=note title="X509 errors" >}}
X509 errors usually indicate that you are attempting to use
a self-signed certificate without configuring the Docker daemon correctly.
See [run an insecure registry](insecure.md).
{{< /hint >}}

### More advanced authentication

You may want to leverage more advanced basic auth implementations by using a
proxy in front of the registry. See the [recipes list](../recipes/_index.md).

The registry also supports delegated authentication which redirects users to a
specific trusted token server. This approach is more complicated to set up, and
only makes sense if you need to fully configure ACLs and need more control over
the registry's integration into your global authorization and authentication
systems. Refer to the following [background information](../spec/auth/token.md) and
[configuration information here](configuration.md#auth).

This approach requires you to implement your own authentication system or
leverage a third-party implementation.

## Deploy your registry using a Compose file

If your registry invocation is advanced, it may be easier to use a Docker
compose file to deploy it, rather than relying on a specific `docker run`
invocation. Use the following example `docker-compose.yml` as a template.

```yaml
services:
  registry:
    restart: always
    image: registry:3
    ports:
      - 5000:5000
    environment:
      REGISTRY_HTTP_TLS_CERTIFICATE: /certs/domain.crt
      REGISTRY_HTTP_TLS_KEY: /certs/domain.key
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
    volumes:
      - /path/data:/var/lib/registry
      - /path/certs:/certs
      - /path/auth:/auth
```

{{< hint type=warning >}}
Replace `/path` with the directory which contains the `certs/` and `auth/`
directories.
{{< /hint >}}

Start your registry by issuing the following command in the directory containing
the `docker-compose.yml` file:

```console
$ docker compose up -d
```

## Considerations for air-gapped registries

You can run a registry in an environment with no internet connectivity.
However, if you rely on any images which are not local, you need to consider the
following:

- You may need to build your local registry's data volume on a connected
  host where you can run `docker pull` to get any images which are available
  remotely, and then migrate the registry's data volume to the air-gapped
  network.

- Certain images, such as the official Microsoft Windows base images, are not
  distributable. This means that when you push an image based on one of these
  images to your private registry, the non-distributable layers are **not**
  pushed, but are always fetched from their authorized location. This is fine
  for internet-connected hosts, but not in an air-gapped set-up.

  You can configure the Docker daemon to allow pushing non-distributable layers 
  to private registries.
  **This is only useful in air-gapped set-ups in the presence of
  non-distributable images, or in extremely bandwidth-limited situations.**
  You are responsible for ensuring that you are in compliance with the terms of
  use for non-distributable layers.

  1. Edit the `daemon.json` file, which is located in `/etc/docker/` on Linux
     hosts and `C:\ProgramData\docker\config\daemon.json` on Windows Server.
     Assuming the file was previously empty, add the following contents:

     ```json
     {
       "allow-nondistributable-artifacts": ["myregistrydomain.com:5000"]
     }
     ```

     The value is an array of registry addresses, separated by commas.

     Save and exit the file.

  2. Restart Docker.

  3. Restart the registry if it does not start automatically.

  4. When you push images to the registries in the list, their
     non-distributable layers are pushed to the registry.

{{< hint type=warning >}}
Non-distributable artifacts typically have restrictions on
how and where they can be distributed and shared. Only use this feature
to push artifacts to private registries and ensure that you are in
compliance with any terms that cover redistributing non-distributable
artifacts.
{{< /hint >}}

## Next steps

More specific and advanced information is available in the following sections:

- [Configuration reference](configuration.md)
- [Working with notifications](notifications.md)
- [Advanced "recipes"](../recipes/_index.md)
- [Registry API](../spec/api.md)
- [Storage driver model](../storage-drivers/_index.md)
- [Token authentication](../spec/auth/token.md)

---

### Content About Garbage Collection (`docs/content/about/garbage-collection.md`)

---
description: High level discussion of garbage collection
keywords: registry, garbage, images, tags, repository, distribution
title: Garbage collection
---

As of v2.4.0 a garbage collector command is included within the registry binary.
This document describes what this command does and how and why it should be used.

## About garbage collection

In the context of the registry, garbage collection is the process of
removing blobs from the filesystem when they are no longer referenced by a
manifest. Blobs can include both layers and manifests.

Registry data can occupy considerable amounts of disk space. In addition,
garbage collection can be a security consideration, when it is desirable to ensure
that certain layers no longer exist on the filesystem.

## Garbage collection in practice

Filesystem layers are stored by their content address in the Registry. This
has many advantages, one of which is that data is stored once and referred to by manifests.
See [here](compatibility.md#content-addressable-storage-cas) for more details.

Layers are therefore shared amongst manifests; each manifest maintains a reference
to the layer. As long as a layer is referenced by one manifest, it cannot be garbage
collected.

Manifests and layers can be `deleted` with the registry API (refer to the API
documentation [here](../spec/api.md#deleting-a-layer) and
[here](../spec/api.md#deleting-an-image) for details). This API removes references
to the target and makes them eligible for garbage collection. It also makes them
unable to be read via the API.

If a layer is deleted, it is removed from the filesystem when garbage collection
is run. If a manifest is deleted the layers to which it refers are removed from
the filesystem if no other manifests refers to them.


### Example

In this example manifest A references two layers: `a` and `b`. Manifest `B` references
layers `a` and `c`. In this state, nothing is eligible for garbage collection:

```
A -----> a <----- B
    \--> b     |
         c <--/
```

Manifest B is deleted via the API:

```
A -----> a     B
    \--> b
         c
```

In this state layer `c` no longer has a reference and is eligible for garbage
collection. Layer `a` had one reference removed but not garbage
collected as it is still referenced by manifest `A`. The blob representing
manifest `B` is eligible for garbage collection.

After garbage collection has been run, manifest `A` and its blobs remain.

```
A -----> a
    \--> b
```


### More details about garbage collection

Garbage collection runs in two phases. First, in the 'mark' phase, the process
scans all the manifests in the registry. From these manifests, it constructs a
set of content address digests. This set is the 'mark set' and denotes the set
of blobs to *not* delete. Secondly, in the 'sweep' phase, the process scans all
the blobs and if a blob's content address digest is not in the mark set, the
process deletes it.


> **Note**: You should ensure that the registry is in read-only mode or not running at
> all. If you were to upload an image while garbage collection is running, there is the
> risk that the image's layers are mistakenly deleted leading to a corrupted image.

This type of garbage collection is known as stop-the-world garbage collection.

## Run garbage collection

Garbage collection can be run as follows

`bin/registry garbage-collect [--dry-run] [--delete-untagged] [--quiet] /path/to/config.yml`

The garbage-collect command accepts a `--dry-run` parameter, which prints the progress
of the mark and sweep phases without removing any data. Running with a log level of `info`
gives a clear indication of items eligible for deletion.

The config.yml file should be in the following format:

```yaml
version: 0.1
storage:
  filesystem:
    rootdirectory: /registry/data
```

_Sample output from a dry run garbage collection with registry log level set to `info`_

```
hello-world
hello-world: marking manifest sha256:fea8895f450959fa676bcc1df0611ea93823a735a01205fd8622846041d0c7cf
hello-world: marking blob sha256:03f4658f8b782e12230c1783426bd3bacce651ce582a4ffb6fbbfa2079428ecb
hello-world: marking blob sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
hello-world: marking configuration sha256:690ed74de00f99a7d00a98a5ad855ac4febd66412be132438f9b8dbd300a937d
ubuntu

4 blobs marked, 5 blobs eligible for deletion
blob eligible for deletion: sha256:28e09fddaacbfc8a13f82871d9d66141a6ed9ca526cb9ed295ef545ab4559b81
blob eligible for deletion: sha256:7e15ce58ccb2181a8fced7709e9893206f0937cc9543bc0c8178ea1cf4d7e7b5
blob eligible for deletion: sha256:87192bdbe00f8f2a62527f36bb4c7c7f4eaf9307e4b87e8334fb6abec1765bcb
blob eligible for deletion: sha256:b549a9959a664038fc35c155a95742cf12297672ca0ae35735ec027d55bf4e97
blob eligible for deletion: sha256:f251d679a7c61455f06d793e43c06786d7766c88b8c24edf242b2c08e3c3f599
```

The `--delete-untagged` option can be used to delete manifests that are not currently referenced by a tag.

The `--quiet` option suppresses any output from being printed.

---

### Content About Glossary (`docs/content/about/glossary.md`)

---
draft: true
---

# Glossary

This page contains definitions for distribution related terms.

<dl>
	<dt id="blob"><h4>Blob</h4></dt>
	<dd>
      <blockquote>A blob is any kind of content that is stored by a Registry under a content-addressable identifier (a "digest").</blockquote>
      <p>
      	<a href="#layer">Layers</a> are a good example of "blobs".
      </p>
	</dd>

	<dt id="image"><h4>Image</h4></dt>
	<dd>
      <blockquote>An image is a named set of immutable data from which a container can be created.</blockquote>
      <p>
      An image is represented by a json file called a <a href="#manifest">manifest</a>, and is conceptually a set of <a href="#layer">layers</a>.

      Image names indicate the location where they can be pulled from and pushed to, as they usually start with a <a href="#registry">registry</a> domain name and port.

      </p>
    </dd>

	<dt id="layer"><h4>Layer</h4></dt>
	<dd>
	<blockquote>A layer is a tar archive bundling partial content from a filesystem.</blockquote>
	<p>
	Layers from an <a href="#image">image</a> are usually extracted in order on top of each other to make up a root filesystem from which containers run out.
	</p>
	</dd>

	<dt id="manifest"><h4>Manifest</h4></dt>
	<dd><blockquote>A manifest is the JSON representation of an image.</blockquote></dd>

	<dt id="namespace"><h4>Namespace</h4></dt>
	<dd><blockquote>A namespace is a collection of repositories with a common name prefix.</blockquote>
	<p>
	The namespace with an empty prefix is considered the Global Namespace.
	</p>
	</dd>

	<dt id="registry"><h4>Registry</h4></dt>
	<dd><blockquote>A registry is a service that let you store and deliver <a href="#images">images</a> and other content.</blockquote>
	</dd>

	<dt id="registry"><h4>Repository</h4></dt>
	<dd>
	<blockquote>A repository is a set of data containing all versions of a given image.</blockquote>
	</dd>

	<dt id="scope"><h4>Scope</h4></dt>
	<dd><blockquote>A scope is the portion of a namespace onto which a given authorization token is granted.</blockquote></dd>

	<dt id="tag"><h4>Tag</h4></dt>
	<dd><blockquote>A tag is conceptually a "version" of a <a href="#image">named image</a>.</blockquote>
	<p>
	Example: `docker pull myimage:latest` instructs docker to pull the image "myimage" in version "latest".
	</p>

	</dd>


</dl>

---

### Content About Help (`docs/content/about/help.md`)

---
description: Getting help with the Registry
keywords: registry, on-prem, images, tags, repository, distribution, help, 101, TL;DR
title: Get help
---

If you need help, or just want to chat about development, you can reach us on the #distribution channel in the CNCF Slack.

If you want to report a bug:

- be sure to first read about [how to contribute](https://github.com/distribution/distribution/blob/master/CONTRIBUTING.md).
- you can then do so on the [GitHub project bugtracker](https://github.com/distribution/distribution/issues).

---

### Content About Insecure (`docs/content/about/insecure.md`)

---
description: Deploying a Registry in an insecure fashion
keywords: registry, on-prem, images, tags, repository, distribution, insecure
title: Test an insecure registry
---

While it's highly recommended to secure your registry using a TLS certificate
issued by a known CA, you can choose to use self-signed certificates, or use
your registry over an unencrypted HTTP connection. Either of these choices
involves security trade-offs and additional configuration steps.

## Deploy a plain HTTP registry

{{< hint type=warning >}}
It's not possible to use an insecure registry with basic authentication.
{{< /hint >}}

This procedure configures Docker to entirely disregard security for your
registry. This is **very** insecure and is not recommended. It exposes your
registry to trivial man-in-the-middle (MITM) attacks. Only use this solution for
isolated testing or in a tightly controlled, air-gapped environment.

1. Edit the `daemon.json` file, whose default location is
   `/etc/docker/daemon.json` on Linux or
   `C:\ProgramData\docker\config\daemon.json` on Windows Server. If you use
   Docker Desktop for Mac or Docker Desktop for Windows, click the Docker icon, choose
   **Preferences** (Mac) or **Settings** (Windows), and choose **Docker Engine**.

   If the `daemon.json` file does not exist, create it. Assuming there are no
   other settings in the file, it should have the following contents:

   ```json
   {
     "insecure-registries" : ["myregistrydomain.com:5000"]
   }
   ```

   Substitute the address of your insecure registry for the one in the example.

   With insecure registries enabled, Docker goes through the following steps:

   - First, try using HTTPS.

     - If HTTPS is available but the certificate is invalid, ignore the error
       about the certificate.

     - If HTTPS is not available, fall back to HTTP.


2. Restart Docker for the changes to take effect.

Repeat these steps on every Engine host that wants to access your registry.

## Use self-signed certificates

{{< hint type=warning >}}
Using this along with basic authentication requires to **also** trust the certificate into the OS cert store for some versions of docker (see below)
{{< /hint >}}

This is more secure than the insecure registry solution.

1. Generate your own certificate:

   ```console
   $ mkdir -p certs

   $ openssl req \
     -newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key \
     -addext "subjectAltName = DNS:myregistry.domain.com" \
     -x509 -days 365 -out certs/domain.crt
   ```

   Be sure to use the name `myregistry.domain.com` as a CN.

2. Use the result to [start your registry with TLS enabled](deploying.md#get-a-certificate).

3. Instruct every Docker daemon to trust that certificate. The way to do this
   depends on your OS.

   - **Linux**: Copy the `domain.crt` file to
     `/etc/docker/certs.d/myregistrydomain.com:5000/ca.crt` on every Docker
     host. You do not need to restart Docker.

   - **Windows Server**:

     1.  Open Windows Explorer, right-click the `domain.crt`
         file, and choose Install certificate. When prompted, select the following
         options:

         | Store location                                | local machine |
         | Place all certificates in the following store | selected      |

     2.  Click **Browser** and select **Trusted Root Certificate Authorities**.

     3.  Click **Finish**. Restart Docker.

   - **Docker Desktop for Mac**: Follow the instructions in
     [Adding custom CA certificates](https://docs.docker.com/desktop/mac/#add-tls-certificates).
     Restart Docker.

   - **Docker Desktop for Windows**: Follow the instructions in
     [Adding custom CA certificates](https://docs.docker.com/desktop/windows/#adding-tls-certificates).
     Restart Docker.


## Troubleshoot insecure registry

This section lists some common failures and how to recover from them.

### Failing...

Failing to configure the Engine daemon and trying to pull from a registry that is not using
TLS results in the following message:

```none
FATA[0000] Error response from daemon: v1 ping attempt failed with error:
Get https://myregistrydomain.com:5000/v1/_ping: tls: oversized record received with length 20527.
If this private registry supports only HTTP or HTTPS with an unknown CA certificate, add
`--insecure-registry myregistrydomain.com:5000` to the daemon's arguments.
In the case of HTTPS, if you have access to the registry's CA certificate, no need for the flag;
simply place the CA certificate at /etc/docker/certs.d/myregistrydomain.com:5000/ca.crt
```

### Docker still complains about the certificate when using authentication?

When using authentication, some versions of Docker also require you to trust the
certificate at the OS level.

#### Ubuntu

```console
$ cp certs/domain.crt /usr/local/share/ca-certificates/myregistrydomain.com.crt
update-ca-certificates
```

#### Red Hat Enterprise Linux

```console
$ cp certs/domain.crt /etc/pki/ca-trust/source/anchors/myregistrydomain.com.crt
update-ca-trust
```

#### Oracle Linux

```console
$ update-ca-trust enable
```

Restart Docker for the changes to take effect.

### Windows

Open Windows Explorer, right-click the certificate, and choose
**Install certificate**.

Then, select the following options:

* Store location: local machine
* Check **place all certificates in the following store**
* Click **Browser**, and select **Trusted Root Certificate Authorities**
* Click **Finish**

[Learn more about managing TLS certificates](https://technet.microsoft.com/en-us/library/cc754841(v=ws.11).aspx#BKMK_addlocal).

After adding the CA certificate to Windows, restart Docker Desktop for Windows.

---

### Content About Notifications (`docs/content/about/notifications.md`)

---
description: Explains how to work with registry notifications
keywords: registry, on-prem, images, tags, repository, distribution, notifications, advanced
title: Work with notifications
---

The Registry supports sending webhook notifications in response to events
happening within the registry. Notifications are sent in response to manifest
pushes and pulls and layer pushes and pulls. These actions are serialized into
events. The events are queued into a registry-internal broadcast system which
queues and dispatches events to [_Endpoints_](#endpoints).



## Endpoints

Notifications are sent to _endpoints_ via HTTP requests. Each configured
endpoint has isolated queues, retry configuration and http targets within each
instance of a registry. When an action happens within the registry, it is
converted into an event which is dropped into an inmemory queue. When the
event reaches the end of the queue, an http request is made to the endpoint
until the request succeeds. The events are sent serially to each endpoint but
order is not guaranteed.

## Configuration

To set up a registry instance to send notifications to endpoints, one must add
them to the configuration. A simple example follows:

```yaml
notifications:
  endpoints:
    - name: alistener
      url: https://mylistener.example.com/event
      headers:
        Authorization: [Bearer <your token, if needed>]
      timeout: 500ms
      threshold: 5
      backoff: 1s
```

The above would configure the registry with an endpoint to send events to
`https://mylistener.example.com/event`, with the header "Authorization: Bearer
<your token, if needed>". The request would timeout after 500 milliseconds. If
5 failures happen consecutively, the registry backs off for 1 second before
trying again.

For details on the fields, see the [configuration documentation](configuration.md#notifications).

A properly configured endpoint should lead to a log message from the registry
upon startup:

```
INFO[0000] configuring endpoint alistener (https://mylistener.example.com/event), timeout=500ms, headers=map[Authorization:[Bearer <your token if needed>]]  app.id=812bfeb2-62d6-43cf-b0c6-152f541618a3 environment=development service=registry
```

## Events

Events have a well-defined JSON structure and are sent as the body of
notification requests. One or more events are sent in a structure called an
envelope. Each event has a unique ID that can be used to uniquely identify incoming
requests, if required. Along with that, an _action_ is provided with a
_target_, identifying the object mutated during the event.

The fields available in an `event` are described below.

Field | Type | Description
----- | ----- | -------------
id | string |ID provides a unique identifier for the event.
timestamp | Time | Timestamp is the time at which the event occurred.
action |  string |  Action indicates what action encompasses the provided event.
target | distribution.Descriptor | Target uniquely describes the target of the event.
length | int | Length in bytes of content. Same as Size field in Descriptor.
repository | string | Repository identifies the named repository.
fromRepository | string |  FromRepository identifies the named repository which a blob was mounted from if appropriate.
url | string | URL provides a direct link to the content.
tag | string | Tag identifies a tag name in tag events.
request | [RequestRecord](https://pkg.go.dev/github.com/distribution/distribution/notifications#RequestRecord) | Request covers the request that generated the event.
actor | [ActorRecord](https://pkg.go.dev/github.com/distribution/distribution/notifications#ActorRecord). |  Actor specifies the agent that initiated the event. For most situations, this could be from the authorization context of the request.
source | [SourceRecord](https://pkg.go.dev/github.com/distribution/distribution/notifications#SourceRecord) |  Source identifies the registry node that generated the event. Put differently, while the actor "initiates" the event, the source "generates" it.



The following is an example of a JSON event, sent in response to the pull of a
manifest:

```json
{
  "events": [
    {
      "id": "320678d8-ca14-430f-8bb6-4ca139cd83f7",
      "timestamp": "2016-03-09T14:44:26.402973972-08:00",
      "action": "pull",
      "target": {
        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
        "digest": "sha256:fea8895f450959fa676bcc1df0611ea93823a735a01205fd8622846041d0c7cf",
        "size": 708,
        "length": 708,
        "repository": "hello-world",
        "url": "http://192.168.100.227:5000/v2/hello-world/manifests/sha256:fea8895f450959fa676bcc1df0611ea93823a735a01205fd8622846041d0c7cf",
        "tag": "latest"
      },
      "request": {
        "id": "6df24a34-0959-4923-81ca-14f09767db19",
        "addr": "192.168.64.11:42961",
        "host": "192.168.100.227:5000",
        "method": "GET",
        "useragent": "curl/7.38.0"
      },
      "actor": {},
      "source": {
        "addr": "xtal.local:5000",
        "instanceID": "a53db899-3b4b-4a62-a067-8dd013beaca4"
      }
    }
  ]
}
```


The target struct of events which are sent when manifests and blobs are deleted
contains a subset of the data contained in Get and Put events. Specifically,
only the digest and repository are sent.

```json
{
  "target": {
    "digest": "sha256:d89e1bee20d9cb344674e213b581f14fbd8e70274ecf9d10c514bab78a307845",
    "repository": "library/test"
  }
}
```

> **Note**: As of version 2.1, the `length` field for event targets
> is being deprecated for the `size` field, bringing the target in line with
> common nomenclature. Both will continue to be set for the foreseeable
> future. Newer code should favor `size` but accept either.

## Envelope

The envelope contains one or more events, with the following json structure:

```json
{
  "events": [ "..." ]
}
```

While events may be sent in the same envelope, the set of events within that
envelope have no implied relationship. For example, the registry may choose to
group unrelated events and send them in the same envelope to reduce the total
number of requests.

The full package has the mediatype
"application/vnd.docker.distribution.events.v2+json", which is set on the
request coming to an endpoint.

An example of a full event may look as follows:

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Responses

The registry is fairly accepting of the response codes from endpoints. If an
endpoint responds with any 2xx or 3xx response code (after following
redirects), the message is considered to have been delivered, and is discarded.

In turn, it is recommended that endpoints are accepting of incoming responses,
as well. While the format of event envelopes are standardized by media type,
any "pickyness" about validation may cause the queue to backup on the
registry.

## Monitoring

The state of the endpoints are reported via the debug/vars http interface,
usually configured to `http://localhost:5001/debug/vars`. Information such as
configuration and metrics are available by endpoint.

The following provides an example of a few endpoints that have experienced
several failures and have since recovered:

```json
{
  "notifications": {
    "endpoints": [
      {
        "name": "local-5003",
        "url": "http://localhost:5003/callback",
        "Headers": {
          "Authorization": [
            "Bearer \u003can example token\u003e"
          ]
        },
        "Timeout": 1000000000,
        "Threshold": 10,
        "Backoff": 1000000000,
        "Metrics": {
          "Pending": 76,
          "Events": 76,
          "Successes": 0,
          "Failures": 0,
          "Errors": 46,
          "Statuses": {
          }
        }
      },
      {
        "name": "local-8083",
        "url": "http://localhost:8083/callback",
        "Headers": null,
        "Timeout": 1000000000,
        "Threshold": 10,
        "Backoff": 1000000000,
        "Metrics": {
          "Pending": 0,
          "Events": 76,
          "Successes": 76,
          "Failures": 0,
          "Errors": 28,
          "Statuses": {
            "202 Accepted": 76
          }
        }
      }
    ]
  }
}
```

If using notification as part of a larger application, it is _critical_ to
monitor the size ("Pending" above) of the endpoint queues. If failures or
queue sizes are increasing, it can indicate a larger problem.

The logs are also a valuable resource for monitoring problems. A failing
endpoint leads to messages similar to the following:

```none
ERRO[0340] retryingsink: error writing events: httpSink{http://localhost:5003/callback}: error posting: Post http://localhost:5003/callback: dial tcp 127.0.0.1:5003: connection refused, retrying
WARN[0340] httpSink{http://localhost:5003/callback} encountered too many errors, backing off
```

The above indicates that several errors caused a backoff and the registry
waits before retrying.

## Considerations

Currently, the queues are inmemory, so endpoints should be _reasonably
reliable_. They are designed to make a best-effort to send the messages but if
an instance is lost, messages may be dropped. If an endpoint goes down, care
should be taken to ensure that the registry instance is not terminated before
the endpoint comes back up or messages are lost.

This can be mitigated by running endpoints in close proximity to the registry
instances. One could run an endpoint that pages to disk and then forwards a
request to provide better durability.

The notification system is designed around a series of interchangeable _sinks_
which can be wired up to achieve interesting behavior. If this system doesn't
provide acceptable guarantees, adding a transactional `Sink` to the registry
is a possibility, although it may have an effect on request service time.
See the
[godoc](https://pkg.go.dev/github.com/distribution/distribution/notifications#Sink)
for more information.

---

### Content Recipes Apache (`docs/content/recipes/apache.md`)

---
description: Restricting access to your registry using an apache proxy
keywords: registry, on-prem, images, tags, repository, distribution, authentication, proxy, apache, httpd, TLS, recipe, advanced
title: Authenticate proxy with apache
---

## Use-case

People already relying on an apache proxy to authenticate their users to other services might want to leverage it and have Registry communications tunneled through the same pipeline.

Usually, that includes enterprise setups using LDAP/AD on the backend and a SSO mechanism fronting their internal http portal.

### Alternatives

If you just want authentication for your registry, and are happy maintaining users access separately, you should really consider sticking with the native [basic auth registry feature](../about/deploying.md#native-basic-auth).

### Solution

With the method presented here, you implement basic authentication for docker engines in a reverse proxy that sits in front of your registry.

While we use a simple htpasswd file as an example, any other apache authentication backend should be fairly easy to implement once you are done with the example.

We also implement push restriction (to a limited user group) for the sake of the example. Again, you should modify this to fit your mileage.

### Gotchas

While this model gives you the ability to use whatever authentication backend you want through the secondary authentication mechanism implemented inside your proxy, it also requires that you move TLS termination from the Registry to the proxy itself.

Furthermore, introducing an extra http layer in your communication pipeline adds complexity when deploying, maintaining, and debugging.

## Setting things up

Read again [the requirements](../#requirements).

Ready?

Run the following script:

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Starting and stopping

Now, start your stack:

```console
$ docker compose up -d
```

Log in with a "push" authorized user (using `testuserpush` and `testpasswordpush`), then tag and push your first image:

```console
$ docker login myregistrydomain.com:5043
$ docker tag ubuntu myregistrydomain.com:5043/test
$ docker push myregistrydomain.com:5043/test
```

Now, log in with a "pull-only" user (using `testuser` and `testpassword`), then pull back the image:

```console
$ docker login myregistrydomain.com:5043
$ docker pull myregistrydomain.com:5043/test
```

Verify that the "pull-only" can NOT push:

```console
$ docker push myregistrydomain.com:5043/test
```

---

### Content Recipes Mirror (`docs/content/recipes/mirror.md`)

---
description: Setting-up a local mirror for Docker Hub images
keywords: registry, on-prem, images, tags, repository, distribution, mirror, Hub, recipe, advanced
title: Registry as a pull through cache
---

## Use-case

If you have multiple consumers of containers running in your environment, such as
multiple physical or virtual machines using containers, or a Kubernetes cluster,
each consumer fetches an images it doesn't have locally, from the external registry.
You can run a local registry mirror and point all your consumers
there, to avoid this extra internet traffic.

### Alternatives

Alternatively, if the set of images you are using is well delimited, you can
simply pull them manually and push them to a simple, local, private registry.

Furthermore, if your images are all built in-house, not using the Hub at all and
relying entirely on your local registry is the simplest scenario.

### Gotcha

It's currently possible to mirror only one upstream registry at a time.

The URL of a pull-through registry mirror must be the root of a domain.
No path components other than an optional trailing slash (`/`) are allowed.
The following table shows examples of allowed and disallowed mirror URLs.

| URL                                    | Allowed |
| -------------------------------------- | ------- |
| `https://mirror.company.example`       | Yes     |
| `https://mirror.company.example/`      | Yes     |
| `https://mirror.company.example/foo`   | No      |
| `https://mirror.company.example#bar`   | No      |
| `https://mirror.company.example?baz=1` | No      |

> **Note**
>
> Mirrors of Docker Hub are still subject to Docker's [fair usage policy](https://docs.docker.com/docker-hub/usage/).

### Solution

The Registry can be configured as a pull through cache. In this mode a Registry
responds to all normal docker pull requests but stores all content locally.

## How does it work?

The first time you request an image from your local registry mirror, it pulls
the image from the public Docker registry and stores it locally before handing
it back to you. On subsequent requests, the local registry mirror is able to
serve the image from its own storage.

### What if the content changes on the Hub?

When a pull is attempted with a tag, the Registry checks the remote to
ensure if it has the latest version of the requested content. Otherwise, it
fetches and caches the latest content.

### What about my disk?

In environments with high churn rates, stale data can build up in the cache.
When running as a pull through cache the Registry periodically removes old
content to save disk space. Subsequent requests for removed content causes a
remote fetch and local re-caching.

To ensure best performance and guarantee correctness the Registry cache should
be configured to use the `filesystem` driver for storage.

## Run a Registry as a pull-through cache

The easiest way to run a registry as a pull through cache is to run the official
Registry image.
At least, you need to specify `proxy.remoteurl` within `/etc/distribution/config.yml`
as described in the following subsection.

Multiple registry caches can be deployed over the same back-end, but each 
instance in a registry cache cluster is stateless, so it maintains its own 
cache.

Note that concurrent inflight pulls will make multiple requests.

> **Note**
>
> Service accounts included in the Team plan are limited to 5,000 pulls per day.
> See [Service Accounts](https://docs.docker.com/docker-hub/service-accounts/) for more details.

### Configure the cache

To configure a Registry to run as a pull through cache, the addition of a
`proxy` section is required to the config file.

To access private images on the Docker Hub, a username and password can
be supplied.

```yaml
proxy:
  remoteurl: https://registry-1.docker.io
  username: [username]
  password: [password]
  ttl: 168h
```

> **Warning**: If you specify a username and password, it's very important to
> understand that private resources that this user has access to Docker Hub is
> made available on your mirror. **You must secure your mirror** by
> implementing authentication if you expect these resources to stay private!

> **Warning**: For the scheduler to clean up old entries, `delete` must
> be enabled in the registry configuration. See
> [Registry Configuration](../about/configuration.md) for more details.

### Configure the Docker daemon

Either pass the `--registry-mirror` option when starting `dockerd` manually,
or edit [`/etc/docker/daemon.json`](https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file)
and add the `registry-mirrors` key and value, to make the change persistent.

```json
{
  "registry-mirrors": ["https://mirror.company.example"]
}
```

> **Note**
>
> The mirror URL must be the root of the domain.

> **Note**
>
> Currently Docker daemon supports only mirrors of Docker Hub.
> It is not possible to run the Docker daemon against a pull through cache with another upstream registry.

Save the file and reload Docker for the change to take effect.

> Some log messages that appear to be errors are actually informational messages.
>
> Check the `level` field to determine whether
> the message is warning you about an error or is giving you information.
> For example, this log message is informational:
>
> ```conf
> time="2017-06-02T15:47:37Z" level=info msg="error statting local store, serving from upstream: unknown blob" go.version=go1.7.4
> ```
>
> It's telling you that the file doesn't exist yet in the local cache and is
> being pulled from upstream.

---

### Content Recipes Nginx (`docs/content/recipes/nginx.md`)

---
description: Restricting access to your registry using a nginx proxy
keywords: registry, on-prem, images, tags, repository, distribution, nginx, proxy, authentication, TLS, recipe, advanced
title: Authenticate proxy with nginx
---

## Use-case

People already relying on a nginx proxy to authenticate their users to other
services might want to leverage it and have Registry communications tunneled
through the same pipeline.

Usually, that includes enterprise setups using LDAP/AD on the backend and a SSO
mechanism fronting their internal http portal.

### Alternatives

If you just want authentication for your registry, and are happy maintaining
users access separately, you should really consider sticking with the native
[basic auth registry feature](../about/deploying.md#native-basic-auth).

### Solution

With the method presented here, you implement basic authentication for docker
engines in a reverse proxy that sits in front of your registry.

While we use a simple htpasswd file as an example, any other nginx
authentication backend should be fairly easy to implement once you are done with
the example.

We also implement push restriction (to a limited user group) for the sake of the
example. Again, you should modify this to fit your mileage.

### Gotchas

While this model gives you the ability to use whatever authentication backend
you want through the secondary authentication mechanism implemented inside your
proxy, it also requires that you move TLS termination from the Registry to the
proxy itself.

> **Note**: It is not recommended to bind your registry to `localhost:5000` without
> authentication. This creates a potential loophole in your registry security.
> As a result, anyone who can log on to the server where your registry is running
> can push images without authentication.

Furthermore, introducing an extra http layer in your communication pipeline
makes it more complex to deploy, maintain, and debug. Make sure the extra
complexity is required.

For instance, Amazon's Elastic Load Balancer (ELB) in HTTPS mode already sets
the following client header:

```none
X-Real-IP
X-Forwarded-For
X-Forwarded-Proto
```

So if you have an Nginx instance sitting behind it, remove these lines from the
example config below:

```none
proxy_set_header  Host              $http_host;   # required for docker client's sake
proxy_set_header  X-Real-IP         $remote_addr; # pass on real client's IP
proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
proxy_set_header  X-Forwarded-Proto $scheme;
```

Otherwise Nginx resets the ELB's values, and the requests are not routed
properly. For more information, see
[#970](https://github.com/distribution/distribution/issues/970).

## Setting things up

Review the [requirements](../#requirements), then follow these steps.

1. Create the required directories

   ```console
   $ mkdir -p auth data
   ```

2. Create the main nginx configuration. Paste this code block into a new file called `auth/nginx.conf`:

   ```
/* Detailed source-code truncated for AI context efficiency. */
```

3. Create a password file `auth/nginx.htpasswd` for "testuser" and "testpassword".

   ```console
   $ docker run --rm --entrypoint htpasswd httpd -Bbn testuser testpassword > auth/nginx.htpasswd
   ```

   > **Note**: If you do not want to use `bcrypt`, you can omit the `-B` parameter.

4. Copy your certificate files to the `auth/` directory.

   ```console
   $ cp domain.crt auth
   $ cp domain.key auth
   ```

5. Create the compose file. Paste the following YAML into a new file called `docker-compose.yml`.

   ```yaml
   services:
       nginx:
         # Note : Only nginx:alpine supports bcrypt.
         # If you don't need to use bcrypt, you can use a different tag.
         # Ref. https://github.com/nginxinc/docker-nginx/issues/29
         image: "nginx:alpine"
         ports:
           - 5043:443
         depends_on:
           - registry
         volumes:
           - ./auth:/etc/nginx/conf.d
           - ./auth/nginx.conf:/etc/nginx/nginx.conf:ro

       registry:
         image: registry:3
         volumes:
           - ./data:/var/lib/registry
   ```

## Starting and stopping

Now, start your stack:

```consonle
$ docker compose up -d
```

Login with a "push" authorized user (using `testuser` and `testpassword`), then
tag and push your first image:

```console
$ docker login -u=testuser -p=testpassword -e=root@example.ch myregistrydomain.com:5043
$ docker tag ubuntu myregistrydomain.com:5043/test
$ docker push myregistrydomain.com:5043/test
$ docker pull myregistrydomain.com:5043/test
```

---

### Content Recipes Osx Setup Guide (`docs/content/recipes/osx-setup-guide.md`)

---
description: Explains how to run a registry on macOS
keywords: registry, on-prem, images, tags, repository, distribution, macOS, recipe, advanced
title: macOS setup guide
---

## Use-case

This is useful if you intend to run a registry server natively on macOS.

### Alternatives

You can start a VM on macOS, and deploy your registry normally as a container using Docker inside that VM.

### Solution

Using the method described here, you install and compile your own from the git repository and run it as an macOS agent.

### Gotchas

Production services operation on macOS is out of scope of this document. Be sure you understand well these aspects before considering going to production with this.

## Setup golang on your machine

If you know, safely skip to the next section.

If you don't, the TLDR is:

```console
$ bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)
$ source ~/.gvm/scripts/gvm
$ gvm install go1.4.2
$ gvm use go1.4.2
```

If you want to understand, you should read [How to Write Go Code](https://golang.org/doc/code.html).

## Checkout the source tree

```console
$ mkdir -p $GOPATH/src/github.com/distribution
$ git clone https://github.com/distribution/distribution.git $GOPATH/src/github.com/distribution/distribution
$ cd $GOPATH/src/github.com/distribution/distribution
```

## Build the binary

```console
$ GOPATH=$(PWD)/Godeps/_workspace:$GOPATH make binaries
$ sudo mkdir -p /usr/local/libexec
$ sudo cp bin/registry /usr/local/libexec/registry
```

## Setup

Copy the registry configuration file in place:

```console
$ mkdir /Users/Shared/Registry
$ cp docs/content/recipes/osx/config.yml /Users/Shared/Registry/config.yml
```

## Modify ports if needed

MacOS runs an Airplay receiver on port 5000 by default, which is the same port as the registry server. You can either disable the Airplay receiver in _System Settings… > General > AirDrop & Handoff > AirPlay Receiver_, or change the listening ports in the config file that you have just copied to /Users/Shared/Registry/config.yml. 

## Run the registry under launchd

Copy the registry plist into place:

```console
$ plutil -lint docs/content/recipes/osx/com.docker.registry.plist
$ cp docs/content/recipes/osx/com.docker.registry.plist ~/Library/LaunchAgents/
$ chmod 644 ~/Library/LaunchAgents/com.docker.registry.plist
```

Start the registry:

```console
$ launchctl load ~/Library/LaunchAgents/com.docker.registry.plist
```

### Restart the registry service

```console
$ launchctl stop com.docker.registry
$ launchctl start com.docker.registry
```

### Unload the registry service

```console
$ launchctl unload ~/Library/LaunchAgents/com.docker.registry.plist
```

---

### Content Recipes Systemd (`docs/content/recipes/systemd.md`)

---
description: Using systemd to manage registry container
keywords: registry, on-prem, systemd, socket-activated, recipe, advanced
title: Start registry via systemd
---

## Use-case

Using systemd to manage containers can make service discovery and maintenance easier
by managing all services in the same way. Additionally, when using Podman, systemd
can start the registry with socket-activation, providing additional security options:

* Run as non-root and expose on a low-numbered socket (< 1024)
* Run with `--network=none`

### Docker

When deploying the registry via Docker, a simple service file can be used to manage
the registry:

registry.service

```ini
[Unit]
Description=Distribution registry
After=docker.service
Requires=docker.service

[Service]
#TimeoutStartSec=0
Restart=always
ExecStartPre=-/usr/bin/docker stop %N
ExecStartPre=-/usr/bin/docker rm %N
ExecStart=/usr/bin/docker run --name %N \
    -v registry:/var/lib/registry \
    -p 5000:5000 \
    registry:3

[Install]
WantedBy=multi-user.target
```

In this case, the registry will store images in the named-volume `registry`.
Note that the container is destroyed on restart instead of using `--rm` or
destroy on stop. This is done to make accessing `docker logs ...` easier in
the case of issues.

### Podman

Podman offers tighter integration with systemd than Docker does, and supports
socket-activation of containers.

#### Create service file

```sh
podman create --name registry --network=none -v registry:/var/lib/registry registry:3
podman generate systemd --name --new registry > registry.service
```

#### Create socket file

registry.socket

```ini
[Unit]
Description=Distribution registry

[Socket]
ListenStream=5000

[Install]
WantedBy=sockets.target
```

### Installation

Installation can be either rootful or rootless. For Docker, rootless configurations
often include additional setup steps that are beyond the scope of this recipe, whereas
for Podman, rootless containers generally work out of the box.

#### Rootful

Run as root:

* Copy registry.service (and registry.socket if relevant) to /etc/systemd/service/
* Run `systemctl daemon-reload`
* Enable the service:
  * When using socket activation: `systemctl enable registry.socket`
  * When **not** using socket activation: `systemctl enable registry.service`
* Start the service:
  * When using socket activation: `systemctl start registry.socket`
  * When **not** using socket activation: `systemctl start registry.service`

#### Rootless

Run as the target user:

* Copy registry.service (and registry.socket if relevant) to ~/.config/systemd/user/
* Run `systemctl --user daemon-reload`
* Enable the service:
  * When using socket activation: `systemctl --user enable registry.socket`
  * When **not** using socket activation: `systemctl --user enable registry.service`
* Start the service:
  * When using socket activation: `systemctl --user start registry.socket`
  * When **not** using socket activation: `systemctl --user start registry.service`

**Note**: To have rootless services start on boot, it may be necessary to enable linger
via `loginctl enable-linger $USER`.

---

### Content Spec Api (`docs/content/spec/api.md`)

---
title: "HTTP API V2"
description: "Specification for the Registry API."
keywords: registry, on-prem, images, tags, repository, distribution, api, advanced
aliases:
  - /reference/api/registry_api/
---

## Introduction

The _Docker Registry HTTP API_ is the protocol to facilitate distribution of
images to the docker engine. It interacts with instances of the docker
registry, which is a service to manage information about docker images and
enable their distribution. The specification covers the operation of version 2
of this API, known as _Docker Registry HTTP API V2_.

While the V1 registry protocol is usable, there are several problems with the
architecture that have led to this new version. The main driver of this
specification is a set of changes to the Docker image format, covered in
[docker/docker#8093](https://github.com/docker/docker/issues/8093).
The new, self-contained image manifest simplifies image definition and improves
security. This specification will build on that work, leveraging new properties
of the manifest format to improve performance, reduce bandwidth usage and
decrease the likelihood of backend corruption.

For relevant details and history leading up to this specification, please see
the following issues:

- [docker/docker#8093](https://github.com/docker/docker/issues/8093)
- [docker/docker#9015](https://github.com/docker/docker/issues/9015)
- [docker/docker-registry#612](https://github.com/docker/docker-registry/issues/612)

### Scope

This specification covers the URL layout and protocols of the interaction
between docker registry and docker core. This will affect the docker core
registry API and the rewrite of docker-registry. Docker registry
implementations may implement other API endpoints, but they are not covered by
this specification.

This includes the following features:

- Namespace-oriented URI Layout
- PUSH/PULL registry server for V2 image manifest format
- Resumable layer PUSH support
- V2 Client library implementation

While authentication and authorization support will influence this
specification, details of the protocol will be left to a future specification.
Relevant header definitions and error codes are present to provide an
indication of what a client may encounter.

### Use Cases

For the most part, the use cases of the former registry API apply to the new
version. Differentiating use cases are covered below.

#### Image Verification

A docker engine instance would like to run verified image named
"library/ubuntu", with the tag "latest". The engine contacts the registry,
requesting the manifest for "library/ubuntu:latest". An untrusted registry
returns a manifest. Before proceeding to download the individual layers, the
engine verifies the manifest's signature, ensuring that the content was
produced from a trusted source and no tampering has occurred. After each layer
is downloaded, the engine verifies the digest of the layer, ensuring that the
content matches that specified by the manifest.

#### Resumable Push

Company X's build servers lose connectivity to docker registry before
completing an image layer transfer. After connectivity returns, the build
server attempts to re-upload the image. The registry notifies the build server
that the upload has already been partially attempted. The build server
responds by only sending the remaining data to complete the image file.

#### Resumable Pull

Company X is having more connectivity problems but this time in their
deployment datacenter. When downloading an image, the connection is
interrupted before completion. The client keeps the partial data and uses http
`Range` requests to avoid downloading repeated data.

#### Layer Upload De-duplication

Company Y's build system creates two identical docker layers from build
processes A and B. Build process A completes uploading the layer before B.
When process B attempts to upload the layer, the registry indicates that its
not necessary because the layer is already known.

If process A and B upload the same layer at the same time, both operations
will proceed and the first to complete will be stored in the registry (Note:
we may modify this to prevent dogpile with some locking mechanism).

### Changes

The V2 specification has been written to work as a living document, specifying
only what is certain and leaving what is not specified open or to future
changes. Only non-conflicting additions should be made to the API and accepted
changes should avoid preventing future changes from happening.

This section should be updated when changes are made to the specification,
indicating what is different. Optionally, we may start marking parts of the
specification to correspond with the versions enumerated here.

Each set of changes is given a letter corresponding to a set of modifications
that were applied to the baseline specification. These are merely for
reference and shouldn't be used outside the specification other than to
identify a set of modifications.

<dl>
  <dt>l</dt>
  <dd>
    <ul>
      <li>Document TOOMANYREQUESTS error code.</li>
    </ul>
  </dd>

  <dt>k</dt>
  <dd>
    <ul>
      <li>Document use of Accept and Content-Type headers in manifests endpoint.</li>
    </ul>
  </dd>

  <dt>j</dt>
  <dd>
    <ul>
      <li>Add ability to mount blobs across repositories.</li>
    </ul>
  </dd>

  <dt>i</dt>
  <dd>
    <ul>
      <li>Clarified expected behavior response to manifest HEAD request.</li>
    </ul>
  </dd>

  <dt>h</dt>
  <dd>
    <ul>
      <li>All mention of tarsum removed.</li>
    </ul>
  </dd>

  <dt>g</dt>
  <dd>
    <ul>
      <li>Clarify behavior of pagination behavior with unspecified parameters.</li>
    </ul>
  </dd>

  <dt>f</dt>
  <dd>
    <ul>
      <li>Specify the delete API for layers and manifests.</li>
    </ul>
  </dd>

  <dt>e</dt>
  <dd>
    <ul>
      <li>Added support for listing registry contents.</li>
      <li>Added pagination to tags API.</li>
      <li>Added common approach to support pagination.</li>
    </ul>
  </dd>

  <dt>d</dt>
  <dd>
    <ul>
      <li>Allow repository name components to be one character.</li>
      <li>Clarified that single component names are allowed.</li>
    </ul>
  </dd>

  <dt>c</dt>
  <dd>
    <ul>
      <li>Added section covering digest format.</li>
      <li>Added more clarification that manifest cannot be deleted by tag.</li>
    </ul>
  </dd>

  <dt>b</dt>
  <dd>
    <ul>
      <li>Added capability of doing streaming upload to PATCH blob upload.</li>
      <li>Updated PUT blob upload to no longer take final chunk, now requires entire data or no data.</li>
      <li>Removed `416 Requested Range Not Satisfiable` response status from PUT blob upload.</li>
    </ul>
  </dd>

  <dt>a</dt>
  <dd>
    <ul>
      <li>Added support for immutable manifest references in manifest endpoints.</li>
      <li>Deleting a manifest by tag has been deprecated.</li>
      <li>Specified `Docker-Content-Digest` header for appropriate entities.</li>
      <li>Added error code for unsupported operations.</li>
    </ul>
  </dd>
</dl>

## Overview

This section covers client flows and details of the API endpoints. The URI
layout of the new API is structured to support a rich authentication and
authorization model by leveraging namespaces. All endpoints will be prefixed
by the API version and the repository name:

```none
/v2/<name>/
```

For example, an API endpoint that will work with the `library/ubuntu`
repository, the URI prefix will be:

    /v2/library/ubuntu/

This scheme provides rich access control over various operations and methods
using the URI prefix and http methods that can be controlled in variety of
ways.

Classically, repository names have always been two path components where each
path component is less than 30 characters. The V2 registry API does not
enforce this. The rules for a repository name are as follows:

1. A repository name is broken up into _path components_. A component of a
   repository name must be at least one lowercase, alpha-numeric characters,
   optionally separated by periods, dashes or underscores. More strictly, it
   must match the regular expression `[a-z0-9]+(?:[._-][a-z0-9]+)*`.
2. If a repository  name has two or more path components, they must be
   separated by a forward slash ("/").
3. The total length of a repository name, including slashes, must be less than
   256 characters.

These name requirements _only_ apply to the registry API and should accept a
superset of what is supported by other docker ecosystem components.

All endpoints should support aggressive http caching, compression and range
headers, where appropriate. The new API attempts to leverage HTTP semantics
where possible but may break from standards to implement targeted features.

For detail on individual endpoints, please see the [_Detail_](#detail)
section.

### Errors

Actionable failure conditions, covered in detail in their relevant sections,
are reported as part of 4xx responses, in a json response body. One or more
errors will be returned in the following format:

```none
    {
        "errors": [
            {
                "code": <error identifier>,
                "message": <message describing condition>,
                "detail": <unstructured>
            },
            ...
        ]
    }
```

The `code` field will be a unique identifier, all caps with underscores by
convention. The `message` field will be a human readable string. The optional
`detail` field may contain arbitrary json data providing information the
client can use to resolve the issue.

While the client can take action on certain error codes, the registry may add
new error codes over time. All client implementations should treat unknown
error codes as `UNKNOWN`, allowing future error codes to be added without
breaking API compatibility. For the purposes of the specification error codes
will only be added and never removed.

For a complete account of all error codes, please see the [_Errors_](#errors-2)
section.

### API Version Check

A minimal endpoint, mounted at `/v2/` will provide version support information
based on its response statuses. The request format is as follows:

```none
GET /v2/
```

If a `200 OK` response is returned, the registry implements the V2(.1)
registry API and the client may proceed safely with other V2 operations.
Optionally, the response may contain information about the supported paths in
the response body. The client should be prepared to ignore this data.

If a `401 Unauthorized` response is returned, the client should take action
based on the contents of the "WWW-Authenticate" header and try the endpoint
again. Depending on access control setup, the client may still have to
authenticate against different resources, even if this check succeeds.

If `404 Not Found` response status, or other unexpected status, is returned,
the client should proceed with the assumption that the registry does not
implement V2 of the API.

When a `200 OK` or `401 Unauthorized` response is returned, the
"Docker-Distribution-API-Version" header should be set to "registry/2.0".
Clients may require this header value to determine if the endpoint serves this
API. When this header is omitted, clients may fallback to an older API version.

### Content Digests

This API design is driven heavily by [content addressability](https://en.wikipedia.org/wiki/Content-addressable_storage).
The core of this design is the concept of a content addressable identifier. It
uniquely identifies content by taking a collision-resistant hash of the bytes.
Such an identifier can be independently calculated and verified by selection
of a common _algorithm_. If such an identifier can be communicated in a secure
manner, one can retrieve the content from an insecure source, calculate it
independently and be certain that the correct content was obtained. Put simply,
the identifier is a property of the content.

To disambiguate from other concepts, we call this identifier a _digest_. A
_digest_ is a serialized hash result, consisting of a _algorithm_ and _hex_
portion. The _algorithm_ identifies the methodology used to calculate the
digest. The _hex_ portion is the hex-encoded result of the hash.

We define a _digest_ string to match the following grammar:
```
digest      := algorithm ":" hex
algorithm   := /[A-Za-z0-9_+.-]+/
hex         := /[A-Fa-f0-9]+/
```

Some examples of _digests_ include the following:

digest                                                                            | description                                   |
----------------------------------------------------------------------------------|------------------------------------------------
sha256:6c3c624b58dbbcd3c0dd82b4c53f04194d1247c6eebdaab7c610cf7d66709b3b           | Common sha256 based digest                    |

While the _algorithm_ does allow one to implement a wide variety of
algorithms, compliant implementations should use sha256. Heavy processing of
input before calculating a hash is discouraged to avoid degrading the
uniqueness of the _digest_ but some canonicalization may be performed to
ensure consistent identifiers.

Let's use a simple example in pseudo-code to demonstrate a digest calculation:
```
let C = 'a small string'
let B = sha256(C)
let D = 'sha256:' + EncodeHex(B)
let ID(C) = D
```

Above, we have bytestring `C` passed into a function, `SHA256`, that returns a
bytestring `B`, which is the hash of `C`. `D` gets the algorithm concatenated
with the hex encoding of `B`. We then define the identifier of `C` to `ID(C)`
as equal to `D`. A digest can be verified by independently calculating `D` and
comparing it with identifier `ID(C)`.

#### Digest Header

To provide verification of http content, any response may include a
`Docker-Content-Digest` header. This will include the digest of the target
entity returned in the response. For blobs, this is the entire blob content. For
manifests, this is the manifest body without the signature content, also known
as the JWS payload. Note that the commonly used canonicalization for digest
calculation may be dependent on the mediatype of the content, such as with
manifests.

The client may choose to ignore the header or may verify it to ensure content
integrity and transport security. This is most important when fetching by a
digest. To ensure security, the content should be verified against the digest
used to fetch the content. At times, the returned digest may differ from that
used to initiate a request. Such digests are considered to be from different
_domains_, meaning they have different values for _algorithm_. In such a case,
the client may choose to verify the digests in both domains or ignore the
server's digest. To maintain security, the client _must_ always verify the
content against the _digest_ used to fetch the content.

> __IMPORTANT:__ If a _digest_ is used to fetch content, the client should use
> the same digest used to fetch the content to verify it. The header
> `Docker-Content-Digest` should not be trusted over the "local" digest.

### Pulling An Image

An "image" is a combination of a JSON manifest and individual layer files. The
process of pulling an image centers around retrieving these two components.

The first step in pulling an image is to retrieve the manifest. For reference,
the relevant manifest fields for the registry are the following:

 field    | description                                    |
----------|------------------------------------------------|
name      | The name of the image.                         |
tag       | The tag for this version of the image.         |
fsLayers  | A list of layer descriptors (including digest) |
signature | A JWS used to verify the manifest content      |

For more information about the manifest format, please see
[docker/docker#8093](https://github.com/docker/docker/issues/8093).

When the manifest is in hand, the client must verify the signature to ensure
the names and layers are valid. Once confirmed, the client will then use the
digests to download the individual layers. Layers are stored in as blobs in
the V2 registry API, keyed by their digest.

#### Pulling an Image Manifest

The image manifest can be fetched with the following url:

```none
GET /v2/<name>/manifests/<reference>
```

The `name` and `reference` parameter identify the image and are required. The
reference may include a tag or digest.

The client should include an Accept header indicating which manifest content
types it supports. For more details on the manifest format and content types,
see [Image Manifest Version 2, Schema 2](manifest-v2-2.md).
In a successful response, the Content-Type header will indicate which manifest type is being returned.

A `404 Not Found` response will be returned if the image is unknown to the
registry. If the image exists and the response is successful, the image
manifest will be returned, with the following format (see
[docker/docker#8093](https://github.com/docker/docker/issues/8093) for details):

```none
{
    "name": <name>,
    "tag": <tag>,
    "fsLayers": [
        {
            "blobSum": <digest>
        },
        ...
    ],
    "history": <v1 images>,
    "signature": <JWS>
}
```

The client should verify the returned manifest signature for authenticity
before fetching layers.

##### Existing Manifests

The image manifest can be checked for existence with the following url:

```none
HEAD /v2/<name>/manifests/<reference>
```

The `name` and `reference` parameter identify the image and are required. The
reference may include a tag or digest.

A `404 Not Found` response will be returned if the image is unknown to the
registry. If the image exists and the response is successful the response will
be as follows:

```none
200 OK
Content-Length: <length of manifest>
Docker-Content-Digest: <digest>
```

#### Pulling a Layer

Layers are stored in the blob portion of the registry, keyed by digest.
Pulling a layer is carried out by a standard http request. The URL is as
follows:

    GET /v2/<name>/blobs/<digest>

Access to a layer will be gated by the `name` of the repository but is
identified uniquely in the registry by `digest`.

This endpoint may issue a 307 (302 for <HTTP 1.1) redirect to another service
for downloading the layer and clients should be prepared to handle redirects.

This endpoint should support aggressive HTTP caching for image layers. Support
for Etags, modification dates and other cache control headers should be
included. To allow for incremental downloads, `Range` requests should be
supported, as well.

### Pushing An Image

Pushing an image works in the opposite order as a pull. After assembling the
image manifest, the client must first push the individual layers. When the
layers are fully pushed into the registry, the client should upload the signed
manifest.

The details of each step of the process are covered in the following sections.

#### Pushing a Layer

All layer uploads use two steps to manage the upload process. The first step
starts the upload in the registry service, returning a url to carry out the
second step. The second step uses the upload url to transfer the actual data.
Uploads are started with a POST request which returns a url that can be used
to push data and check upload status.

The `Location` header will be used to communicate the upload location after
each request. While it won't change in this specification, clients should
use the most recent value returned by the API.

##### Starting An Upload

To begin the process, a POST request should be issued in the following format:

```none
POST /v2/<name>/blobs/uploads/
```

The parameters of this request are the image namespace under which the layer
will be linked. Responses to this request are covered below.

##### Existing Layers

The existence of a layer can be checked via a `HEAD` request to the blob store
API. The request should be formatted as follows:

```none
HEAD /v2/<name>/blobs/<digest>
```

If the layer with the digest specified in `digest` is available, a 200 OK
response will be received, with no actual body content (this is according to
http specification). The response will look as follows:

```none
200 OK
Content-Length: <length of blob>
Docker-Content-Digest: <digest>
```

When this response is received, the client can assume that the layer is
already available in the registry under the given name and should take no
further action to upload the layer. Note that the binary digests may differ
for the existing registry layer, but the digests will be guaranteed to match.

##### Uploading the Layer

If the POST request is successful, a `202 Accepted` response will be returned
with the upload URL in the `Location` header:

```none
202 Accepted
Location: /v2/<name>/blobs/uploads/<uuid>
Range: bytes=0-<offset>
Content-Length: 0
Docker-Upload-UUID: <uuid>
```

The rest of the upload process can be carried out with the returned url,
called the "Upload URL" from the `Location` header. All responses to the
upload url, whether sending data or getting status, will be in this format.
Though the URI format (`/v2/<name>/blobs/uploads/<uuid>`) for the `Location`
header is specified, clients should treat it as an opaque url and should never
try to assemble it. While the `uuid` parameter may be an actual UUID, this
proposal imposes no constraints on the format and clients should never impose
any.

If clients need to correlate local upload state with remote upload state, the
contents of the `Docker-Upload-UUID` header should be used. Such an id can be
used to key the last used location header when implementing resumable uploads.

##### Upload Progress

The progress and chunk coordination of the upload process will be coordinated
through the `Range` header. While this is a non-standard use of the `Range`
header, there are examples of [similar approaches](https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol) in APIs with heavy use.
For an upload that just started, for an example with a 1000 byte layer file,
the `Range` header would be as follows:

```none
Range: bytes=0-0
```

To get the status of an upload, issue a GET request to the upload URL:

```none
GET /v2/<name>/blobs/uploads/<uuid>
Host: <registry host>
```

The response will be similar to the above, except will return 204 status:

```none
204 No Content
Location: /v2/<name>/blobs/uploads/<uuid>
Range: bytes=0-<offset>
Docker-Upload-UUID: <uuid>
```

Note that the HTTP `Range` header byte ranges are inclusive and that will be
honored, even in non-standard use cases.

##### Monolithic Upload

A monolithic upload is simply a chunked upload with a single chunk and may be
favored by clients that would like to avoided the complexity of chunking. To
carry out a "monolithic" upload, one can simply put the entire content blob to
the provided URL:

```none
PUT /v2/<name>/blobs/uploads/<uuid>?digest=<digest>
Content-Length: <size of layer>
Content-Type: application/octet-stream

<Layer Binary Data>
```

The "digest" parameter must be included with the PUT request. Please see the
[_Completed Upload_](#completed-upload) section for details on the parameters
and expected responses.

##### Chunked Upload

To carry out an upload of a chunk, the client can specify a range header and
only include that part of the layer file:

```none
PATCH /v2/<name>/blobs/uploads/<uuid>
Content-Length: <size of chunk>
Content-Range: <start of range>-<end of range>
Content-Type: application/octet-stream

<Layer Chunk Binary Data>
```

There is no enforcement on layer chunk splits other than that the server must
receive them in order. The server may enforce a minimum chunk size. If the
server cannot accept the chunk, a `416 Requested Range Not Satisfiable`
response will be returned and will include a `Range` header indicating the
current status:

```none
416 Requested Range Not Satisfiable
Location: /v2/<name>/blobs/uploads/<uuid>
Range: 0-<last valid range>
Content-Length: 0
Docker-Upload-UUID: <uuid>
```

If this response is received, the client should resume from the "last valid
range" and upload the subsequent chunk. A 416 will be returned under the
following conditions:

- Invalid Content-Range header format
- Out of order chunk: the range of the next chunk must start immediately after
  the "last valid range" from the previous response.

When a chunk is accepted as part of the upload, a `202 Accepted` response will
be returned, including a `Range` header with the current upload status:

```none
202 Accepted
Location: /v2/<name>/blobs/uploads/<uuid>
Range: bytes=0-<offset>
Content-Length: 0
Docker-Upload-UUID: <uuid>
```

##### Completed Upload

For an upload to be considered complete, the client must submit a `PUT`
request on the upload endpoint with a digest parameter. If it is not provided,
the upload will not be considered complete. The format for the final chunk
will be as follows:

```none
PUT /v2/<name>/blobs/uploads/<uuid>?digest=<digest>
Content-Length: <size of chunk>
Content-Range: <start of range>-<end of range>
Content-Type: application/octet-stream

<Last Layer Chunk Binary Data>
```

Optionally, if all chunks have already been uploaded, a `PUT` request with a
`digest` parameter and zero-length body may be sent to complete and validate
the upload. Multiple "digest" parameters may be provided with different
digests. The server may verify none or all of them but _must_ notify the
client if the content is rejected.

When the last chunk is received and the layer has been validated, the client
will receive a `201 Created` response:

```none
201 Created
Location: /v2/<name>/blobs/<digest>
Content-Length: 0
Docker-Content-Digest: <digest>
```

The `Location` header will contain the registry URL to access the accepted
layer file. The `Docker-Content-Digest` header returns the canonical digest of
the uploaded blob which may differ from the provided digest. Most clients may
ignore the value but if it is used, the client should verify the value against
the uploaded blob data.

###### Digest Parameter

The "digest" parameter is designed as an opaque parameter to support
verification of a successful transfer. For example, an HTTP URI parameter
might be as follows:

```none
sha256:6c3c624b58dbbcd3c0dd82b4c53f04194d1247c6eebdaab7c610cf7d66709b3b
```

Given this parameter, the registry will verify that the provided content does
match this digest.

##### Canceling an Upload

An upload can be cancelled by issuing a DELETE request to the upload endpoint.
The format will be as follows:

```none
DELETE /v2/<name>/blobs/uploads/<uuid>
```

After this request is issued, the upload uuid will no longer be valid and the
registry server will dump all intermediate data. While uploads will time out
if not completed, clients should issue this request if they encounter a fatal
error but still have the ability to issue an http request.

##### Cross Repository Blob Mount

A blob may be mounted from another repository that the client has read access
to, removing the need to upload a blob already known to the registry. To issue
a blob mount instead of an upload, a POST request should be issued in the
following format:

```none
POST /v2/<name>/blobs/uploads/?mount=<digest>&from=<repository name>
Content-Length: 0
```

If the blob is successfully mounted, the client will receive a `201 Created`
response:

```none
201 Created
Location: /v2/<name>/blobs/<digest>
Content-Length: 0
Docker-Content-Digest: <digest>
```

The `Location` header will contain the registry URL to access the accepted
layer file. The `Docker-Content-Digest` header returns the canonical digest of
the uploaded blob which may differ from the provided digest. Most clients may
ignore the value but if it is used, the client should verify the value against
the uploaded blob data.

If a mount fails due to invalid repository or digest arguments, the registry
will fall back to the standard upload behavior and return a `202 Accepted` with
the upload URL in the `Location` header:

```none
202 Accepted
Location: /v2/<name>/blobs/uploads/<uuid>
Range: bytes=0-<offset>
Content-Length: 0
Docker-Upload-UUID: <uuid>
```

This behavior is consistent with older versions of the registry, which do not
recognize the repository mount query parameters.

{{< hint type=note >}}
A client may issue a HEAD request to check existence of a blob in a source
repository to distinguish between the registry not supporting blob mounts and
the blob not existing in the expected repository.
{{< /hint >}}

##### Errors

If an 502, 503 or 504 error is received, the client should assume that the
download can proceed due to a temporary condition, honoring the appropriate
retry mechanism. Other 5xx errors should be treated as terminal.

If there is a problem with the upload, a 4xx error will be returned indicating
the problem. After receiving a 4xx response (except 416, as called out above),
the upload will be considered failed and the client should take appropriate
action.

Note that the upload url will not be available forever. If the upload uuid is
unknown to the registry, a `404 Not Found` response will be returned and the
client must restart the upload process.

#### Deleting a Layer

A layer may be deleted from the registry via its `name` and `digest`. A
delete may be issued with the following request format:

```none
DELETE /v2/<name>/blobs/<digest>
```

If the blob exists and has been successfully deleted, the following response
will be issued:

```none
202 Accepted
Content-Length: None
```

If the blob had already been deleted or did not exist, a `404 Not Found`
response will be issued instead.

If a layer is deleted which is referenced by a manifest in the registry,
then the complete images will not be resolvable.

#### Pushing an Image Manifest

Once all of the layers for an image are uploaded, the client can upload the
image manifest. An image can be pushed using the following request format:

```none
PUT /v2/<name>/manifests/<reference>
Content-Type: <manifest media type>

{
    "name": <name>,
    "tag": <tag>,
    "fsLayers": [
        {
            "blobSum": <digest>
        },
        ...
    ],
    "history": <v1 images>,
    "signature": <JWS>,
    ...
}
```

The `name` and `reference` fields of the response body must match those
specified in the URL. The `reference` field may be a "tag" or a "digest". The
content type should match the type of the manifest being uploaded, as specified
in [Image Manifest Version 2, Schema 2](manifest-v2-2.md).

If there is a problem with pushing the manifest, a relevant 4xx response will
be returned with a JSON error message. Please see the
[_PUT Manifest_](#put-manifest) section for details on possible error codes that
may be returned.

If one or more layers are unknown to the registry, `BLOB_UNKNOWN` errors are
returned. The `detail` field of the error response will have a `digest` field
identifying the missing blob. An error is returned for each unknown blob. The
response format is as follows:

```none
{
    "errors": [
        {
            "code": "BLOB_UNKNOWN",
            "message": "blob unknown to registry",
            "detail": {
                "digest": <digest>
            }
        },
        ...
    ]
}
```

### Listing Repositories

Images are stored in collections, known as a _repository_, which is keyed by a
`name`, as seen throughout the API specification. A registry instance may
contain several repositories. The list of available repositories is made
available through the _catalog_.

The catalog for a given registry can be retrieved with the following request:

```none
GET /v2/_catalog
```

The response will be in the following format:

```none
200 OK
Content-Type: application/json

{
    "repositories": [
        <name>,
        ...
    ]
}
```

Note that the contents of the response are specific to the registry
implementation. Some registries may opt to provide a full catalog output,
limit it based on the user's access level or omit upstream results, if
providing mirroring functionality. Subsequently, the presence of a repository
in the catalog listing only means that the registry *may* provide access to
the repository at the time of the request. Conversely, a missing entry does
*not* mean that the registry does not have the repository. More succinctly,
the presence of a repository only guarantees that it is there but not that it
is _not_ there.

For registries with a large number of repositories, this response may be quite
large. If such a response is expected, one should use pagination. A registry
may also limit the amount of responses returned even if pagination was not
explicitly requested. In this case the `Link` header will be returned along
with the results, and subsequent results can be obtained by following the link
as if pagination had been initially requested.

For details of the `Link` header, please see the [_Pagination_](#pagination)
section.

#### Pagination

Paginated catalog results can be retrieved by adding an `n` parameter to the
request URL, declaring that the response should be limited to `n` results.
Starting a paginated flow begins as follows:

```none
GET /v2/_catalog?n=<integer>
```

The above specifies that a catalog response should be returned, from the start of
the result set, ordered lexically, limiting the number of results to `n`. The
response to such a request would look as follows:

```none
200 OK
Content-Type: application/json
Link: <<url>?n=<n from the request>&last=<last repository in response>>; rel="next"

{
    "repositories": [
        <name>,
        ...
    ]
}
```

The above includes the _first_ `n` entries from the result set. To get the
_next_ `n` entries, one can create a URL where the argument `last` has the
value from `repositories[len(repositories)-1]`. If there are indeed more
results, the URL for the next block is encoded in an
[RFC5988](https://tools.ietf.org/html/rfc5988) `Link` header, as a "next"
relation. The presence of the `Link` header communicates to the client that
the entire result set has not been returned and another request must be
issued. If the header is not present, the client can assume that all results
have been received.

> __NOTE:__ In the request template above, note that the brackets
> are required. For example, if the url is
> `http://example.com/v2/_catalog?n=20&last=b`, the value of the header would
> be `<http://example.com/v2/_catalog?n=20&last=b>; rel="next"`. Please see
> [RFC5988](https://tools.ietf.org/html/rfc5988) for details.

Compliant client implementations should always use the `Link` header
value when proceeding through results linearly. The client may construct URLs
to skip forward in the catalog.

To get the next result set, a client would issue the request as follows, using
the URL encoded in the described `Link` header:

```none
GET /v2/_catalog?n=<n from the request>&last=<last repository value from previous response>
```

The above process should then be repeated until the `Link` header is no longer
set.

The catalog result set is represented abstractly as a lexically sorted list,
where the position in that list can be specified by the query term `last`. The
entries in the response start _after_ the term specified by `last`, up to `n`
entries.

The behavior of `last` is quite simple when demonstrated with an example. Let
us say the registry has the following repositories:

```none
a
b
c
d
```

If the value of `n` is 2, _a_ and _b_ will be returned on the first response.
The `Link` header returned on the response will have `n` set to 2 and last set
to _b_:

```none
Link: <<url>?n=2&last=b>; rel="next"
```

The client can then issue the request with the above value from the `Link`
header, receiving the values _c_ and _d_. Note that `n` may change on the second
to last response or be fully omitted, depending on the server implementation.

### Listing Image Tags

It may be necessary to list all of the tags under a given repository. The tags
for an image repository can be retrieved with the following request:

    GET /v2/<name>/tags/list

The response will be in the following format:

    200 OK
    Content-Type: application/json

    {
        "name": <name>,
        "tags": [
            <tag>,
            ...
        ]
    }

For repositories with a large number of tags, this response may be quite
large. If such a response is expected, one should use the pagination.

#### Pagination

Paginated tag results can be retrieved by adding the appropriate parameters to
the request URL described above. The behavior of tag pagination is identical
to that specified for catalog pagination. We cover a simple flow to highlight
any differences.

Starting a paginated flow may begin as follows:

```none
GET /v2/<name>/tags/list?n=<integer>
```

The above specifies that a tags response should be returned, from the start of
the result set, ordered lexically, limiting the number of results to `n`. The
response to such a request would look as follows:

```none
200 OK
Content-Type: application/json
Link: <<url>?n=<n from the request>&last=<last tag value from previous response>>; rel="next"

{
    "name": <name>,
    "tags": [
        <tag>,
        ...
    ]
}
```

To get the next result set, a client would issue the request as follows, using
the value encoded in the [RFC5988](https://tools.ietf.org/html/rfc5988) `Link`
header:

```none
GET /v2/<name>/tags/list?n=<n from the request>&last=<last tag value from previous response>
```

The above process should then be repeated until the `Link` header is no longer
set in the response. The behavior of the `last` parameter, the provided
response result, lexical ordering and encoding of the `Link` header are
identical to that of catalog pagination.

### Deleting an Image

An image may be deleted from the registry via its `name` and `reference`. A
delete may be issued with the following request format:

    DELETE /v2/<name>/manifests/<reference>

For deletes, `reference` *must* be a digest or the delete will fail. If the
image exists and has been successfully deleted, the following response will be
issued:

    202 Accepted
    Content-Length: None

If the image had already been deleted or did not exist, a `404 Not Found`
response will be issued instead.

> **Note**  When deleting a manifest from a registry version 2.3 or later, the
> following header must be used when `HEAD` or `GET`-ing the manifest to obtain
> the correct digest to delete:

    Accept: application/vnd.docker.distribution.manifest.v2+json

> for more details, see: [compatibility](../about/compatibility.md#content-addressable-storage-cas)

## Detail

{{< hint type=note >}}
This section is still under construction. For the purposes of
implementation, if any details below differ from the described request flows
above, the section below should be corrected. When they match, this note
should be removed.
{{< /hint >}}

The behavior of the endpoints are covered in detail in this section, organized
by route and entity. All aspects of the request and responses are covered,
including headers, parameters and body formats. Examples of requests and their
corresponding responses, with success and failure, are enumerated.

{{< hint type=note >}}
The sections on endpoint detail are arranged with an example
request, a description of the request, followed by information about that
request.
{{< /hint >}}

A list of methods and URIs are covered in the table below:

|Method|Path|Entity|Description|
|------|----|------|-----------|
| GET | `/v2/` | Base | Check that the endpoint implements Docker Registry API V2. |
| GET | `/v2/<name>/tags/list` | Tags | Fetch the tags under the repository identified by `name`. |
| GET | `/v2/<name>/manifests/<reference>` | Manifest | Fetch the manifest identified by `name` and `reference` where `reference` can be a tag or digest. A `HEAD` request can also be issued to this endpoint to obtain resource information without receiving all data. |
| PUT | `/v2/<name>/manifests/<reference>` | Manifest | Put the manifest identified by `name` and `reference` where `reference` can be a tag or digest. |
| DELETE | `/v2/<name>/manifests/<reference>` | Manifest | Delete the manifest or tag identified by `name` and `reference` where `reference` can be a tag or digest. Note that a manifest can _only_ be deleted by digest. |
| GET | `/v2/<name>/blobs/<digest>` | Blob | Retrieve the blob from the registry identified by `digest`. A `HEAD` request can also be issued to this endpoint to obtain resource information without receiving all data. |
| DELETE | `/v2/<name>/blobs/<digest>` | Blob | Delete the blob identified by `name` and `digest` |
| POST | `/v2/<name>/blobs/uploads/` | Initiate Blob Upload | Initiate a resumable blob upload. If successful, an upload location will be provided to complete the upload. Optionally, if the `digest` parameter is present, the request body will be used to complete the upload in a single request. |
| GET | `/v2/<name>/blobs/uploads/<uuid>` | Blob Upload | Retrieve status of upload identified by `uuid`. The primary purpose of this endpoint is to resolve the current status of a resumable upload. |
| PATCH | `/v2/<name>/blobs/uploads/<uuid>` | Blob Upload | Upload a chunk of data for the specified upload. |
| PUT | `/v2/<name>/blobs/uploads/<uuid>` | Blob Upload | Complete the upload specified by `uuid`, optionally appending the body as the final chunk. |
| DELETE | `/v2/<name>/blobs/uploads/<uuid>` | Blob Upload | Cancel outstanding upload processes, releasing associated resources. If this is not called, the unfinished uploads will eventually timeout. |
| GET | `/v2/_catalog` | Catalog | Retrieve a sorted, json list of repositories available in the registry. |

The detail for each endpoint is covered in the following sections.

### Errors

The error codes encountered via the API are enumerated in the following table:

|Code|Message|Description|
|----|-------|-----------|
 `BLOB_UNKNOWN` | blob unknown to registry | This error may be returned when a blob is unknown to the registry in a specified repository. This can be returned with a standard get or if a manifest references an unknown layer during upload.
 `BLOB_UPLOAD_INVALID` | blob upload invalid | The blob upload encountered an error and can no longer proceed.
 `BLOB_UPLOAD_UNKNOWN` | blob upload unknown to registry | If a blob upload has been cancelled or was never started, this error code may be returned.
 `DIGEST_INVALID` | provided digest did not match uploaded content | When a blob is uploaded, the registry will check that the content matches the digest provided by the client. The error may include a detail structure with the key "digest", including the invalid digest string. This error may also be returned when a manifest includes an invalid layer digest.
 `MANIFEST_BLOB_UNKNOWN` | blob unknown to registry | This error may be returned when a manifest blob is  unknown to the registry.
 `MANIFEST_INVALID` | manifest invalid | During upload, manifests undergo several checks ensuring validity. If those checks fail, this error may be returned, unless a more specific error is included. The detail will contain information the failed validation.
 `MANIFEST_UNKNOWN` | manifest unknown | This error is returned when the manifest, identified by name and tag is unknown to the repository.
 `MANIFEST_UNVERIFIED` | manifest failed signature verification | During manifest upload, if the manifest fails signature verification, this error will be returned.
 `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation.
 `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry.
 `PAGINATION_NUMBER_INVALID` | invalid number of results requested | Returned when the "n" parameter (number of results to return) is not an integer, "n" is negative or "n" is bigger than the maximum allowed.
 `RANGE_INVALID` | invalid content range | When a layer is uploaded, the provided range is checked against the uploaded chunk. This error is returned if the range is out of order.
 `SIZE_INVALID` | provided length did not match content length | When a layer is uploaded, the provided size will be checked against the uploaded content. If they do not match, this error will be returned.
 `TAG_INVALID` | manifest tag did not match URI | During a manifest upload, if the tag in the manifest does not match the uri tag, this error will be returned.
 `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate.
 `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource.
 `UNSUPPORTED` | The operation is unsupported. | The operation was unsupported due to a missing implementation or invalid set of parameters.
### Base

Base V2 API route. Typically, this can be used for lightweight version checks and to validate registry authentication.

#### GET Base

Check that the endpoint implements Docker Registry API V2.

```none
GET /v2/
Host: <registry host>
Authorization: <scheme> <token>
```

The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
|`Authorization`|header|An RFC7235 compliant authorization header.|

###### On Success: OK

```none
200 OK
```

The API implements V2 protocol and is accessible.

###### On Failure: Not Found

```none
404 Not Found
```

The registry does not implement the V2 API.

###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |




### Tags

Retrieve information about tags.

#### GET Tags

Fetch the tags under the repository identified by `name`.
##### Tags

```none
GET /v2/<name>/tags/list
Host: <registry host>
Authorization: <scheme> <token>
```
Return all tags for the repository
The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
|`Authorization`|header|An RFC7235 compliant authorization header.|
|`name`|path|Name of the target repository.|

###### On Success: OK

```none
200 OK
Content-Length: <length>
Content-Type: application/json

{
    "name": <name>,
    "tags": [
        <tag>,
        ...
    ]
}
```

A list of tags for the named repository.

The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|


###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: No Such Repository Error

```none
404 Not Found
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The repository is not known to the registry.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |


###### On Failure: Access Denied

```none
403 Forbidden
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client does not have required access to the repository.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |



##### Tags Paginated

```none
GET /v2/<name>/tags/list?n=<integer>&last=<integer>
```
Return a portion of the tags for the specified repository.
The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`name`|path|Name of the target repository.|
|`n`|query|Limit the number of entries in each response. It not present, 100 entries will be returned.|
|`last`|query|Result set will include values lexically after last.|

###### On Success: OK

```none
200 OK
Content-Length: <length>
Link: <<url>?n=<last n value>&last=<last entry from response>>; rel="next"
Content-Type: application/json

{
    "name": <name>,
    "tags": [
        <tag>,
        ...
    ],
}
```

A list of tags for the named repository.

The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|
|`Link`|RFC5988 compliant rel='next' with URL to next result set, if available|


###### On Failure: Invalid pagination number

```none
400 Bad Request
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The received parameter n was invalid in some way, as described by the error code. The client should resolve the issue and retry the request.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `PAGINATION_NUMBER_INVALID` | invalid number of results requested | Returned when the "n" parameter (number of results to return) is not an integer, "n" is negative or "n" is bigger than the maximum allowed. |


###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: No Such Repository Error

```none
404 Not Found
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The repository is not known to the registry.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |


###### On Failure: Access Denied

```none
403 Forbidden
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client does not have required access to the repository.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |




### Manifest

Create, update, delete and retrieve manifests.

#### GET Manifest

Fetch the manifest identified by `name` and `reference` where `reference` can be a tag or digest. A `HEAD` request can also be issued to this endpoint to obtain resource information without receiving all data.

```none
GET /v2/<name>/manifests/<reference>
Host: <registry host>
Authorization: <scheme> <token>
```

The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
|`Authorization`|header|An RFC7235 compliant authorization header.|
|`name`|path|Name of the target repository.|
|`reference`|path|Tag or digest of the target manifest.|

###### On Success: OK

```none
200 OK
Docker-Content-Digest: <digest>
Content-Type: <media type of manifest>

{
    "name": <name>,
    "tag": <tag>,
    "fsLayers": [
        {
            "blobSum": "<digest>"
        },
        ...
    ],
    "history": <v1 images>,
    "signature": <JWS>
}
```

The manifest identified by `name` and `reference`. The contents can be used to identify and resolve resources required to run the specified image.

The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Docker-Content-Digest`|Digest of the targeted content for the request.|


###### On Failure: Bad Request

```none
400 Bad Request
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The name or reference was invalid.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation. |
| `TAG_INVALID` | manifest tag did not match URI | During a manifest upload, if the tag in the manifest does not match the uri tag, this error will be returned. |


###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: No Such Repository Error

```none
404 Not Found
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The repository is not known to the registry.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |


###### On Failure: Access Denied

```none
403 Forbidden
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client does not have required access to the repository.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |


#### PUT Manifest

Put the manifest identified by `name` and `reference` where `reference` can be a tag or digest.

```none
PUT /v2/<name>/manifests/<reference>
Host: <registry host>
Authorization: <scheme> <token>
Content-Type: <media type of manifest>

{
    "name": <name>,
    "tag": <tag>,
    "fsLayers": [
        {
            "blobSum": "<digest>"
        },
        ...
    ],
    "history": <v1 images>,
    "signature": <JWS>
}
```

The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
|`Authorization`|header|An RFC7235 compliant authorization header.|
|`name`|path|Name of the target repository.|
|`reference`|path|Tag or digest of the target manifest.|

###### On Success: Created

```none
201 Created
Location: <url>
Content-Length: 0
Docker-Content-Digest: <digest>
```

The manifest has been accepted by the registry and is stored under the specified `name` and `tag`.

The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Location`|The canonical location url of the uploaded manifest.|
|`Content-Length`|The `Content-Length` header must be zero and the body must be empty.|
|`Docker-Content-Digest`|Digest of the targeted content for the request.|


###### On Failure: Invalid Manifest

```none
400 Bad Request
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The received manifest was invalid in some way, as described by the error codes. The client should resolve the issue and retry the request.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation. |
| `TAG_INVALID` | manifest tag did not match URI | During a manifest upload, if the tag in the manifest does not match the uri tag, this error will be returned. |
| `MANIFEST_INVALID` | manifest invalid | During upload, manifests undergo several checks ensuring validity. If those checks fail, this error may be returned, unless a more specific error is included. The detail will contain information the failed validation. |
| `MANIFEST_UNVERIFIED` | manifest failed signature verification | During manifest upload, if the manifest fails signature verification, this error will be returned. |
| `BLOB_UNKNOWN` | blob unknown to registry | This error may be returned when a blob is unknown to the registry in a specified repository. This can be returned with a standard get or if a manifest references an unknown layer during upload. |


###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: No Such Repository Error

```none
404 Not Found
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The repository is not known to the registry.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |


###### On Failure: Access Denied

```none
403 Forbidden
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client does not have required access to the repository.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |


###### On Failure: Missing Layer(s)

```none
400 Bad Request
Content-Type: application/json

{
    "errors": [
        {
            "code": "BLOB_UNKNOWN",
            "message": "blob unknown to registry",
            "detail": {
                "digest": "<digest>"
            }
        },
        ...
    ]
}
```

One or more layers may be missing during a manifest upload. If so, the missing layers will be enumerated in the error response.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `BLOB_UNKNOWN` | blob unknown to registry | This error may be returned when a blob is unknown to the registry in a specified repository. This can be returned with a standard get or if a manifest references an unknown layer during upload. |


###### On Failure: Not allowed

```none
405 Method Not Allowed
```

Manifest put is not allowed because the registry is configured as a pull-through cache or for some other reason

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNSUPPORTED` | The operation is unsupported. | The operation was unsupported due to a missing implementation or invalid set of parameters. |


#### DELETE Manifest

Delete the manifest or tag identified by `name` and `reference` where `reference` can be a tag or digest. Note that a manifest can _only_ be deleted by digest.

```none
DELETE /v2/<name>/manifests/<reference>
Host: <registry host>
Authorization: <scheme> <token>
```

The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
|`Authorization`|header|An RFC7235 compliant authorization header.|
|`name`|path|Name of the target repository.|
|`reference`|path|Tag or digest of the target manifest.|

###### On Success: Accepted

```none
202 Accepted
```



###### On Failure: Invalid Name or Reference

```none
400 Bad Request
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The specified `name` or `reference` were invalid and the delete was unable to proceed.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation. |
| `TAG_INVALID` | manifest tag did not match URI | During a manifest upload, if the tag in the manifest does not match the uri tag, this error will be returned. |


###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: No Such Repository Error

```none
404 Not Found
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The repository is not known to the registry.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |


###### On Failure: Access Denied

```none
403 Forbidden
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client does not have required access to the repository.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |


###### On Failure: Unknown Manifest

```none
404 Not Found
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The specified `name` or `reference` are unknown to the registry and the delete was unable to proceed. Clients can assume the manifest or tag was already deleted if this response is returned.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |
| `MANIFEST_UNKNOWN` | manifest unknown | This error is returned when the manifest, identified by name and tag is unknown to the repository. |


###### On Failure: Not allowed

```none
405 Method Not Allowed
```

Manifest or tag delete is not allowed because the registry is configured as a pull-through cache or `delete` has been disabled.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNSUPPORTED` | The operation is unsupported. | The operation was unsupported due to a missing implementation or invalid set of parameters. |




### Blob

Operations on blobs identified by `name` and `digest`. Used to fetch or delete layers by digest.

#### GET Blob

Retrieve the blob from the registry identified by `digest`. A `HEAD` request can also be issued to this endpoint to obtain resource information without receiving all data.
##### Fetch Blob

```none
GET /v2/<name>/blobs/<digest>
Host: <registry host>
Authorization: <scheme> <token>
```

The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
|`Authorization`|header|An RFC7235 compliant authorization header.|
|`name`|path|Name of the target repository.|
|`digest`|path|Digest of desired blob.|

###### On Success: OK

```none
200 OK
Content-Length: <length>
Docker-Content-Digest: <digest>
Content-Type: application/octet-stream

<blob binary data>
```

The blob identified by `digest` is available. The blob content will be present in the body of the request.

The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Content-Length`|The length of the requested blob content.|
|`Docker-Content-Digest`|Digest of the targeted content for the request.|

###### On Success: Temporary Redirect

```none
307 Temporary Redirect
Location: <blob location>
Docker-Content-Digest: <digest>
```

The blob identified by `digest` is available at the provided location.

The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Location`|The location where the layer should be accessible.|
|`Docker-Content-Digest`|Digest of the targeted content for the request.|


###### On Failure: Bad Request

```none
400 Bad Request
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

There was a problem with the request that needs to be addressed by the client, such as an invalid `name` or `tag`.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation. |
| `DIGEST_INVALID` | provided digest did not match uploaded content | When a blob is uploaded, the registry will check that the content matches the digest provided by the client. The error may include a detail structure with the key "digest", including the invalid digest string. This error may also be returned when a manifest includes an invalid layer digest. |


###### On Failure: Not Found

```none
404 Not Found
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The blob, identified by `name` and `digest`, is unknown to the registry.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |
| `BLOB_UNKNOWN` | blob unknown to registry | This error may be returned when a blob is unknown to the registry in a specified repository. This can be returned with a standard get or if a manifest references an unknown layer during upload. |


###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: No Such Repository Error

```none
404 Not Found
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The repository is not known to the registry.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |


###### On Failure: Access Denied

```none
403 Forbidden
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client does not have required access to the repository.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |



##### Fetch Blob Part

```none
GET /v2/<name>/blobs/<digest>
Host: <registry host>
Authorization: <scheme> <token>
Range: bytes=<start>-<end>
```
This endpoint may also support RFC7233 compliant range requests. Support can be detected by issuing a HEAD request. If the header `Accept-Range: bytes` is returned, range requests can be used to fetch partial content.
The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
|`Authorization`|header|An RFC7235 compliant authorization header.|
|`Range`|header|HTTP Range header specifying blob chunk.|
|`name`|path|Name of the target repository.|
|`digest`|path|Digest of desired blob.|

###### On Success: Partial Content

```none
206 Partial Content
Content-Length: <length>
Content-Range: bytes <start>-<end>/<size>
Content-Type: application/octet-stream

<blob binary data>
```

The blob identified by `digest` is available. The specified chunk of blob content will be present in the body of the request.

The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Content-Length`|The length of the requested blob chunk.|
|`Content-Range`|Content range of blob chunk.|


###### On Failure: Bad Request

```none
400 Bad Request
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

There was a problem with the request that needs to be addressed by the client, such as an invalid `name` or `tag`.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation. |
| `DIGEST_INVALID` | provided digest did not match uploaded content | When a blob is uploaded, the registry will check that the content matches the digest provided by the client. The error may include a detail structure with the key "digest", including the invalid digest string. This error may also be returned when a manifest includes an invalid layer digest. |


###### On Failure: Not Found

```none
404 Not Found
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```



The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |
| `BLOB_UNKNOWN` | blob unknown to registry | This error may be returned when a blob is unknown to the registry in a specified repository. This can be returned with a standard get or if a manifest references an unknown layer during upload. |


###### On Failure: Requested Range Not Satisfiable

```none
416 Requested Range Not Satisfiable
```

The range specification cannot be satisfied for the requested content. This can happen when the range is not formatted correctly or if the range is outside of the valid size of the content.

###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: No Such Repository Error

```none
404 Not Found
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The repository is not known to the registry.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |


###### On Failure: Access Denied

```none
403 Forbidden
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client does not have required access to the repository.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |


#### DELETE Blob

Delete the blob identified by `name` and `digest`

```none
DELETE /v2/<name>/blobs/<digest>
Host: <registry host>
Authorization: <scheme> <token>
```

The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
|`Authorization`|header|An RFC7235 compliant authorization header.|
|`name`|path|Name of the target repository.|
|`digest`|path|Digest of desired blob.|

###### On Success: Accepted

```none
202 Accepted
Content-Length: 0
Docker-Content-Digest: <digest>
```



The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Content-Length`|0|
|`Docker-Content-Digest`|Digest of the targeted content for the request.|


###### On Failure: Invalid Name or Digest

```none
400 Bad Request
```



The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DIGEST_INVALID` | provided digest did not match uploaded content | When a blob is uploaded, the registry will check that the content matches the digest provided by the client. The error may include a detail structure with the key "digest", including the invalid digest string. This error may also be returned when a manifest includes an invalid layer digest. |
| `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation. |


###### On Failure: Not Found

```none
404 Not Found
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The blob, identified by `name` and `digest`, is unknown to the registry.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |
| `BLOB_UNKNOWN` | blob unknown to registry | This error may be returned when a blob is unknown to the registry in a specified repository. This can be returned with a standard get or if a manifest references an unknown layer during upload. |


###### On Failure: Method Not Allowed

```none
405 Method Not Allowed
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

Blob delete is not allowed because the registry is configured as a pull-through cache or `delete` has been disabled

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNSUPPORTED` | The operation is unsupported. | The operation was unsupported due to a missing implementation or invalid set of parameters. |


###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: No Such Repository Error

```none
404 Not Found
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The repository is not known to the registry.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |


###### On Failure: Access Denied

```none
403 Forbidden
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client does not have required access to the repository.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |




### Initiate Blob Upload

Initiate a blob upload. This endpoint can be used to create resumable uploads or monolithic uploads.

#### POST Initiate Blob Upload

Initiate a resumable blob upload. If successful, an upload location will be provided to complete the upload. Optionally, if the `digest` parameter is present, the request body will be used to complete the upload in a single request.
##### Initiate Monolithic Blob Upload

```none
POST /v2/<name>/blobs/uploads/?digest=<digest>
Host: <registry host>
Authorization: <scheme> <token>
Content-Length: <length of blob>
Content-Type: application/octet-stream

<binary data>
```
Upload a blob identified by the `digest` parameter in single request. This upload will not be resumable unless a recoverable error is returned.
The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
|`Authorization`|header|An RFC7235 compliant authorization header.|
|`Content-Length`|header||
|`name`|path|Name of the target repository.|
|`digest`|query|Digest of uploaded blob. If present, the upload will be completed, in a single request, with contents of the request body as the resulting blob.|

###### On Success: Created

```none
201 Created
Location: <blob location>
Content-Length: 0
Docker-Upload-UUID: <uuid>
```

The blob has been created in the registry and is available at the provided location.

The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Location`||
|`Content-Length`|The `Content-Length` header must be zero and the body must be empty.|
|`Docker-Upload-UUID`|Identifies the docker upload uuid for the current request.|


###### On Failure: Invalid Name or Digest

```none
400 Bad Request
```



The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DIGEST_INVALID` | provided digest did not match uploaded content | When a blob is uploaded, the registry will check that the content matches the digest provided by the client. The error may include a detail structure with the key "digest", including the invalid digest string. This error may also be returned when a manifest includes an invalid layer digest. |
| `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation. |


###### On Failure: Not allowed

```none
405 Method Not Allowed
```

Blob upload is not allowed because the registry is configured as a pull-through cache or for some other reason

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNSUPPORTED` | The operation is unsupported. | The operation was unsupported due to a missing implementation or invalid set of parameters. |


###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: No Such Repository Error

```none
404 Not Found
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The repository is not known to the registry.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |


###### On Failure: Access Denied

```none
403 Forbidden
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client does not have required access to the repository.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |



##### Initiate Resumable Blob Upload

```none
POST /v2/<name>/blobs/uploads/
Host: <registry host>
Authorization: <scheme> <token>
Content-Length: 0
```
Initiate a resumable blob upload with an empty request body.
The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
|`Authorization`|header|An RFC7235 compliant authorization header.|
|`Content-Length`|header|The `Content-Length` header must be zero and the body must be empty.|
|`name`|path|Name of the target repository.|

###### On Success: Accepted

```none
202 Accepted
Location: /v2/<name>/blobs/uploads/<uuid>
Range: 0-<offset>
Content-Length: 0
Docker-Upload-UUID: <uuid>
```

The upload has been created. The `Location` header must be used to complete the upload. The response should be identical to a `GET` request on the contents of the returned `Location` header.

The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Location`|The location of the created upload. Clients should use the contents verbatim to complete the upload, adding parameters where required.|
|`Range`|Range header indicating the progress of the upload. When starting an upload, it will return an empty range, since no content has been received.|
|`Content-Length`|The `Content-Length` header must be zero and the body must be empty.|
|`Docker-Upload-UUID`|Identifies the docker upload uuid for the current request.|


###### On Failure: Invalid Name or Digest

```none
400 Bad Request
```



The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DIGEST_INVALID` | provided digest did not match uploaded content | When a blob is uploaded, the registry will check that the content matches the digest provided by the client. The error may include a detail structure with the key "digest", including the invalid digest string. This error may also be returned when a manifest includes an invalid layer digest. |
| `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation. |


###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: No Such Repository Error

```none
404 Not Found
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The repository is not known to the registry.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |


###### On Failure: Access Denied

```none
403 Forbidden
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client does not have required access to the repository.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |



##### Mount Blob

```none
POST /v2/<name>/blobs/uploads/?mount=<digest>&from=<repository name>
Host: <registry host>
Authorization: <scheme> <token>
Content-Length: 0
```
Mount a blob identified by the `mount` parameter from another repository.
The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
|`Authorization`|header|An RFC7235 compliant authorization header.|
|`Content-Length`|header|The `Content-Length` header must be zero and the body must be empty.|
|`name`|path|Name of the target repository.|
|`mount`|query|Digest of blob to mount from the source repository.|
|`from`|query|Name of the source repository.|

###### On Success: Created

```none
201 Created
Location: <blob location>
Content-Length: 0
Docker-Upload-UUID: <uuid>
```

The blob has been mounted in the repository and is available at the provided location.

The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Location`||
|`Content-Length`|The `Content-Length` header must be zero and the body must be empty.|
|`Docker-Upload-UUID`|Identifies the docker upload uuid for the current request.|


###### On Failure: Invalid Name or Digest

```none
400 Bad Request
```



The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DIGEST_INVALID` | provided digest did not match uploaded content | When a blob is uploaded, the registry will check that the content matches the digest provided by the client. The error may include a detail structure with the key "digest", including the invalid digest string. This error may also be returned when a manifest includes an invalid layer digest. |
| `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation. |


###### On Failure: Not allowed

```none
405 Method Not Allowed
```

Blob mount is not allowed because the registry is configured as a pull-through cache or for some other reason

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNSUPPORTED` | The operation is unsupported. | The operation was unsupported due to a missing implementation or invalid set of parameters. |


###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: No Such Repository Error

```none
404 Not Found
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The repository is not known to the registry.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |


###### On Failure: Access Denied

```none
403 Forbidden
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client does not have required access to the repository.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |




### Blob Upload

Interact with blob uploads. Clients should never assemble URLs for this endpoint and should only take it through the `Location` header on related API requests. The `Location` header and its parameters should be preserved by clients, using the latest value returned via upload related API calls.

#### GET Blob Upload

Retrieve status of upload identified by `uuid`. The primary purpose of this endpoint is to resolve the current status of a resumable upload.

```none
GET /v2/<name>/blobs/uploads/<uuid>
Host: <registry host>
Authorization: <scheme> <token>
```
Retrieve the progress of the current upload, as reported by the `Range` header.
The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
|`Authorization`|header|An RFC7235 compliant authorization header.|
|`name`|path|Name of the target repository.|
|`uuid`|path|A uuid identifying the upload. This field can accept characters that match `[a-zA-Z0-9-_.=]+`.|

###### On Success: Upload Progress

```none
204 No Content
Range: 0-<offset>
Content-Length: 0
Docker-Upload-UUID: <uuid>
```

The upload is known and in progress. The last received offset is available in the `Range` header.

The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Range`|Range indicating the current progress of the upload.|
|`Content-Length`|The `Content-Length` header must be zero and the body must be empty.|
|`Docker-Upload-UUID`|Identifies the docker upload uuid for the current request.|


###### On Failure: Bad Request

```none
400 Bad Request
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

There was an error processing the upload and it must be restarted.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DIGEST_INVALID` | provided digest did not match uploaded content | When a blob is uploaded, the registry will check that the content matches the digest provided by the client. The error may include a detail structure with the key "digest", including the invalid digest string. This error may also be returned when a manifest includes an invalid layer digest. |
| `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation. |
| `BLOB_UPLOAD_INVALID` | blob upload invalid | The blob upload encountered an error and can no longer proceed. |


###### On Failure: Not Found

```none
404 Not Found
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The upload is unknown to the registry. The upload must be restarted.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `BLOB_UPLOAD_UNKNOWN` | blob upload unknown to registry | If a blob upload has been cancelled or was never started, this error code may be returned. |


###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: No Such Repository Error

```none
404 Not Found
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The repository is not known to the registry.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |


###### On Failure: Access Denied

```none
403 Forbidden
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client does not have required access to the repository.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |


#### PATCH Blob Upload

Upload a chunk of data for the specified upload.
##### Stream upload

```none
PATCH /v2/<name>/blobs/uploads/<uuid>
Host: <registry host>
Authorization: <scheme> <token>
Content-Type: application/octet-stream

<binary data>
```
Upload a stream of data to upload without completing the upload.
The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
|`Authorization`|header|An RFC7235 compliant authorization header.|
|`name`|path|Name of the target repository.|
|`uuid`|path|A uuid identifying the upload. This field can accept characters that match `[a-zA-Z0-9-_.=]+`.|

###### On Success: Data Accepted

```none
202 Accepted
Location: /v2/<name>/blobs/uploads/<uuid>
Range: 0-<offset>
Content-Length: 0
Docker-Upload-UUID: <uuid>
```

The stream of data has been accepted and the current progress is available in the range header. The updated upload location is available in the `Location` header.

The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Location`|The location of the upload. Clients should assume this changes after each request. Clients should use the contents verbatim to complete the upload, adding parameters where required.|
|`Range`|Range indicating the current progress of the upload.|
|`Content-Length`|The `Content-Length` header must be zero and the body must be empty.|
|`Docker-Upload-UUID`|Identifies the docker upload uuid for the current request.|


###### On Failure: Bad Request

```none
400 Bad Request
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

There was an error processing the upload and it must be restarted.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DIGEST_INVALID` | provided digest did not match uploaded content | When a blob is uploaded, the registry will check that the content matches the digest provided by the client. The error may include a detail structure with the key "digest", including the invalid digest string. This error may also be returned when a manifest includes an invalid layer digest. |
| `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation. |
| `BLOB_UPLOAD_INVALID` | blob upload invalid | The blob upload encountered an error and can no longer proceed. |


###### On Failure: Not Found

```none
404 Not Found
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The upload is unknown to the registry. The upload must be restarted.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `BLOB_UPLOAD_UNKNOWN` | blob upload unknown to registry | If a blob upload has been cancelled or was never started, this error code may be returned. |


###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: No Such Repository Error

```none
404 Not Found
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The repository is not known to the registry.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |


###### On Failure: Access Denied

```none
403 Forbidden
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client does not have required access to the repository.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |



##### Chunked upload

```none
PATCH /v2/<name>/blobs/uploads/<uuid>
Host: <registry host>
Authorization: <scheme> <token>
Content-Range: <start of range>-<end of range, inclusive>
Content-Length: <length of chunk>
Content-Type: application/octet-stream

<binary chunk>
```
Upload a chunk of data to specified upload without completing the upload. The data will be uploaded to the specified Content Range.
The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
|`Authorization`|header|An RFC7235 compliant authorization header.|
|`Content-Range`|header|Range of bytes identifying the desired block of content represented by the body. Start must the end offset retrieved via status check plus one. Note that this is a non-standard use of the `Content-Range` header.|
|`Content-Length`|header|Length of the chunk being uploaded, corresponding the length of the request body.|
|`name`|path|Name of the target repository.|
|`uuid`|path|A uuid identifying the upload. This field can accept characters that match `[a-zA-Z0-9-_.=]+`.|

###### On Success: Chunk Accepted

```none
202 Accepted
Location: /v2/<name>/blobs/uploads/<uuid>
Range: 0-<offset>
Content-Length: 0
Docker-Upload-UUID: <uuid>
```

The chunk of data has been accepted and the current progress is available in the range header. The updated upload location is available in the `Location` header.

The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Location`|The location of the upload. Clients should assume this changes after each request. Clients should use the contents verbatim to complete the upload, adding parameters where required.|
|`Range`|Range indicating the current progress of the upload.|
|`Content-Length`|The `Content-Length` header must be zero and the body must be empty.|
|`Docker-Upload-UUID`|Identifies the docker upload uuid for the current request.|


###### On Failure: Bad Request

```none
400 Bad Request
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

There was an error processing the upload and it must be restarted.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DIGEST_INVALID` | provided digest did not match uploaded content | When a blob is uploaded, the registry will check that the content matches the digest provided by the client. The error may include a detail structure with the key "digest", including the invalid digest string. This error may also be returned when a manifest includes an invalid layer digest. |
| `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation. |
| `BLOB_UPLOAD_INVALID` | blob upload invalid | The blob upload encountered an error and can no longer proceed. |


###### On Failure: Not Found

```none
404 Not Found
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The upload is unknown to the registry. The upload must be restarted.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `BLOB_UPLOAD_UNKNOWN` | blob upload unknown to registry | If a blob upload has been cancelled or was never started, this error code may be returned. |


###### On Failure: Requested Range Not Satisfiable

```none
416 Requested Range Not Satisfiable
```

The `Content-Range` specification cannot be accepted, either because it does not overlap with the current progress or it is invalid.

###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: No Such Repository Error

```none
404 Not Found
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The repository is not known to the registry.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |


###### On Failure: Access Denied

```none
403 Forbidden
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client does not have required access to the repository.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |


#### PUT Blob Upload

Complete the upload specified by `uuid`, optionally appending the body as the final chunk.

```none
PUT /v2/<name>/blobs/uploads/<uuid>?digest=<digest>
Host: <registry host>
Authorization: <scheme> <token>
Content-Length: <length of data>
Content-Type: application/octet-stream

<binary data>
```
Complete the upload, providing all the data in the body, if necessary. A request without a body will just complete the upload with previously uploaded content.
The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
|`Authorization`|header|An RFC7235 compliant authorization header.|
|`Content-Length`|header|Length of the data being uploaded, corresponding to the length of the request body. May be zero if no data is provided.|
|`name`|path|Name of the target repository.|
|`uuid`|path|A uuid identifying the upload. This field can accept characters that match `[a-zA-Z0-9-_.=]+`.|
|`digest`|query|Digest of uploaded blob.|

###### On Success: Upload Complete

```none
201 Created
Location: <blob location>
Content-Range: <start of range>-<end of range, inclusive>
Content-Length: 0
Docker-Content-Digest: <digest>
```

The upload has been completed and accepted by the registry. The canonical location will be available in the `Location` header.

The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Location`|The canonical location of the blob for retrieval|
|`Content-Range`|Range of bytes identifying the desired block of content represented by the body. Start must match the end of offset retrieved via status check. Note that this is a non-standard use of the `Content-Range` header.|
|`Content-Length`|The `Content-Length` header must be zero and the body must be empty.|
|`Docker-Content-Digest`|Digest of the targeted content for the request.|


###### On Failure: Bad Request

```none
400 Bad Request
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

There was an error processing the upload and it must be restarted.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DIGEST_INVALID` | provided digest did not match uploaded content | When a blob is uploaded, the registry will check that the content matches the digest provided by the client. The error may include a detail structure with the key "digest", including the invalid digest string. This error may also be returned when a manifest includes an invalid layer digest. |
| `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation. |
| `BLOB_UPLOAD_INVALID` | blob upload invalid | The blob upload encountered an error and can no longer proceed. |
| `UNSUPPORTED` | The operation is unsupported. | The operation was unsupported due to a missing implementation or invalid set of parameters. |


###### On Failure: Not Found

```none
404 Not Found
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The upload is unknown to the registry. The upload must be restarted.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `BLOB_UPLOAD_UNKNOWN` | blob upload unknown to registry | If a blob upload has been cancelled or was never started, this error code may be returned. |


###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: No Such Repository Error

```none
404 Not Found
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The repository is not known to the registry.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |


###### On Failure: Access Denied

```none
403 Forbidden
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client does not have required access to the repository.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |


#### DELETE Blob Upload

Cancel outstanding upload processes, releasing associated resources. If this is not called, the unfinished uploads will eventually timeout.

```none
DELETE /v2/<name>/blobs/uploads/<uuid>
Host: <registry host>
Authorization: <scheme> <token>
Content-Length: 0
```
Cancel the upload specified by `uuid`.
The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`Host`|header|Standard HTTP Host Header. Should be set to the registry host.|
|`Authorization`|header|An RFC7235 compliant authorization header.|
|`Content-Length`|header|The `Content-Length` header must be zero and the body must be empty.|
|`name`|path|Name of the target repository.|
|`uuid`|path|A uuid identifying the upload. This field can accept characters that match `[a-zA-Z0-9-_.=]+`.|

###### On Success: Upload Deleted

```none
204 No Content
Content-Length: 0
```

The upload has been successfully deleted.

The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Content-Length`|The `Content-Length` header must be zero and the body must be empty.|


###### On Failure: Bad Request

```none
400 Bad Request
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

An error was encountered processing the delete. The client may ignore this error.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_INVALID` | invalid repository name | Invalid repository name encountered either during manifest validation or any API operation. |
| `BLOB_UPLOAD_INVALID` | blob upload invalid | The blob upload encountered an error and can no longer proceed. |


###### On Failure: Not Found

```none
404 Not Found
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The upload is unknown to the registry. The client may ignore this error and assume the upload has been deleted.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `BLOB_UPLOAD_UNKNOWN` | blob upload unknown to registry | If a blob upload has been cancelled or was never started, this error code may be returned. |


###### On Failure: Authentication Required

```none
401 Unauthorized
WWW-Authenticate: <scheme> realm="<realm>", ..."
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client is not authenticated.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`WWW-Authenticate`|An RFC7235 compliant authentication challenge header.|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `UNAUTHORIZED` | authentication required | The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate. |


###### On Failure: No Such Repository Error

```none
404 Not Found
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The repository is not known to the registry.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `NAME_UNKNOWN` | repository name not known to registry | This is returned if the name used during an operation is unknown to the registry. |


###### On Failure: Access Denied

```none
403 Forbidden
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client does not have required access to the repository.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `DENIED` | requested access to the resource is denied | The access controller denied access for the operation on a resource. |


###### On Failure: Too Many Requests

```none
429 Too Many Requests
Content-Length: <length>
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The client made too many requests within a time interval.

The following headers will be returned on the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `TOOMANYREQUESTS` | too many requests | Returned when a client attempts to contact a service too many times |




### Catalog

List a set of available repositories in the local registry cluster. Does not provide any indication of what may be available upstream. Applications can only determine if a repository is available but not if it is not available.

#### GET Catalog

Retrieve a sorted, json list of repositories available in the registry.
##### Catalog Fetch

```none
GET /v2/_catalog
```
Request an unabridged list of repositories available.  The implementation may impose a maximum limit and return a partial set with pagination links.
###### On Success: OK

```none
200 OK
Content-Length: <length>
Content-Type: application/json

{
	"repositories": [
		<name>,
		...
	],
}
```

Returns the unabridged list of repositories as a json response.

The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|



##### Catalog Fetch Paginated

```none
GET /v2/_catalog?n=<integer>&last=<integer>
```
Return the specified portion of repositories.
The following parameters should be specified on the request:

|Name|Kind|Description|
|----|----|-----------|
|`n`|query|Limit the number of entries in each response. It not present, 100 entries will be returned.|
|`last`|query|Result set will include values lexically after last.|

###### On Success: OK

```none
200 OK
Content-Length: <length>
Link: <<url>?n=<last n value>&last=<last entry from response>>; rel="next"
Content-Type: application/json

{
	"repositories": [
		<name>,
		...
	],
	"next": "<url>?last=<name>&n=<last value of n>"
}
```



The following headers will be returned with the response:

|Name|Description|
|----|-----------|
|`Content-Length`|Length of the JSON response body.|
|`Link`|RFC5988 compliant rel='next' with URL to next result set, if available|


###### On Failure: Invalid pagination number

```none
400 Bad Request
Content-Type: application/json

{
	"errors": [
	    {
            "code": <error code>,
            "message": "<error message>",
            "detail": ...
        },
        ...
    ]
}
```

The received parameter n was invalid in some way, as described by the error code. The client should resolve the issue and retry the request.

The error codes that may be included in the response body are enumerated below:

|Code|Message|Description|
|----|-------|-----------|
| `PAGINATION_NUMBER_INVALID` | invalid number of results requested | Returned when the "n" parameter (number of results to return) is not an integer, "n" is negative or "n" is bigger than the maximum allowed. |

---

--- METRICS ---
- Files Extracted: 145
- Estimated Token Budget: ~157829 tokens
- Canonical Reference: https://codewiki.google/github.com/docker/DISTRIBUTION
