This is a follow-up to 0e73168b7e
This repository is not yet a module (i.e., does not have a `go.mod`). This
is not problematic when building the code in GOPATH or "vendor" mode, but
when using the code as a module-dependency (in module-mode), different semantics
are applied since Go1.21, which switches Go _language versions_ on a per-module,
per-package, or even per-file base.
A condensed summary of that logic [is as follows][1]:
- For modules that have a go.mod containing a go version directive; that
version is considered a minimum _required_ version (starting with the
go1.19.13 and go1.20.8 patch releases: before those, it was only a
recommendation).
- For dependencies that don't have a go.mod (not a module), go language
version go1.16 is assumed.
- Likewise, for modules that have a go.mod, but the file does not have a
go version directive, go language version go1.16 is assumed.
- If a go.work file is present, but does not have a go version directive,
language version go1.17 is assumed.
When switching language versions, Go _downgrades_ the language version,
which means that language features (such as generics, and `any`) are not
available, and compilation fails. For example:
# github.com/docker/cli/cli/context/store
/go/pkg/mod/github.com/docker/cli@v25.0.0-beta.2+incompatible/cli/context/store/storeconfig.go:6:24: predeclared any requires go1.18 or later (-lang was set to go1.16; check go.mod)
/go/pkg/mod/github.com/docker/cli@v25.0.0-beta.2+incompatible/cli/context/store/store.go:74:12: predeclared any requires go1.18 or later (-lang was set to go1.16; check go.mod)
Note that these fallbacks are per-module, per-package, and can even be
per-file, so _(indirect) dependencies_ can still use modern language
features, as long as their respective go.mod has a version specified.
Unfortunately, these failures do not occur when building locally (using
vendor / GOPATH mode), but will affect consumers of the module.
Obviously, this situation is not ideal, and the ultimate solution is to
move to go modules (add a go.mod), but this comes with a non-insignificant
risk in other areas (due to our complex dependency tree).
We can revert to using go1.16 language features only, but this may be
limiting, and may still be problematic when (e.g.) matching signatures
of dependencies.
There is an escape hatch: adding a `//go:build` directive to files that
make use of go language features. From the [go toolchain docs][2]:
> The go line for each module sets the language version the compiler enforces
> when compiling packages in that module. The language version can be changed
> on a per-file basis by using a build constraint.
>
> For example, a module containing code that uses the Go 1.21 language version
> should have a `go.mod` file with a go line such as `go 1.21` or `go 1.21.3`.
> If a specific source file should be compiled only when using a newer Go
> toolchain, adding `//go:build go1.22` to that source file both ensures that
> only Go 1.22 and newer toolchains will compile the file and also changes
> the language version in that file to Go 1.22.
This patch adds `//go:build` directives to those files using recent additions
to the language. It's currently using go1.19 as version to match the version
in our "vendor.mod", but we can consider being more permissive ("any" requires
go1.18 or up), or more "optimistic" (force go1.21, which is the version we
currently use to build).
For completeness sake, note that any file _without_ a `//go:build` directive
will continue to use go1.16 language version when used as a module.
[1]: 58c28ba286/src/cmd/go/internal/gover/version.go (L9-L56)
[2]; https://go.dev/doc/toolchain#:~:text=The%20go%20line%20for,file%20to%20Go%201.22
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 70216b662d)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This field was deprecated in 15535d4594, which
is part of docker 23.0, so users should have had a chance to migrate.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
These were deprecated in de6020a240, which
is part of docker 23.0, so users should have had a chance to migrate.
This removes IsErrContextDoesNotExist() and IsErrTLSDataDoesNotExist()
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
if a context is set (e.g. through DOCKER_CONTEXT or the CLI config file), but
wasn't found, then a "stub" context is added, including an error message that
the context doesn't exist.
DOCKER_CONTEXT=nosuchcontext docker context ls
NAME DESCRIPTION DOCKER ENDPOINT ERROR
default Current DOCKER_HOST based configuration unix:///var/run/docker.sock
nosuchcontext * context "nosuchcontext": context not found: …
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Looks like the linter uses an explicit -lang, which (for go1.19)
results in some additional formatting for octal values.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
The existing `remove()` was unused, and using that as name makes it more
consistent with the metadata-store. Also renaming `removeAllEndpointData`
to just `removeEndpoint`, as it's part of the TLS-store, which should already
make it clear it's about (TLS)data.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
There's no reason to stop listing contexts if a context does not exist
while iterating over the directories,
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Go conventions are for interfaces to be defined on the receiver side,
and for producers to return concrete types. This patch changes the
constructor to return a concrete type.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
The package defined various special errors; these errors existed for two reasons;
- being able to distinguish "not found" errors from other errors (as "not found"
errors can be ignored in various cases).
- to be able to update the context _name_ in the error message after the error
was created. This was needed in cases where the name was not available at the
location where the error was produced (e.g. only the "id" was present), and
the helpers to detect "not found" errors did not support wrapped errors (so
wrapping the error with a "name" could break logic); a `setContextName` interface
and corresponding `patchErrContextName()` utility was created for this (which
was a "creative", but not very standard approach).
This patch:
- Removes the special error-types, replacing them with errdefs definitions (which
is a more common approach in our code-base to detect error types / classes).
- Removes the internal utilities for error-handling, and deprecates the exported
utilities (to allow external consumers to adjust their code).
- Some errors have been enriched with detailed information (which may be useful
for debugging / problem solving).
- Note that in some cases, `patchErrContextName()` was called, but the code
producing the error would never return a `setContextName` error, so would
never update the error message.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This test was depending on the fact that contextDir's are a string,
and for the test is was using the context _name_ as a pseudo-ID.
This patch updates the test to be more explicit where ID's and where
names are used.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This allows callers to just pass the name, and handle the conversion to ID and
path internally. This also fixes a test which incorrectly used "names" as
pseudo-IDs.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Older versions of Go do not format these comments, so we can already
reformat them ahead of time to prevent gofmt linting failing once
we update to Go 1.19 or up.
Result of:
gofmt -s -w $(find . -type f -name '*.go' | grep -v "/vendor/")
With some manual adjusting.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This was there for historic reasons (I think `goimports` expected this,
and we used to have a linter that wanted it), but it's not needed, so
let's remove it (to make my IDE less complaining about unneeded aliases)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
> Legacy PEM encryption as specified in RFC 1423 is insecure by design. Since
> it does not authenticate the ciphertext, it is vulnerable to padding oracle
> attacks that can let an attacker recover the plaintext
From https://go-review.googlesource.com/c/go/+/264159
> It's unfortunate that we don't implement PKCS#8 encryption so we can't
> recommend an alternative but PEM encryption is so broken that it's worth
> deprecating outright.
This feature allowed using an encrypted private key with a supplied password,
but did not provide additional security as the encryption is known to be broken,
and the key is sitting next to the password in the filesystem. Users are recommended
to decrypt the private key, and store it un-encrypted to continue using it.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
> Legacy PEM encryption as specified in RFC 1423 is insecure by design. Since
> it does not authenticate the ciphertext, it is vulnerable to padding oracle
> attacks that can let an attacker recover the plaintext
From https://go-review.googlesource.com/c/go/+/264159
> It's unfortunate that we don't implement PKCS#8 encryption so we can't
> recommend an alternative but PEM encryption is so broken that it's worth
> deprecating outright.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
From https://go-review.googlesource.com/c/go/+/264159
> It's unfortunate that we don't implement PKCS#8 encryption so we can't
> recommend an alternative but PEM encryption is so broken that it's worth
> deprecating outright.
When linting on Go 1.16:
cli/context/docker/load.go:69:6: SA1019: x509.IsEncryptedPEMBlock is deprecated: Legacy PEM encryption as specified in RFC 1423 is insecure by design. Since it does not authenticate the ciphertext, it is vulnerable to padding oracle attacks that can let an attacker recover the plaintext. (staticcheck)
if x509.IsEncryptedPEMBlock(pemBlock) {
^
cli/context/docker/load.go:70:20: SA1019: x509.DecryptPEMBlock is deprecated: Legacy PEM encryption as specified in RFC 1423 is insecure by design. Since it does not authenticate the ciphertext, it is vulnerable to padding oracle attacks that can let an attacker recover the plaintext. (staticcheck)
keyBytes, err = x509.DecryptPEMBlock(pemBlock, []byte(c.TLSPassword))
^
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
The vanity domain is down, and the project has moved
to a new location.
vendor check started failing because of this:
Collecting initial packages
Download dependencies
unrecognized import path "vbom.ml/util" (https fetch: Get https://vbom.ml/util?go-get=1: dial tcp: lookup vbom.ml on 169.254.169.254:53: no such host)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This is required for supporting some Kubernetes distributions such as
rancher/k3s.
It comes with a test case validating correct parsing of a k3s kubeconfig
file
Signed-off-by: Simon Ferquel <simon.ferquel@docker.com>
```
cli/context/store/store_test.go:156:2: SA5001: should check returned error before deferring f.Close() (staticcheck)
defer f.Close()
^
cli/context/store/store_test.go:189:2: SA5001: should check returned error before deferring f.Close() (staticcheck)
defer f.Close()
^
cli/context/store/store_test.go:240:2: SA5001: should check returned error before deferring f.Close() (staticcheck)
defer f.Close()
^
```
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Adds capabilities to import a .zip file with importZip.
Detects the content type of source by checking bytes & DetectContentType.
Adds LimitedReader reader, a fork of io.LimitedReader,
was needed for better error messaging instead of just getting back EOF.
We are using limited reader to avoid very big files causing memory issues.
Adds a new file size limit for context imports,
this limit is used for the main file for .zip & .tar and individual compressed
files for .zip.
Added TestImportZip that will check the import content type
Then will assert no err on Importing .zip file
Signed-off-by: Goksu Toprak <goksu.toprak@docker.com>
This is less of a layering violation and removes some ugly hardcoded
`"kubernetes"` strings which were needed to avoid an import loop.
Signed-off-by: Ian Campbell <ijc@docker.com>
This removes the need for the core context code to import
`github.com/docker/cli/cli/context/kubernetes` which in turn reduces the
transitive import tree in this file to not pull in all of Kubernetes.
Note that this means that any calling code which is interested in the
kubernetes endpoint must import `github.com/docker/cli/cli/context/kubernetes`
itself somewhere in order to trigger the dynamic registration. In practice
anything which is interested in Kubernetes must import that package (e.g.
`./cli/command/context.list` does for the `EndpointFromContext` function) to do
anything useful, so this restriction is not too onerous.
As a special case a small amount of Kubernetes related logic remains in
`ResolveDefaultContext` to handle error handling when the stack orchestrator
includes Kubernetes. In order to avoid a circular import loop this hardcodes
the kube endpoint name.
Similarly to avoid an import loop the existing `TestDefaultContextInitializer`
cannot continue to unit test for the Kubernetes case, so that aspect of the
test is carved off into a very similar test in the kubernetes context package.
Lastly, note that the kubernetes endpoint is now modifiable via
`WithContextEndpointType`.
Signed-off-by: Ian Campbell <ijc@docker.com>
This reverts commit 59defcb34d which caused #1892
since the timeout applied not only to the dial phase but to everything, so it
would kill `docker logs -f ...` if the container was not chatty enough.
Signed-off-by: Ian Campbell <ijc@docker.com>
The comment on `github.com/docker/cli/kubernetes.NewKubernetesConfig` said:
// Deprecated: Use github.com/docker/compose-on-kubernetes/api.NewKubernetesConfig instead
By making this switch in `github.com/docker/cli/context/kubernetes/load.go` we
break a vendoring chain:
`github.com/docker/cli/cli/command`
→ `vendor/github.com/docker/cli/cli/context/kubernetes/load.go`
→ `vendor/github.com/docker/cli/kubernetes`
→ `github.com/docker/compose-on-kubernetes/api/compose/...`
This means that projects which just want `github.com/docker/cli/cli/command`
(which is itself pulled in transitively by
`github.com/docker/cli/cli-plugins/plugin`) which do not themselves need the
compose-on-kubernetes API avoid a huge pile of transitive dependencies.
On one of my private projects the diff on the vendor dir is:
280 files changed, 21 insertions(+), 211346 deletions(-)
and includes dropping:
* `github.com/docker/compose-on-kubernetes/api/compose/{clone,impersonation}`
* `github.com/docker/compose-on-kubernetes/api/compose/{v1alpha3,v1beta1,v1beta2,v1beta3}`
* `github.com/google/btree`
* `github.com/googleapis/gnostic`
* `github.com/gregjones/httpcache`
* `github.com/peterbourgon/diskv`
* `k8s.io/api/*` (_lots_ of subpackages)
* `k8s.io/client-go/{discovery,kubernetes/scheme}`
and I've gone from:
$ du -sh vendor/k8s.io/
8.1M vendor/k8s.io/
to:
$ du -sh vendor/k8s.io/
2.1M vendor/k8s.io/
(overall I went from 36M → 29M of vendor dir for this particular project)
The change to `cli/command/system/version.go` is just for consistency and
allows us to drop the now unused alias.
Signed-off-by: Ian Campbell <ijc@docker.com>