mirror of
https://github.com/docker/cli.git
synced 2026-11-06 21:18:28 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a82e528901 | ||
|
|
e35bc1b6ae | ||
|
|
baf6c13889 | ||
|
|
4051f75f69 | ||
|
|
76321a699d | ||
|
|
b82456c62f | ||
|
|
a98becc3e3 | ||
|
|
eabc65846b | ||
|
|
b873f57cd0 | ||
|
|
c8a849c2f9 | ||
|
|
f4efc1b596 | ||
|
|
2747e2e3bf | ||
|
|
329cdf1a9d | ||
|
|
0c7e2e7203 | ||
|
|
dfc4efb1e2 | ||
|
|
dba867594c | ||
|
|
d9aefe565a | ||
|
|
9182b351c1 | ||
|
|
0ae55a3e6c | ||
|
|
029a4b21b3 | ||
|
|
e596fea454 | ||
|
|
0c72f456aa | ||
|
|
26f2736a2b | ||
|
|
ac4c4dfabd | ||
|
|
1245054535 | ||
|
|
f72fb0caf0 | ||
|
|
e4af2bf0d3 | ||
|
|
49a1af6aaa | ||
|
|
c2be9ccfc3 | ||
|
|
0da6a5121f | ||
|
|
6b3ca8fc04 | ||
|
|
f47603c290 | ||
|
|
9709c8fe08 | ||
|
|
af45a23fa9 | ||
|
|
bc97f5ac19 | ||
|
|
6d71967120 | ||
|
|
9b51892b80 |
@@ -68,7 +68,7 @@ jobs:
|
||||
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@59cb1203cd42bcefd40a1b6d73b589e48c86040e # v7.5.0
|
||||
uses: docker/bake-action@018cb6412ab401ebaa809aa5f85966b74628600f # v7.4.0
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
set: |
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
|
||||
bin-image:
|
||||
if: ${{ github.event_name != 'pull_request' && github.repository == 'docker/cli' }}
|
||||
uses: docker/github-builder/.github/workflows/bake.yml@cbc9d42f8c89a55623392aadd03600965b80e963 # v1.18.1
|
||||
uses: docker/github-builder/.github/workflows/bake.yml@58cb9f5b71b1836d6f690c1e95effdeb9b98cb8a # v1.17.0
|
||||
permissions:
|
||||
contents: read # same as global permission
|
||||
id-token: write # for signing attestation(s) and authenticating to Docker Hub with GitHub OIDC Token
|
||||
@@ -159,7 +159,7 @@ jobs:
|
||||
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@59cb1203cd42bcefd40a1b6d73b589e48c86040e # v7.5.0
|
||||
uses: docker/bake-action@018cb6412ab401ebaa809aa5f85966b74628600f # v7.4.0
|
||||
with:
|
||||
targets: plugins-cross
|
||||
set: |
|
||||
|
||||
@@ -64,18 +64,18 @@ jobs:
|
||||
name: Update Go
|
||||
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
||||
with:
|
||||
go-version: "1.27.3"
|
||||
go-version: "1.26.10"
|
||||
cache: false
|
||||
-
|
||||
name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
|
||||
uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
with:
|
||||
languages: go
|
||||
-
|
||||
name: Autobuild
|
||||
uses: github/codeql-action/autobuild@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
|
||||
uses: github/codeql-action/autobuild@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
-
|
||||
name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
|
||||
uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
with:
|
||||
category: "/language:go"
|
||||
|
||||
@@ -26,9 +26,6 @@ on:
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write # needed for CodeCov; https://github.com/codecov/codecov-action/blob/v7.1.1/README.md#using-oidc
|
||||
runs-on: ubuntu-26.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -83,4 +80,4 @@ jobs:
|
||||
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
|
||||
with:
|
||||
files: ./build/coverage/coverage.txt
|
||||
use_oidc: true
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
@@ -11,7 +11,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
review:
|
||||
uses: docker/docker-agent-action/.github/workflows/review-pr.yml@aaa657c53cc69ed15683cd8a985d86663a0e1594 # v2.1.0
|
||||
uses: docker/docker-agent-action/.github/workflows/review-pr.yml@3654ec391b070e247de2e2e3c1ff2519b6378b3a # v2.0.9
|
||||
permissions:
|
||||
contents: read # Read repository files and PR diffs
|
||||
pull-requests: write # Post review comments
|
||||
|
||||
@@ -26,9 +26,6 @@ on:
|
||||
|
||||
jobs:
|
||||
ctn:
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write # needed for CodeCov; https://github.com/codecov/codecov-action/blob/v7.1.1/README.md#using-oidc
|
||||
runs-on: ubuntu-26.04
|
||||
steps:
|
||||
-
|
||||
@@ -36,7 +33,7 @@ jobs:
|
||||
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
|
||||
-
|
||||
name: Test
|
||||
uses: docker/bake-action@59cb1203cd42bcefd40a1b6d73b589e48c86040e # v7.5.0
|
||||
uses: docker/bake-action@018cb6412ab401ebaa809aa5f85966b74628600f # v7.4.0
|
||||
with:
|
||||
targets: test-coverage
|
||||
-
|
||||
@@ -44,12 +41,9 @@ jobs:
|
||||
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
|
||||
with:
|
||||
files: ./build/coverage/coverage.txt
|
||||
use_oidc: true
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
host:
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write # needed for CodeCov; https://github.com/codecov/codecov-action/blob/v7.1.1/README.md#using-oidc
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
GOPATH: ${{ github.workspace }}
|
||||
@@ -59,9 +53,9 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- macos-14 # macOS 14 on arm64 (Apple Silicon M1)
|
||||
- macos-15-intel # macOS 15 on Intel
|
||||
- macos-15 # macOS 15 on arm64 (Apple Silicon M1)
|
||||
- macos-26 # macOS 26 on arm64 (Apple Silicon M1)
|
||||
- macos-26-intel # macOS 26 on Intel
|
||||
# - windows-2022 # FIXME: some tests are failing on the Windows runner, as well as on Appveyor since June 24, 2018: https://ci.appveyor.com/project/docker/cli/history
|
||||
steps:
|
||||
-
|
||||
@@ -74,7 +68,7 @@ jobs:
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
||||
with:
|
||||
go-version: "1.27.3"
|
||||
go-version: "1.26.10"
|
||||
cache: false
|
||||
-
|
||||
name: Test
|
||||
@@ -92,4 +86,4 @@ jobs:
|
||||
with:
|
||||
files: /tmp/coverage.txt
|
||||
working-directory: ${{ env.GOPATH }}/src/github.com/docker/cli
|
||||
use_oidc: true
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Run
|
||||
uses: docker/bake-action@59cb1203cd42bcefd40a1b6d73b589e48c86040e # v7.5.0
|
||||
uses: docker/bake-action@018cb6412ab401ebaa809aa5f85966b74628600f # v7.4.0
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
@@ -101,7 +101,7 @@ jobs:
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
||||
with:
|
||||
go-version: "1.27.3"
|
||||
go-version: "1.26.10"
|
||||
cache: false
|
||||
-
|
||||
name: Run gocompat check
|
||||
|
||||
+11
-1
@@ -5,7 +5,7 @@ run:
|
||||
# which causes it to fallback to go1.17 semantics.
|
||||
#
|
||||
# TODO(thaJeztah): update "usetesting" settings to enable go1.24 features once our minimum version is go1.24
|
||||
go: "1.27.3"
|
||||
go: "1.26.10"
|
||||
|
||||
timeout: 5m
|
||||
|
||||
@@ -201,6 +201,11 @@ linters:
|
||||
linters:
|
||||
- gosec
|
||||
|
||||
# TODO: make sure all packages have a description. Currently, there's 67 packages without.
|
||||
- text: "package-comments: should have a package comment"
|
||||
linters:
|
||||
- revive
|
||||
|
||||
# Exclude some linters from running on tests files.
|
||||
- path: _test\.go
|
||||
linters:
|
||||
@@ -222,6 +227,11 @@ linters:
|
||||
linters:
|
||||
- staticcheck
|
||||
|
||||
# TODO(thaJeztah): remove once https://github.com/leighmcculloch/gocheckcompilerdirectives/issues/7 is fixed.
|
||||
- text: "compiler directive unrecognized: //go:fix"
|
||||
linters:
|
||||
- gocheckcompilerdirectives
|
||||
|
||||
# Log a warning if an exclusion rule is unused.
|
||||
# Default: false
|
||||
warn-unused: true
|
||||
|
||||
+6
-8
@@ -5,12 +5,10 @@ ARG BASE_VARIANT=alpine
|
||||
# ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image.
|
||||
# It must be a supported tag in the docker.io/library/alpine image repository
|
||||
# that's also available as alpine image variant for the Golang version used.
|
||||
ARG ALPINE_VERSION=3.24
|
||||
ARG ALPINE_VERSION=3.23
|
||||
ARG BASE_DEBIAN_DISTRO=bookworm
|
||||
|
||||
# BASE_DEBIAN_DISTRO sets the version of the debian base image to use,
|
||||
ARG BASE_DEBIAN_DISTRO=trixie
|
||||
|
||||
ARG GO_VERSION=1.27.3
|
||||
ARG GO_VERSION=1.26.10
|
||||
|
||||
# XX_VERSION specifies the version of the xx utility to use.
|
||||
# It must be a valid tag in the docker.io/tonistiigi/xx image repository.
|
||||
@@ -27,12 +25,12 @@ ARG GOTESTSUM_VERSION=v1.13.0
|
||||
# BUILDX_VERSION sets the version of buildx to use for the e2e tests.
|
||||
# It must be a tag in the docker.io/docker/buildx-bin image repository
|
||||
# on Docker Hub.
|
||||
ARG BUILDX_VERSION=0.38.1
|
||||
ARG BUILDX_VERSION=0.38.0
|
||||
|
||||
# COMPOSE_VERSION is the version of compose to install in the dev container.
|
||||
# It must be a tag in the docker.io/docker/compose-bin image repository
|
||||
# on Docker Hub.
|
||||
ARG COMPOSE_VERSION=v5.7.0
|
||||
ARG COMPOSE_VERSION=v5.6.0
|
||||
|
||||
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
|
||||
|
||||
@@ -55,7 +53,7 @@ WORKDIR /go/src/github.com/docker/cli
|
||||
|
||||
FROM build-base-debian AS build-debian
|
||||
ARG TARGETPLATFORM
|
||||
RUN xx-apt-get install --no-install-recommends -y libc6-dev libgcc-14-dev pkgconf
|
||||
RUN xx-apt-get install --no-install-recommends -y libc6-dev libgcc-12-dev pkgconf
|
||||
|
||||
FROM build-base-${BASE_VARIANT} AS goversioninfo
|
||||
ARG GOVERSIONINFO_VERSION
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli-plugins/metadata"
|
||||
@@ -33,11 +32,6 @@ import (
|
||||
// called.
|
||||
var PersistentPreRunE func(*cobra.Command, []string) error
|
||||
|
||||
// finalizeHookTimeout is the timeout given for running the finalize hook.
|
||||
// It contains the timeout for exporting metrics and a little bit extra in case
|
||||
// shutdown does not respond to the export timeout promptly.
|
||||
const finalizeHookTimeout = command.ExportTimeout + 10*time.Millisecond
|
||||
|
||||
// RunPlugin executes the specified plugin command
|
||||
func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta metadata.Metadata) error {
|
||||
tcmd := newPluginCommand(dockerCli, plugin, meta)
|
||||
@@ -75,7 +69,6 @@ func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta metadat
|
||||
stopInstrumentation(err)
|
||||
return err
|
||||
}
|
||||
cobra.OnFinalize(func() { finalizeHook(dockerCli) })
|
||||
})
|
||||
return retErr
|
||||
}
|
||||
@@ -90,59 +83,6 @@ func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta metadat
|
||||
return cmd.Execute()
|
||||
}
|
||||
|
||||
// finalizeHook is a hook to be run when the CLI has finished executing the run command.
|
||||
// This happens after any post run methods but also always runs even when an error happens.
|
||||
func finalizeHook(dockerCli *command.DockerCli) {
|
||||
// Use a new context for the export so that the command being cancelled
|
||||
// doesn't affect the metrics, and we get metrics for cancelled commands.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), command.ExportTimeout)
|
||||
defer cancel()
|
||||
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
wait bool
|
||||
)
|
||||
if tp, ok := dockerCli.TracerProvider().(command.TracerProvider); ok {
|
||||
wg.Go(func() {
|
||||
if err := tp.Shutdown(ctx); err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
})
|
||||
wait = true
|
||||
}
|
||||
|
||||
if mp, ok := dockerCli.MeterProvider().(command.MeterProvider); ok {
|
||||
wg.Go(func() {
|
||||
if err := mp.Shutdown(ctx); err != nil {
|
||||
otel.Handle(err)
|
||||
}
|
||||
})
|
||||
wait = true
|
||||
}
|
||||
|
||||
// Wait for the wait group in another goroutine if any were created.
|
||||
if !wait {
|
||||
return
|
||||
}
|
||||
|
||||
// Spawn a goroutine to wait for the wait group.
|
||||
// If the shutdown does not promptly hang up with the
|
||||
// cancellation of the context, we leave this goroutine
|
||||
// orphaned so the process can exit.
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
wg.Wait()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(finalizeHookTimeout):
|
||||
// Ensure we still exit even if the shutdown doesn't work properly.
|
||||
// We give 10 extra milliseconds for the cleanup to happen.
|
||||
}
|
||||
}
|
||||
|
||||
// Run is the top-level entry point to the CLI plugin framework. It should
|
||||
// be called from the plugin's "main()" function. It initializes a new
|
||||
// [command.DockerCli] instance with the given options before calling
|
||||
@@ -272,8 +212,8 @@ func newMetadataSubcommand(plugin *cobra.Command, meta metadata.Metadata) *cobra
|
||||
Use: metadata.MetadataSubcommandName,
|
||||
Hidden: true,
|
||||
// Suppress the global/parent PersistentPreRunE, which
|
||||
// needlessly initializes the client and tries to connect to the
|
||||
// daemon.
|
||||
// needlessly initializes the client and tries to
|
||||
// connect to the daemon.
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
|
||||
+1
-19
@@ -160,25 +160,7 @@ func (tcmd *TopLevelCommand) HandleGlobalFlags() (*cobra.Command, []string, erro
|
||||
return nil, nil, cmd.FlagErrorFunc()(cmd, err)
|
||||
}
|
||||
|
||||
args := flags.Args()
|
||||
|
||||
// A leading "--help"/"-h" is consumed above as the root's persistent
|
||||
// help flag and stripped from args, so the target subcommand never sees
|
||||
// it. That's fine for most subcommands, which inherit the same help
|
||||
// flag instance, but "run" and "create" register their own local
|
||||
// "help" flag (to avoid a shorthand clash with "-h"/"--hostname"),
|
||||
// which shadows the persistent one and is left false. Propagate the
|
||||
// value so "docker --help run <image>" shows help like "docker run
|
||||
// --help" does, instead of running the container.
|
||||
if help, _ := flags.GetBool("help"); help {
|
||||
if sub, _, err := cmd.Find(args); err == nil && sub != cmd {
|
||||
if sub.Flags().Lookup("help") != nil {
|
||||
_ = sub.Flags().Set("help", "true")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cmd, args, nil
|
||||
return cmd, flags.Args(), nil
|
||||
}
|
||||
|
||||
// Initialize finalises global option parsing and initializes the docker client.
|
||||
|
||||
@@ -108,45 +108,3 @@ func TestDecoratedName(t *testing.T) {
|
||||
topLevelCommand.Annotations = map[string]string{metadata.CommandAnnotationPlugin: "true"}
|
||||
assert.Equal(t, decoratedName(topLevelCommand), "pluginTopLevelCommand*")
|
||||
}
|
||||
|
||||
// TestHandleGlobalFlagsHelpPropagation covers https://github.com/docker/cli/issues/7473:
|
||||
// a leading "--help" is consumed as the root's persistent help flag and
|
||||
// stripped from args, so a subcommand that registers its own local "help"
|
||||
// flag (as "run" and "create" do, to avoid a shorthand clash with "-h") never
|
||||
// sees it and runs instead of showing help.
|
||||
func TestHandleGlobalFlagsHelpPropagation(t *testing.T) {
|
||||
newRootCmd := func() (root, sub *cobra.Command) {
|
||||
root = &cobra.Command{Use: "docker"}
|
||||
root.PersistentFlags().BoolP("help", "h", false, "Print usage")
|
||||
|
||||
sub = &cobra.Command{Use: "run", RunE: func(cmd *cobra.Command, args []string) error { return nil }}
|
||||
sub.Flags().Bool("help", false, "Print usage")
|
||||
root.AddCommand(sub)
|
||||
return root, sub
|
||||
}
|
||||
|
||||
t.Run("propagates to the shadowing local help flag", func(t *testing.T) {
|
||||
root, sub := newRootCmd()
|
||||
tcmd := &TopLevelCommand{cmd: root, args: []string{"--help", "run", "hello-world"}}
|
||||
|
||||
_, args, err := tcmd.HandleGlobalFlags()
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, args, []string{"run", "hello-world"})
|
||||
|
||||
help, err := sub.Flags().GetBool("help")
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, help, true)
|
||||
})
|
||||
|
||||
t.Run("leaves the local help flag alone without --help", func(t *testing.T) {
|
||||
root, sub := newRootCmd()
|
||||
tcmd := &TopLevelCommand{cmd: root, args: []string{"run", "hello-world"}}
|
||||
|
||||
_, _, err := tcmd.HandleGlobalFlags()
|
||||
assert.NilError(t, err)
|
||||
|
||||
help, err := sub.Flags().GetBool("help")
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, help, false)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -146,27 +146,24 @@ func (c *ContainerContext) ID() string {
|
||||
// slash (/) prefix stripped. Additional names for the container (related to the
|
||||
// legacy `--link` feature) are omitted when formatting "truncated".
|
||||
func (c *ContainerContext) Names() string {
|
||||
if c.trunc {
|
||||
// When printing truncated, we only print a single name.
|
||||
//
|
||||
// Pick the first name that's not a legacy link (does not have
|
||||
// slashes inside the name itself (e.g., "/other-container/link")).
|
||||
// Normally this would be the first name found.
|
||||
for _, n := range c.c.Names {
|
||||
if name := strings.TrimPrefix(n, "/"); strings.IndexByte(name, '/') == -1 {
|
||||
return name
|
||||
}
|
||||
}
|
||||
// No name without slashes was found; this can happen when connected
|
||||
// to a classic Swarm API, which prefixes names with the node-name
|
||||
// ("/<node-name>/<container-name>"). Fall back to printing all names.
|
||||
}
|
||||
var b strings.Builder
|
||||
for i, n := range c.c.Names {
|
||||
name := strings.TrimPrefix(n, "/")
|
||||
if c.trunc {
|
||||
// When printing truncated, we only print a single name.
|
||||
//
|
||||
// Pick the first name that's not a legacy link (does not have
|
||||
// slashes inside the name itself (e.g., "/other-container/link")).
|
||||
// Normally this would be the first name found.
|
||||
if strings.IndexByte(name, '/') == -1 {
|
||||
return name
|
||||
}
|
||||
continue
|
||||
}
|
||||
if i > 0 {
|
||||
b.WriteByte(',')
|
||||
}
|
||||
b.WriteString(strings.TrimPrefix(n, "/"))
|
||||
b.WriteString(name)
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
@@ -48,25 +48,6 @@ func TestContainerPsContext(t *testing.T) {
|
||||
expValue: "foobar_baz",
|
||||
call: ctx.Names,
|
||||
},
|
||||
{
|
||||
container: container.Summary{Names: []string{"/other/link", "/foobar_baz"}},
|
||||
trunc: true,
|
||||
expValue: "foobar_baz",
|
||||
call: ctx.Names,
|
||||
},
|
||||
{
|
||||
container: container.Summary{Names: []string{"/foobar_baz", "/other/link"}},
|
||||
expValue: "foobar_baz,other/link",
|
||||
call: ctx.Names,
|
||||
},
|
||||
{
|
||||
// Names returned by a classic Swarm API are prefixed with the
|
||||
// node-name; see https://github.com/docker/cli/pull/6875
|
||||
container: container.Summary{Names: []string{"/node-1/foobar_baz"}},
|
||||
trunc: true,
|
||||
expValue: "node-1/foobar_baz",
|
||||
call: ctx.Names,
|
||||
},
|
||||
{
|
||||
container: container.Summary{Image: "ubuntu"},
|
||||
trunc: true,
|
||||
@@ -276,7 +257,6 @@ func TestContainerPsContext(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:dupword // ignore duplicate "ubuntu" in test fixtures
|
||||
func TestContainerContextWrite(t *testing.T) {
|
||||
unixTime := time.Now().AddDate(0, 0, -1).Unix()
|
||||
expectedTime := time.Unix(unixTime, 0).String()
|
||||
|
||||
@@ -10,10 +10,8 @@ import (
|
||||
"slices"
|
||||
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/completion"
|
||||
"github.com/docker/cli/cli/config"
|
||||
"github.com/docker/cli/cli/manifest/store"
|
||||
"github.com/docker/cli/internal/registryclient"
|
||||
@@ -22,23 +20,6 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// similar to https://github.com/containerd/platforms/blob/v1.0.0-rc.5/database.go#L29-L38
|
||||
knownOSes = []string{
|
||||
"aix", "android", "darwin", "dragonfly", "freebsd", "hurd", "illumos",
|
||||
"ios", "js", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris",
|
||||
"windows", "zos",
|
||||
}
|
||||
|
||||
// similar to https://github.com/containerd/platforms/blob/v1.0.0-rc.5/database.go#L51-L60
|
||||
knownArches = []string{
|
||||
"386", "amd64", "amd64p32", "arm", "armbe", "arm64", "arm64be", "ppc64",
|
||||
"ppc64le", "loong64", "mips", "mipsle", "mips64", "mips64le", "mips64p32",
|
||||
"mips64p32le", "ppc", "riscv", "riscv64", "s390", "s390x", "sparc",
|
||||
"sparc64", "wasm",
|
||||
}
|
||||
)
|
||||
|
||||
type annotateOptions struct {
|
||||
target string // the target manifest list name (also transaction ID)
|
||||
image string // the manifest to annotate within the list
|
||||
@@ -116,8 +97,6 @@ func newAnnotateCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
flags.StringSliceVar(&opts.osFeatures, "os-features", []string{}, "Set operating system feature")
|
||||
flags.StringVar(&opts.variant, "variant", "", "Set architecture variant")
|
||||
|
||||
_ = cmd.RegisterFlagCompletionFunc("os", completion.FromList(knownOSes...))
|
||||
_ = cmd.RegisterFlagCompletionFunc("arch", completion.FromList(knownArches...))
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -160,15 +139,8 @@ func runManifestAnnotate(dockerCLI command.Cli, opts annotateOptions) error {
|
||||
imageManifest.Descriptor.Platform.OSVersion = opts.osVersion
|
||||
}
|
||||
|
||||
// Validate platform syntax, without restricting OS/architecture combinations.
|
||||
//
|
||||
// TODO(thaJeztah): Implement a platforms.Validate in containerd/platforms and replace this code.
|
||||
p := imageManifest.Descriptor.Platform
|
||||
if p.OS == "" || p.Architecture == "" {
|
||||
return fmt.Errorf("manifest entry for image has missing os/architecture: %q/%q", p.OS, p.Architecture)
|
||||
}
|
||||
if _, err := platforms.Parse(platforms.FormatAll(*p)); err != nil {
|
||||
return fmt.Errorf("manifest entry for image has invalid platform: %w", err)
|
||||
if !isValidOSArch(imageManifest.Descriptor.Platform.OS, imageManifest.Descriptor.Platform.Architecture) {
|
||||
return fmt.Errorf("manifest entry for image has unsupported os/arch combination: %s/%s", opts.os, opts.arch)
|
||||
}
|
||||
return manifestStore.Save(targetRef, imgRef, imageManifest)
|
||||
}
|
||||
|
||||
@@ -58,16 +58,15 @@ func TestManifestAnnotate(t *testing.T) {
|
||||
assert.ErrorContains(t, cmd.Execute(), expectedError)
|
||||
|
||||
cmd.SetArgs([]string{"example.com/list:v1", "example.com/alpine:3.0"})
|
||||
assert.NilError(t, cmd.Flags().Set("os", "freebsd"))
|
||||
assert.NilError(t, cmd.Flags().Set("arch", "<invalid>"))
|
||||
assert.NilError(t, cmd.Flags().Set("os-version", "1"))
|
||||
assert.NilError(t, cmd.Flags().Set("os-features", "feature1"))
|
||||
assert.NilError(t, cmd.Flags().Set("variant", "v7"))
|
||||
|
||||
expectedError = "manifest entry for image has invalid platform"
|
||||
cmd.Flags().Set("os", "freebsd")
|
||||
cmd.Flags().Set("arch", "fake")
|
||||
cmd.Flags().Set("os-version", "1")
|
||||
cmd.Flags().Set("os-features", "feature1")
|
||||
cmd.Flags().Set("variant", "v7")
|
||||
expectedError = "manifest entry for image has unsupported os/arch combination"
|
||||
assert.ErrorContains(t, cmd.Execute(), expectedError)
|
||||
|
||||
assert.NilError(t, cmd.Flags().Set("arch", "arm"))
|
||||
cmd.Flags().Set("arch", "arm")
|
||||
assert.NilError(t, cmd.Execute())
|
||||
|
||||
cmd = newInspectCommand(cli)
|
||||
|
||||
@@ -9,6 +9,53 @@ import (
|
||||
"github.com/docker/cli/cli/manifest/types"
|
||||
)
|
||||
|
||||
type osArch struct {
|
||||
os string
|
||||
arch string
|
||||
}
|
||||
|
||||
// Remove any unsupported os/arch combo
|
||||
// list of valid os/arch values (see "Optional Environment Variables" section
|
||||
// of https://go.dev/doc/install/source
|
||||
// Added linux/s390x as we know System z support already exists
|
||||
// Keep in sync with _docker_manifest_annotate in contrib/completion/bash/docker
|
||||
var validOSArches = map[osArch]bool{
|
||||
{os: "darwin", arch: "386"}: true,
|
||||
{os: "darwin", arch: "amd64"}: true,
|
||||
{os: "darwin", arch: "arm"}: true,
|
||||
{os: "darwin", arch: "arm64"}: true,
|
||||
{os: "dragonfly", arch: "amd64"}: true,
|
||||
{os: "freebsd", arch: "386"}: true,
|
||||
{os: "freebsd", arch: "amd64"}: true,
|
||||
{os: "freebsd", arch: "arm"}: true,
|
||||
{os: "linux", arch: "386"}: true,
|
||||
{os: "linux", arch: "amd64"}: true,
|
||||
{os: "linux", arch: "arm"}: true,
|
||||
{os: "linux", arch: "arm64"}: true,
|
||||
{os: "linux", arch: "ppc64le"}: true,
|
||||
{os: "linux", arch: "mips64"}: true,
|
||||
{os: "linux", arch: "mips64le"}: true,
|
||||
{os: "linux", arch: "riscv64"}: true,
|
||||
{os: "linux", arch: "s390x"}: true,
|
||||
{os: "netbsd", arch: "386"}: true,
|
||||
{os: "netbsd", arch: "amd64"}: true,
|
||||
{os: "netbsd", arch: "arm"}: true,
|
||||
{os: "openbsd", arch: "386"}: true,
|
||||
{os: "openbsd", arch: "amd64"}: true,
|
||||
{os: "openbsd", arch: "arm"}: true,
|
||||
{os: "plan9", arch: "386"}: true,
|
||||
{os: "plan9", arch: "amd64"}: true,
|
||||
{os: "solaris", arch: "amd64"}: true,
|
||||
{os: "windows", arch: "386"}: true,
|
||||
{os: "windows", arch: "amd64"}: true,
|
||||
}
|
||||
|
||||
func isValidOSArch(os string, arch string) bool {
|
||||
// check for existence of this combo
|
||||
_, ok := validOSArches[osArch{os, arch}]
|
||||
return ok
|
||||
}
|
||||
|
||||
func normalizeReference(ref string) (reference.Named, error) {
|
||||
namedRef, err := reference.ParseNormalizedNamed(ref)
|
||||
if err != nil {
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"github.com/docker/cli/internal/tui"
|
||||
registrytypes "github.com/moby/moby/api/types/registry"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
@@ -227,7 +226,7 @@ func loginWithStoredCredentials(ctx context.Context, dockerCLI command.Cli, auth
|
||||
return resp.Auth.Status, err
|
||||
}
|
||||
|
||||
func loginUser(ctx context.Context, dockerCLI command.Cli, opts loginOptions, defaultUsername, serverAddress string) (message string, _ error) {
|
||||
func loginUser(ctx context.Context, dockerCLI command.Cli, opts loginOptions, defaultUsername, serverAddress string) (msg string, _ error) {
|
||||
// Some links documenting this:
|
||||
// - https://code.google.com/archive/p/mintty/issues/56
|
||||
// - https://github.com/docker/docker/issues/15272
|
||||
@@ -241,12 +240,13 @@ func loginUser(ctx context.Context, dockerCLI command.Cli, opts loginOptions, de
|
||||
|
||||
// If we're logging into the index server and the user didn't provide a username or password, use the device flow
|
||||
if serverAddress == registry.IndexServer && opts.user == "" && opts.password == "" {
|
||||
msg, err := loginWithDeviceCodeFlow(ctx, dockerCLI)
|
||||
if err == nil || !errors.Is(err, manager.ErrDeviceLoginStartFail) {
|
||||
var err error
|
||||
msg, err = loginWithDeviceCodeFlow(ctx, dockerCLI)
|
||||
// if the error represents a failure to initiate the device-code flow,
|
||||
// then we fallback to regular cli credentials login
|
||||
if !errors.Is(err, manager.ErrDeviceLoginStartFail) {
|
||||
return msg, err
|
||||
}
|
||||
|
||||
logrus.WithError(err).Debug("failed to start web-based login")
|
||||
_, _ = fmt.Fprint(dockerCLI.Err(), "Failed to start web-based login - falling back to command line login...\n\n")
|
||||
}
|
||||
|
||||
|
||||
@@ -210,9 +210,9 @@ func TestResourceOptionsToResourceRequirementsSwap(t *testing.T) {
|
||||
r, err = swapOptions.ToResourceRequirements(flags)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, r.SwapBytes != nil)
|
||||
assert.Check(t, is.Equal(*r.SwapBytes, int64(86000)))
|
||||
assert.Check(t, is.Equal(*(r.SwapBytes), int64(86000)))
|
||||
assert.Check(t, r.MemorySwappiness != nil)
|
||||
assert.Check(t, is.Equal(*r.MemorySwappiness, int64(23)))
|
||||
assert.Check(t, is.Equal(*(r.MemorySwappiness), int64(23)))
|
||||
}
|
||||
|
||||
func TestToServiceNetwork(t *testing.T) {
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
const ExportTimeout = 50 * time.Millisecond
|
||||
const exportTimeout = 50 * time.Millisecond
|
||||
|
||||
// TracerProvider is an extension of the trace.TracerProvider interface for CLI programs.
|
||||
type TracerProvider interface {
|
||||
@@ -205,7 +205,7 @@ func (r *cliReader) Shutdown(ctx context.Context) error {
|
||||
// We don't want CLI metrics to prevent the CLI from exiting
|
||||
// so if there's some kind of issue we need to abort pretty
|
||||
// quickly.
|
||||
ctx, cancel := context.WithTimeout(ctx, ExportTimeout)
|
||||
ctx, cancel := context.WithTimeout(ctx, exportTimeout)
|
||||
defer cancel()
|
||||
|
||||
return r.ForceFlush(ctx)
|
||||
|
||||
@@ -109,7 +109,7 @@ func dockerSpanExporter(ctx context.Context, cli Cli) []sdktrace.TracerProviderO
|
||||
otel.Handle(err)
|
||||
return nil
|
||||
}
|
||||
return []sdktrace.TracerProviderOption{sdktrace.WithBatcher(exp, sdktrace.WithExportTimeout(ExportTimeout))}
|
||||
return []sdktrace.TracerProviderOption{sdktrace.WithBatcher(exp, sdktrace.WithExportTimeout(exportTimeout))}
|
||||
}
|
||||
|
||||
func dockerMetricExporter(ctx context.Context, cli Cli) []sdkmetric.Option {
|
||||
|
||||
@@ -85,7 +85,7 @@ func startCobraCommandTimer(mp metric.MeterProvider, attrs []attribute.KeyValue)
|
||||
return func(err error) {
|
||||
// Use a new context for the export so that the command being cancelled
|
||||
// doesn't affect the metrics, and we get metrics for cancelled commands.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), ExportTimeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), exportTimeout)
|
||||
defer cancel()
|
||||
|
||||
duration := float64(time.Since(start)) / float64(time.Millisecond)
|
||||
|
||||
@@ -255,6 +255,7 @@ func mergeLoggingConfig(dst, src reflect.Value) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func mergeUlimitsConfig(dst, src reflect.Value) error {
|
||||
if src.Interface() != reflect.Zero(reflect.TypeOf(src.Interface())).Interface() {
|
||||
dst.Elem().Set(src.Elem())
|
||||
@@ -262,6 +263,7 @@ func mergeUlimitsConfig(dst, src reflect.Value) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func mergeShellCommand(dst, src reflect.Value) error {
|
||||
if src.Len() != 0 {
|
||||
dst.Set(src)
|
||||
@@ -269,6 +271,7 @@ func mergeShellCommand(dst, src reflect.Value) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func mergeServiceNetworkConfig(dst, src reflect.Value) error {
|
||||
if src.Interface() != reflect.Zero(reflect.TypeOf(src.Interface())).Interface() {
|
||||
dst.Elem().FieldByName("Aliases").Set(src.Elem().FieldByName("Aliases"))
|
||||
@@ -282,6 +285,7 @@ func mergeServiceNetworkConfig(dst, src reflect.Value) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func mergeUint64(dst, src reflect.Value) error {
|
||||
if !src.IsNil() {
|
||||
dst.Elem().Set(src.Elem())
|
||||
|
||||
@@ -27,13 +27,8 @@ func TerminatePrompt(ctx context.Context, t *testing.T, cmd *cobra.Command, cli
|
||||
}))
|
||||
cli.SetOut(outStream)
|
||||
|
||||
r, w, err := os.Pipe()
|
||||
r, _, err := os.Pipe()
|
||||
assert.NilError(t, err)
|
||||
t.Cleanup(func() {
|
||||
_ = w.Close()
|
||||
_ = r.Close()
|
||||
})
|
||||
|
||||
cli.SetIn(streams.NewIn(r))
|
||||
|
||||
notifyCtx, notifyCancel := context.WithCancel(ctx)
|
||||
@@ -63,6 +58,8 @@ func TerminatePrompt(ctx context.Context, t *testing.T, cmd *cobra.Command, cli
|
||||
}()
|
||||
}
|
||||
|
||||
assert.Check(t, cli.OutBuffer().Len() > 0)
|
||||
|
||||
// a small delay to ensure the plugin is prompting
|
||||
time.Sleep(100 * time.Microsecond)
|
||||
|
||||
|
||||
@@ -11,9 +11,8 @@ import (
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/cli/cli/streams"
|
||||
"github.com/moby/moby/api/types/jsonstream"
|
||||
"github.com/docker/cli/internal/jsonstream"
|
||||
registrytypes "github.com/moby/moby/api/types/registry"
|
||||
"github.com/moby/moby/client/pkg/jsonmessage"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/theupdateframework/notary/client"
|
||||
"github.com/theupdateframework/notary/tuf/data"
|
||||
@@ -47,7 +46,7 @@ func PushTrustedReference(ctx context.Context, ioStreams Streams, repoInfo *Repo
|
||||
// Count the times of calling for handleTarget,
|
||||
// if it is called more that once, that should be considered an error in a trusted push.
|
||||
cnt := 0
|
||||
handleTarget := func(msg jsonstream.Message) {
|
||||
handleTarget := func(msg jsonstream.JSONMessage) {
|
||||
cnt++
|
||||
if cnt > 1 {
|
||||
// handleTarget should only be called once. This will be treated as an error.
|
||||
@@ -79,14 +78,14 @@ func PushTrustedReference(ctx context.Context, ioStreams Streams, repoInfo *Repo
|
||||
default:
|
||||
// We want trust signatures to always take an explicit tag,
|
||||
// otherwise it will act as an untrusted push.
|
||||
if err := displayJSONMessages(ctx, in, ioStreams.Out(), nil); err != nil {
|
||||
if err := jsonstream.Display(ctx, in, ioStreams.Out()); err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = fmt.Fprintln(ioStreams.Err(), "No tag specified, skipping trust metadata push")
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := displayJSONMessages(ctx, in, ioStreams.Out(), handleTarget); err != nil {
|
||||
if err := jsonstream.Display(ctx, in, ioStreams.Out(), jsonstream.WithAuxCallback(handleTarget)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -148,34 +147,3 @@ func PushTrustedReference(ctx context.Context, ioStreams Streams, repoInfo *Repo
|
||||
_, _ = fmt.Fprintf(ioStreams.Out(), "Successfully signed %s:%s\n", repoInfo.Name.Name(), tag)
|
||||
return nil
|
||||
}
|
||||
|
||||
type ctxReader struct {
|
||||
err chan error
|
||||
r io.Reader
|
||||
}
|
||||
|
||||
func (r *ctxReader) Read(p []byte) (int, error) {
|
||||
select {
|
||||
case err := <-r.err:
|
||||
return 0, err
|
||||
default:
|
||||
return r.r.Read(p)
|
||||
}
|
||||
}
|
||||
|
||||
// displayJSONMessages prints the JSON messages from in to out. It returns
|
||||
// ctx.Err() if ctx is canceled, but not when in is closed.
|
||||
func displayJSONMessages(ctx context.Context, in io.Reader, out *streams.Out, auxCallback func(jsonstream.Message)) error {
|
||||
if ctx.Err() != nil {
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
reader := &ctxReader{err: make(chan error, 1), r: in}
|
||||
stop := context.AfterFunc(ctx, func() { reader.err <- ctx.Err() })
|
||||
defer stop()
|
||||
|
||||
if err := jsonmessage.DisplayJSONMessagesStream(reader, out, out.FD(), out.IsTerminal(), auxCallback); err != nil {
|
||||
return err
|
||||
}
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package trust
|
||||
|
||||
import (
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/internal/commands"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
commands.Register(newTrustCommand)
|
||||
}
|
||||
|
||||
// newTrustCommand returns a cobra command for `trust` subcommands.
|
||||
func newTrustCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "trust",
|
||||
Short: "Manage trust on Docker images",
|
||||
Args: cli.NoArgs,
|
||||
RunE: command.ShowHelp(dockerCLI.Err()),
|
||||
|
||||
DisableFlagsInUseLine: true,
|
||||
}
|
||||
cmd.AddCommand(
|
||||
newRevokeCommand(dockerCLI),
|
||||
newSignCommand(dockerCLI),
|
||||
newTrustKeyCommand(dockerCLI),
|
||||
newTrustSignerCommand(dockerCLI),
|
||||
newInspectCommand(dockerCLI),
|
||||
)
|
||||
return cmd
|
||||
}
|
||||
@@ -5,12 +5,12 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cmd/docker-trust/internal/trust"
|
||||
"github.com/docker/cli/internal/lazyregexp"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/theupdateframework/notary"
|
||||
"github.com/theupdateframework/notary/trustmanager"
|
||||
@@ -41,7 +41,7 @@ func newKeyGenerateCommand(dockerCLI command.Streams) *cobra.Command {
|
||||
}
|
||||
|
||||
// key names can use lowercase alphanumeric + _ + - characters
|
||||
var validKeyName = regexp.MustCompile(`^[a-z0-9][a-z0-9\_\-]*$`).MatchString
|
||||
var validKeyName = lazyregexp.New(`^[a-z0-9][a-z0-9\_\-]*$`).MatchString
|
||||
|
||||
// validate that all of the key names are unique and are alphanumeric + _ + -
|
||||
// and that we do not already have public key files in the target dir on disk
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cmd/docker-trust/internal/trust"
|
||||
"github.com/docker/cli/internal/lazyregexp"
|
||||
"github.com/docker/cli/opts"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/theupdateframework/notary/client"
|
||||
@@ -45,7 +45,7 @@ func newSignerAddCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
var validSignerName = regexp.MustCompile(`^[a-z0-9][a-z0-9\_\-]*$`).MatchString
|
||||
var validSignerName = lazyregexp.New(`^[a-z0-9][a-z0-9\_\-]*$`).MatchString
|
||||
|
||||
func addSigner(ctx context.Context, dockerCLI command.Cli, options signerAddOptions) error {
|
||||
signerName := options.signer
|
||||
|
||||
@@ -580,15 +580,6 @@ func runDocker(ctx context.Context, dockerCli *command.DockerCli) error {
|
||||
}
|
||||
// Other missing or invalid plugins fall through to cmd.ExecuteContext(),
|
||||
// which reports the standard unknown-command error.
|
||||
//
|
||||
// Cobra handles "--version" before it checks for unknown commands,
|
||||
// so unset it to make "docker nonexistent --version" fail instead
|
||||
// of printing the version. A global "--version" flag (as in
|
||||
// "docker --version nonexistent") was already parsed, and still
|
||||
// prints the version.
|
||||
if !cmd.Flags().Changed("version") {
|
||||
cmd.Version = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4156,7 +4156,6 @@ _docker_manifest_annotate() {
|
||||
amd64
|
||||
arm
|
||||
arm64
|
||||
loong64
|
||||
mips64
|
||||
mips64le
|
||||
ppc64le
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# ALPINE_VERSION sets the version of the alpine base image to use.
|
||||
# It must be a supported tag in the docker.io/library/alpine image repository.
|
||||
ARG ALPINE_VERSION=3.24
|
||||
ARG ALPINE_VERSION=3.23
|
||||
|
||||
FROM alpine:${ALPINE_VERSION} AS gen
|
||||
RUN apk add --no-cache bash git
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG GO_VERSION=1.27.3
|
||||
ARG GO_VERSION=1.26.10
|
||||
|
||||
# ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image.
|
||||
# It must be a supported tag in the docker.io/library/alpine image repository
|
||||
# that's also available as alpine image variant for the Golang version used.
|
||||
ARG ALPINE_VERSION=3.24
|
||||
ARG ALPINE_VERSION=3.23
|
||||
|
||||
# BUILDX_VERSION sets the version of buildx to install in the dev container.
|
||||
# It must be a valid tag in the docker.io/docker/buildx-bin image repository
|
||||
# on Docker Hub.
|
||||
ARG BUILDX_VERSION=0.38.1
|
||||
ARG BUILDX_VERSION=0.38.0
|
||||
FROM docker/buildx-bin:${BUILDX_VERSION} AS buildx
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS golang
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG GO_VERSION=1.27.3
|
||||
ARG GO_VERSION=1.26.10
|
||||
|
||||
# ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image.
|
||||
# It must be a supported tag in the docker.io/library/alpine image repository
|
||||
# that's also available as alpine image variant for the Golang version used.
|
||||
ARG ALPINE_VERSION=3.24
|
||||
ARG ALPINE_VERSION=3.23
|
||||
# GOLANGCI_LINT_VERSION sets the version of the golangci/golangci-lint image to use.
|
||||
ARG GOLANGCI_LINT_VERSION=v2.14.0
|
||||
ARG GOLANGCI_LINT_VERSION=v2.10.1
|
||||
|
||||
FROM golangci/golangci-lint:${GOLANGCI_LINT_VERSION}-alpine AS golangci-lint
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG GO_VERSION=1.27.3
|
||||
ARG GO_VERSION=1.26.10
|
||||
|
||||
# ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image.
|
||||
# It must be a supported tag in the docker.io/library/alpine image repository
|
||||
# that's also available as alpine image variant for the Golang version used.
|
||||
ARG ALPINE_VERSION=3.24
|
||||
ARG MODOUTDATED_VERSION=v0.9.0
|
||||
ARG ALPINE_VERSION=3.23
|
||||
ARG MODOUTDATED_VERSION=v0.8.0
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS base
|
||||
ENV GOTOOLCHAIN=local
|
||||
|
||||
@@ -44,8 +44,8 @@ created. Supported `Dockerfile` instructions:
|
||||
$ docker ps
|
||||
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
c3f279d17e0a ubuntu:26.04 /bin/bash 7 days ago Up 25 hours desperate_dubinsky
|
||||
197387f1b436 ubuntu:26.04 /bin/bash 7 days ago Up 25 hours focused_hamilton
|
||||
c3f279d17e0a ubuntu:24.04 /bin/bash 7 days ago Up 25 hours desperate_dubinsky
|
||||
197387f1b436 ubuntu:24.04 /bin/bash 7 days ago Up 25 hours focused_hamilton
|
||||
|
||||
$ docker commit c3f279d17e0a svendowideit/testimage:version3
|
||||
|
||||
@@ -63,8 +63,8 @@ svendowideit/testimage version3 f5283438590d 16 sec
|
||||
$ docker ps
|
||||
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
c3f279d17e0a ubuntu:26.04 /bin/bash 7 days ago Up 25 hours desperate_dubinsky
|
||||
197387f1b436 ubuntu:26.04 /bin/bash 7 days ago Up 25 hours focused_hamilton
|
||||
c3f279d17e0a ubuntu:24.04 /bin/bash 7 days ago Up 25 hours desperate_dubinsky
|
||||
197387f1b436 ubuntu:24.04 /bin/bash 7 days ago Up 25 hours focused_hamilton
|
||||
|
||||
$ docker inspect -f "{{ .Config.Env }}" c3f279d17e0a
|
||||
|
||||
@@ -85,8 +85,8 @@ $ docker inspect -f "{{ .Config.Env }}" f5283438590d
|
||||
$ docker ps
|
||||
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
c3f279d17e0a ubuntu:26.04 /bin/bash 7 days ago Up 25 hours desperate_dubinsky
|
||||
197387f1b436 ubuntu:26.04 /bin/bash 7 days ago Up 25 hours focused_hamilton
|
||||
c3f279d17e0a ubuntu:24.04 /bin/bash 7 days ago Up 25 hours desperate_dubinsky
|
||||
197387f1b436 ubuntu:24.04 /bin/bash 7 days ago Up 25 hours focused_hamilton
|
||||
|
||||
$ docker commit --change='CMD ["apachectl", "-DFOREGROUND"]' -c "EXPOSE 80" c3f279d17e0a svendowideit/testimage:version4
|
||||
|
||||
@@ -100,6 +100,6 @@ $ docker ps
|
||||
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
89373736e2e7 testimage:version4 "apachectl -DFOREGROU" 3 seconds ago Up 2 seconds 80/tcp distracted_fermat
|
||||
c3f279d17e0a ubuntu:26.04 /bin/bash 7 days ago Up 25 hours desperate_dubinsky
|
||||
197387f1b436 ubuntu:26.04 /bin/bash 7 days ago Up 25 hours focused_hamilton
|
||||
c3f279d17e0a ubuntu:24.04 /bin/bash 7 days ago Up 25 hours desperate_dubinsky
|
||||
197387f1b436 ubuntu:24.04 /bin/bash 7 days ago Up 25 hours focused_hamilton
|
||||
```
|
||||
|
||||
@@ -33,7 +33,7 @@ Running `docker ps --no-trunc` showing 2 linked containers.
|
||||
$ docker ps --no-trunc
|
||||
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
ca5534a51dd04bbcebe9b23ba05f389466cf0c190f1f8f182d7eea92a9671d00 ubuntu:26.04 bash 17 seconds ago Up 16 seconds 3300-3310/tcp webapp
|
||||
ca5534a51dd04bbcebe9b23ba05f389466cf0c190f1f8f182d7eea92a9671d00 ubuntu:24.04 bash 17 seconds ago Up 16 seconds 3300-3310/tcp webapp
|
||||
9ca9747b233100676a48cc7806131586213fa5dab86dd1972d6a8732e3a84a4d crosbymichael/redis:latest /redis-server --dir 33 minutes ago Up 33 minutes 6379/tcp redis,webapp/db
|
||||
```
|
||||
|
||||
@@ -240,13 +240,13 @@ CONTAINER ID IMAGE COMMAND CREATED
|
||||
919e1179bdb8 ubuntu-c1 "top" About a minute ago Up About a minute admiring_lovelace
|
||||
```
|
||||
|
||||
Match containers based on the `ubuntu` version `26.04` image:
|
||||
Match containers based on the `ubuntu` version `24.04` image:
|
||||
|
||||
```console
|
||||
$ docker ps --filter ancestor=ubuntu:26.04
|
||||
$ docker ps --filter ancestor=ubuntu:24.04
|
||||
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
82a598284012 ubuntu:26.04 "top" 3 minutes ago Up 3 minutes sleepy_bose
|
||||
82a598284012 ubuntu:24.04 "top" 3 minutes ago Up 3 minutes sleepy_bose
|
||||
```
|
||||
|
||||
The following matches containers based on the layer `d0e008c6cf02` or an image
|
||||
@@ -256,7 +256,7 @@ that have this layer in its layer stack.
|
||||
$ docker ps --filter ancestor=d0e008c6cf02
|
||||
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
82a598284012 ubuntu:26.04 "top" 3 minutes ago Up 3 minutes sleepy_bose
|
||||
82a598284012 ubuntu:24.04 "top" 3 minutes ago Up 3 minutes sleepy_bose
|
||||
```
|
||||
|
||||
#### Create time
|
||||
|
||||
@@ -66,18 +66,18 @@ docker.io/library/debian:latest
|
||||
Docker images can consist of multiple layers. In the example above, the image
|
||||
consists of a single layer; `e756f3fdd6a3`.
|
||||
|
||||
Layers can be reused by images. For example, the `debian:trixie` image shares
|
||||
its layer with the `debian:latest`. Pulling the `debian:trixie` image therefore
|
||||
Layers can be reused by images. For example, the `debian:bookworm` image shares
|
||||
its layer with the `debian:latest`. Pulling the `debian:bookworm` image therefore
|
||||
only pulls its metadata, but not its layers, because the layer is already present
|
||||
locally:
|
||||
|
||||
```console
|
||||
$ docker image pull debian:trixie
|
||||
$ docker image pull debian:bookworm
|
||||
|
||||
trixie: Pulling from library/debian
|
||||
bookworm: Pulling from library/debian
|
||||
Digest: sha256:3f1d6c17773a45c97bd8f158d665c9709d7b29ed7917ac934086ad96f92e4510
|
||||
Status: Downloaded newer image for debian:trixie
|
||||
docker.io/library/debian:trixie
|
||||
Status: Downloaded newer image for debian:bookworm
|
||||
docker.io/library/debian:bookworm
|
||||
```
|
||||
|
||||
To see which images are present locally, use the [`docker images`](image_ls.md)
|
||||
@@ -87,13 +87,13 @@ command:
|
||||
$ docker images
|
||||
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
debian trixie 4eacea30377a 8 days ago 124MB
|
||||
debian bookworm 4eacea30377a 8 days ago 124MB
|
||||
debian latest 4eacea30377a 8 days ago 124MB
|
||||
```
|
||||
|
||||
Docker uses a content-addressable image store, and the image ID is a SHA256
|
||||
digest covering the image's configuration and layers. In the example above,
|
||||
`debian:trixie` and `debian:latest` have the same image ID because they are
|
||||
`debian:bookworm` and `debian:latest` have the same image ID because they are
|
||||
the same image tagged with different names. Because they are the same image,
|
||||
their layers are stored only once and do not consume extra disk space.
|
||||
|
||||
@@ -106,8 +106,8 @@ refer to [understand images, containers, and storage drivers](https://docs.docke
|
||||
So far, you've pulled images by their name (and "tag"). Using names and tags is
|
||||
a convenient way to work with images. When using tags, you can `docker pull` an
|
||||
image again to make sure you have the most up-to-date version of that image.
|
||||
For example, `docker pull ubuntu:26.04` pulls the latest version of the Ubuntu
|
||||
26.04 image.
|
||||
For example, `docker pull ubuntu:24.04` pulls the latest version of the Ubuntu
|
||||
24.04 image.
|
||||
|
||||
In some cases you don't want images to be updated to newer versions, but prefer
|
||||
to use a fixed version of an image. Docker enables you to pull an image by its
|
||||
@@ -116,16 +116,16 @@ of an image to pull. Doing so, allows you to "pin" an image to that version,
|
||||
and guarantee that the image you're using is always the same.
|
||||
|
||||
To know the digest of an image, pull the image first. Let's pull the latest
|
||||
`ubuntu:26.04` image from Docker Hub:
|
||||
`ubuntu:24.04` image from Docker Hub:
|
||||
|
||||
```console
|
||||
$ docker pull ubuntu:26.04
|
||||
$ docker pull ubuntu:24.04
|
||||
|
||||
26.04: Pulling from library/ubuntu
|
||||
24.04: Pulling from library/ubuntu
|
||||
125a6e411906: Pull complete
|
||||
Digest: sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30
|
||||
Status: Downloaded newer image for ubuntu:26.04
|
||||
docker.io/library/ubuntu:26.04
|
||||
Status: Downloaded newer image for ubuntu:24.04
|
||||
docker.io/library/ubuntu:24.04
|
||||
```
|
||||
|
||||
Docker prints the digest of the image after the pull has finished. In the example
|
||||
@@ -213,11 +213,11 @@ shorthand) to see the images that were pulled. The example below shows all the
|
||||
```console
|
||||
$ docker image ls --filter reference=ubuntu
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
ubuntu 24.04 8a3cdc4d1ad3 3 weeks ago 77.9MB
|
||||
ubuntu noble 8a3cdc4d1ad3 3 weeks ago 77.9MB
|
||||
ubuntu 26.04 35a88802559d 6 weeks ago 78.1MB
|
||||
ubuntu 22.04 8a3cdc4d1ad3 3 weeks ago 77.9MB
|
||||
ubuntu jammy 8a3cdc4d1ad3 3 weeks ago 77.9MB
|
||||
ubuntu 24.04 35a88802559d 6 weeks ago 78.1MB
|
||||
ubuntu latest 35a88802559d 6 weeks ago 78.1MB
|
||||
ubuntu resolute 35a88802559d 6 weeks ago 78.1MB
|
||||
ubuntu noble 35a88802559d 6 weeks ago 78.1MB
|
||||
```
|
||||
|
||||
### Cancel a pull
|
||||
|
||||
@@ -180,12 +180,13 @@ code, and authenticate.
|
||||
```console
|
||||
$ docker login
|
||||
|
||||
Using web-based login. To sign in with credentials on the command line, use 'docker login -u <username>'
|
||||
USING WEB-BASED LOGIN
|
||||
To sign in with credentials on the command line, use 'docker login -u <username>'
|
||||
|
||||
Your one-time device confirmation code is: LNFR-PGCJ
|
||||
Open this URL to authenticate: https://login.docker.com/activate?user_code=LNFR-PGCJ
|
||||
Press ENTER to open your browser or submit your device code here: https://login.docker.com/activate
|
||||
|
||||
Press ENTER to open the URL in your browser, or Ctrl+C to cancel.
|
||||
Waiting for authentication in the browser…
|
||||
```
|
||||
|
||||
After entering the code in your browser, you are authenticated to Docker Hub
|
||||
|
||||
@@ -706,7 +706,7 @@ follows:
|
||||
| `node.platform.os` | Node operating system | `node.platform.os==windows` |
|
||||
| `node.platform.arch` | Node architecture | `node.platform.arch==x86_64` |
|
||||
| `node.labels` | User-defined node labels | `node.labels.security==high` |
|
||||
| `engine.labels` | Docker Engine's labels | `engine.labels.operatingsystem==ubuntu-26.04` |
|
||||
| `engine.labels` | Docker Engine's labels | `engine.labels.operatingsystem==ubuntu-24.04` |
|
||||
|
||||
`engine.labels` apply to Docker Engine labels like operating system, drivers,
|
||||
etc. Swarm administrators add `node.labels` for operational purposes by using
|
||||
|
||||
@@ -339,8 +339,8 @@ $ docker events --filter 'type=network'
|
||||
|
||||
$ docker events --filter 'container=container_1' --filter 'container=container_2'
|
||||
|
||||
2014-09-03T15:49:29.999999999Z07:00 container die 4386fb97867d (image=ubuntu:26.04)
|
||||
2014-05-10T17:42:14.999999999Z07:00 container stop 4386fb97867d (image=ubuntu:26.04)
|
||||
2014-09-03T15:49:29.999999999Z07:00 container die 4386fb97867d (image=ubuntu:24.04)
|
||||
2014-05-10T17:42:14.999999999Z07:00 container stop 4386fb97867d (image=ubuntu:24.04)
|
||||
2014-05-10T17:42:14.999999999Z07:00 container die 7805c1d35632 (imager=redis:7.2)
|
||||
2014-09-03T15:49:29.999999999Z07:00 container stop 7805c1d35632 (image=redis:7.2)
|
||||
|
||||
|
||||
+19
-19
@@ -35,7 +35,7 @@ reference to create or run a container based on an image.
|
||||
|
||||
An image tag is the image version, which defaults to `latest` when omitted. Use
|
||||
the tag to run a container from specific version of an image. For example, to
|
||||
run version `26.04` of the `ubuntu` image: `docker run ubuntu:26.04`.
|
||||
run version `24.04` of the `ubuntu` image: `docker run ubuntu:24.04`.
|
||||
|
||||
#### Image digests
|
||||
|
||||
@@ -406,14 +406,14 @@ We have four ways to set user memory usage:
|
||||
Examples:
|
||||
|
||||
```console
|
||||
$ docker run -it ubuntu:26.04 /bin/bash
|
||||
$ docker run -it ubuntu:24.04 /bin/bash
|
||||
```
|
||||
|
||||
We set nothing about memory, this means the processes in the container can use
|
||||
as much memory and swap memory as they need.
|
||||
|
||||
```console
|
||||
$ docker run -it -m 300M --memory-swap -1 ubuntu:26.04 /bin/bash
|
||||
$ docker run -it -m 300M --memory-swap -1 ubuntu:24.04 /bin/bash
|
||||
```
|
||||
|
||||
We set memory limit and disabled swap memory limit, this means the processes in
|
||||
@@ -421,7 +421,7 @@ the container can use 300M memory and as much swap memory as they need (if the
|
||||
host supports swap memory).
|
||||
|
||||
```console
|
||||
$ docker run -it -m 300M ubuntu:26.04 /bin/bash
|
||||
$ docker run -it -m 300M ubuntu:24.04 /bin/bash
|
||||
```
|
||||
|
||||
We set memory limit only, this means the processes in the container can use
|
||||
@@ -430,7 +430,7 @@ We set memory limit only, this means the processes in the container can use
|
||||
would be 2*300M, so processes can use 300M swap memory as well.
|
||||
|
||||
```console
|
||||
$ docker run -it -m 300M --memory-swap 1G ubuntu:26.04 /bin/bash
|
||||
$ docker run -it -m 300M --memory-swap 1G ubuntu:24.04 /bin/bash
|
||||
```
|
||||
|
||||
We set both memory and swap memory, so the processes in the container can use
|
||||
@@ -456,7 +456,7 @@ The following example limits the memory (`-m`) to 500M and sets the memory
|
||||
reservation to 200M.
|
||||
|
||||
```console
|
||||
$ docker run -it -m 500M --memory-reservation 200M ubuntu:26.04 /bin/bash
|
||||
$ docker run -it -m 500M --memory-reservation 200M ubuntu:24.04 /bin/bash
|
||||
```
|
||||
|
||||
Under this configuration, when the container consumes memory more than 200M and
|
||||
@@ -466,7 +466,7 @@ memory below 200M.
|
||||
The following example set memory reservation to 1G without a hard memory limit.
|
||||
|
||||
```console
|
||||
$ docker run -it --memory-reservation 1G ubuntu:26.04 /bin/bash
|
||||
$ docker run -it --memory-reservation 1G ubuntu:24.04 /bin/bash
|
||||
```
|
||||
|
||||
The container can use as much memory as it needs. The memory reservation setting
|
||||
@@ -484,13 +484,13 @@ The following example limits the memory to 100M and disables the OOM killer for
|
||||
this container:
|
||||
|
||||
```console
|
||||
$ docker run -it -m 100M --oom-kill-disable ubuntu:26.04 /bin/bash
|
||||
$ docker run -it -m 100M --oom-kill-disable ubuntu:24.04 /bin/bash
|
||||
```
|
||||
|
||||
The following example, illustrates a dangerous way to use the flag:
|
||||
|
||||
```console
|
||||
$ docker run -it --oom-kill-disable ubuntu:26.04 /bin/bash
|
||||
$ docker run -it --oom-kill-disable ubuntu:24.04 /bin/bash
|
||||
```
|
||||
|
||||
The container has unlimited memory which can cause the host to run out memory
|
||||
@@ -510,7 +510,7 @@ between 0 and 100. A value of 0 turns off anonymous page swapping. A value of
|
||||
For example, you can set:
|
||||
|
||||
```console
|
||||
$ docker run -it --memory-swappiness=0 ubuntu:26.04 /bin/bash
|
||||
$ docker run -it --memory-swappiness=0 ubuntu:24.04 /bin/bash
|
||||
```
|
||||
|
||||
Setting the `--memory-swappiness` option is helpful when you want to retain the
|
||||
@@ -561,7 +561,7 @@ And usually `--cpu-period` should work with `--cpu-quota`.
|
||||
Examples:
|
||||
|
||||
```console
|
||||
$ docker run -it --cpu-period=50000 --cpu-quota=25000 ubuntu:26.04 /bin/bash
|
||||
$ docker run -it --cpu-period=50000 --cpu-quota=25000 ubuntu:24.04 /bin/bash
|
||||
```
|
||||
|
||||
If there is 1 CPU, this means the container can get 50% CPU worth of run-time every 50ms.
|
||||
@@ -582,13 +582,13 @@ We can set cpus in which to allow execution for containers.
|
||||
Examples:
|
||||
|
||||
```console
|
||||
$ docker run -it --cpuset-cpus="1,3" ubuntu:26.04 /bin/bash
|
||||
$ docker run -it --cpuset-cpus="1,3" ubuntu:24.04 /bin/bash
|
||||
```
|
||||
|
||||
This means processes in container can be executed on cpu 1 and cpu 3.
|
||||
|
||||
```console
|
||||
$ docker run -it --cpuset-cpus="0-2" ubuntu:26.04 /bin/bash
|
||||
$ docker run -it --cpuset-cpus="0-2" ubuntu:24.04 /bin/bash
|
||||
```
|
||||
|
||||
This means processes in container can be executed on cpu 0, cpu 1 and cpu 2.
|
||||
@@ -599,14 +599,14 @@ on NUMA systems.
|
||||
Examples:
|
||||
|
||||
```console
|
||||
$ docker run -it --cpuset-mems="1,3" ubuntu:26.04 /bin/bash
|
||||
$ docker run -it --cpuset-mems="1,3" ubuntu:24.04 /bin/bash
|
||||
```
|
||||
|
||||
This example restricts the processes in the container to only use memory from
|
||||
memory nodes 1 and 3.
|
||||
|
||||
```console
|
||||
$ docker run -it --cpuset-mems="0-2" ubuntu:26.04 /bin/bash
|
||||
$ docker run -it --cpuset-mems="0-2" ubuntu:24.04 /bin/bash
|
||||
```
|
||||
|
||||
This example restricts the processes in the container to only use memory from
|
||||
@@ -637,8 +637,8 @@ For example, the commands below create two containers with different blkio
|
||||
weight:
|
||||
|
||||
```console
|
||||
$ docker run -it --name c1 --blkio-weight 300 ubuntu:26.04 /bin/bash
|
||||
$ docker run -it --name c2 --blkio-weight 600 ubuntu:26.04 /bin/bash
|
||||
$ docker run -it --name c1 --blkio-weight 300 ubuntu:24.04 /bin/bash
|
||||
$ docker run -it --name c2 --blkio-weight 600 ubuntu:24.04 /bin/bash
|
||||
```
|
||||
|
||||
If you do block IO in the two containers at the same time, by, for example:
|
||||
@@ -854,11 +854,11 @@ For interacting with the network stack, instead of using `--privileged` they
|
||||
should use `--cap-add=NET_ADMIN` to modify the network interfaces.
|
||||
|
||||
```console
|
||||
$ docker run -it --rm ubuntu:26.04 ip link add dummy0 type dummy
|
||||
$ docker run -it --rm ubuntu:24.04 ip link add dummy0 type dummy
|
||||
|
||||
RTNETLINK answers: Operation not permitted
|
||||
|
||||
$ docker run -it --rm --cap-add=NET_ADMIN ubuntu:26.04 ip link add dummy0 type dummy
|
||||
$ docker run -it --rm --cap-add=NET_ADMIN ubuntu:24.04 ip link add dummy0 type dummy
|
||||
```
|
||||
|
||||
To mount a FUSE based filesystem, you need to combine both `--cap-add` and
|
||||
|
||||
@@ -62,22 +62,6 @@ func TestNonexistingHelp(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestNonexistingVersion ensures correct behaviour when invoking a
|
||||
// nonexistent plugin with `--version`.
|
||||
func TestNonexistingVersion(t *testing.T) {
|
||||
run, _, cleanup := prepare(t)
|
||||
defer cleanup()
|
||||
|
||||
for _, flag := range []string{"--version", "-v"} {
|
||||
res := icmd.RunCmd(run("nonexistent", flag))
|
||||
res.Assert(t, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Out: icmd.None,
|
||||
})
|
||||
golden.Assert(t, res.Stderr(), "docker-nonexistent-err.golden")
|
||||
}
|
||||
}
|
||||
|
||||
// TestRunBad ensures correct behaviour when running an existent but invalid plugin
|
||||
func TestRunBad(t *testing.T) {
|
||||
run, _, cleanup := prepare(t)
|
||||
|
||||
@@ -30,5 +30,5 @@ func TestOauthLogin(t *testing.T) {
|
||||
assert.NilError(t, err)
|
||||
|
||||
output, _ := io.ReadAll(p)
|
||||
assert.Check(t, strings.Contains(string(output), "Using web-based login"), string(output))
|
||||
assert.Check(t, strings.Contains(string(output), "USING WEB-BASED LOGIN"), string(output))
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli/config/credentials"
|
||||
@@ -18,6 +17,8 @@ import (
|
||||
"github.com/docker/cli/internal/registry"
|
||||
"github.com/docker/cli/internal/tui"
|
||||
"github.com/morikuni/aec"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/pkg/browser"
|
||||
)
|
||||
|
||||
@@ -82,18 +83,19 @@ var ErrDeviceLoginStartFail = errors.New("failed to start device code flow login
|
||||
// The retrieved tokens are stored in the credentials store (under a separate
|
||||
// key), and the refresh token is concatenated with the client ID.
|
||||
func (m *OAuthManager) LoginDevice(ctx context.Context, w io.Writer) (*types.AuthConfig, error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
state, err := m.api.GetDeviceCode(ctx, m.audience)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %w", ErrDeviceLoginStartFail, err)
|
||||
logrus.Debugf("failed to start device code login: %v", err)
|
||||
return nil, ErrDeviceLoginStartFail
|
||||
}
|
||||
|
||||
if state.UserCode == "" {
|
||||
return nil, fmt.Errorf("%w: missing user code", ErrDeviceLoginStartFail)
|
||||
logrus.Debugf("failed to start device code login: missing user code")
|
||||
return nil, ErrDeviceLoginStartFail
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintln(w, aec.Bold.Apply("\nUSING WEB-BASED LOGIN"))
|
||||
|
||||
var out tui.Output
|
||||
switch stream := w.(type) {
|
||||
case *streams.Out:
|
||||
@@ -101,10 +103,9 @@ func (m *OAuthManager) LoginDevice(ctx context.Context, w io.Writer) (*types.Aut
|
||||
default:
|
||||
out = tui.NewOutput(streams.NewOut(w))
|
||||
}
|
||||
out.PrintNote("Using web-based login. To sign in with credentials on the command line, use 'docker login -u <username>'\n")
|
||||
_, _ = fmt.Fprintln(w, "Your one-time device confirmation code is:", aec.Bold.Apply(state.UserCode))
|
||||
_, _ = fmt.Fprintln(w, "Open this URL to authenticate:", aec.Underline.Apply(state.VerificationURI))
|
||||
_, _ = fmt.Fprintln(w, "\n"+aec.Bold.Apply("Press ENTER")+" to open the URL in your browser, or "+aec.Bold.Apply("Ctrl+C")+" to cancel.")
|
||||
out.PrintNote("To sign in with credentials on the command line, use 'docker login -u <username>'\n")
|
||||
_, _ = fmt.Fprintf(w, "\nYour one-time device confirmation code is: "+aec.Bold.Apply("%s\n"), state.UserCode)
|
||||
_, _ = fmt.Fprintf(w, aec.Bold.Apply("Press ENTER")+" to open your browser or submit your device code here: "+aec.Underline.Apply("%s\n"), strings.Split(state.VerificationURI, "?")[0])
|
||||
|
||||
tokenResChan := make(chan api.TokenResponse)
|
||||
waitForTokenErrChan := make(chan error)
|
||||
@@ -119,25 +120,11 @@ func (m *OAuthManager) LoginDevice(ctx context.Context, w io.Writer) (*types.Aut
|
||||
|
||||
go func() {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
if _, err := reader.ReadString('\n'); err != nil || ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
err := m.openBrowser(state.VerificationURI)
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
if errors.Is(err, exec.ErrNotFound) {
|
||||
_, _ = fmt.Fprintln(w, "No browser found. Open the URL above manually to continue.")
|
||||
} else {
|
||||
_, _ = fmt.Fprintln(w, "Failed to open browser:", err)
|
||||
_, _ = fmt.Fprintln(w, "Open the URL above manually to continue.")
|
||||
}
|
||||
return
|
||||
}
|
||||
_, _ = fmt.Fprintln(w, "\nOpening browser…")
|
||||
_, _ = reader.ReadString('\n')
|
||||
_ = m.openBrowser(state.VerificationURI)
|
||||
}()
|
||||
|
||||
_, _ = fmt.Fprint(w, "\nWaiting for authentication in the browser…\n")
|
||||
var tokenRes api.TokenResponse
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
|
||||
@@ -69,10 +69,10 @@ func getHTTPTransport(authConfig registrytypes.AuthConfig, endpoint registry.API
|
||||
// get the http transport, this will be used in a client to upload manifest
|
||||
base := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: (&net.Dialer{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).DialContext,
|
||||
}).Dial,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
TLSClientConfig: endpoint.TLSConfig,
|
||||
DisableKeepAlives: true,
|
||||
|
||||
@@ -27,13 +27,8 @@ func TerminatePrompt(ctx context.Context, t *testing.T, cmd *cobra.Command, cli
|
||||
}))
|
||||
cli.SetOut(outStream)
|
||||
|
||||
r, w, err := os.Pipe()
|
||||
r, _, err := os.Pipe()
|
||||
assert.NilError(t, err)
|
||||
t.Cleanup(func() {
|
||||
_ = w.Close()
|
||||
_ = r.Close()
|
||||
})
|
||||
|
||||
cli.SetIn(streams.NewIn(r))
|
||||
|
||||
notifyCtx, notifyCancel := context.WithCancel(ctx)
|
||||
@@ -63,6 +58,8 @@ func TerminatePrompt(ctx context.Context, t *testing.T, cmd *cobra.Command, cli
|
||||
}()
|
||||
}
|
||||
|
||||
assert.Check(t, cli.OutBuffer().Len() > 0)
|
||||
|
||||
// a small delay to ensure the plugin is prompting
|
||||
time.Sleep(100 * time.Microsecond)
|
||||
|
||||
|
||||
+6
-14
@@ -83,24 +83,16 @@ set as the **URL**, the repository is cloned locally and then sent as the contex
|
||||
Add a line to /etc/hosts. The format is hostname=ip, or hostname:ip.
|
||||
The **--add-host** option can be set multiple times.
|
||||
|
||||
**--build-arg** *name*[=*value*]
|
||||
Set a build-time variable. The *name* is the variable name, as declared
|
||||
by an `ARG` instruction in the Dockerfile. If *value* is omitted, the
|
||||
value of the variable *name* from the local environment is used; if it is
|
||||
not set there either, the default from the `ARG` instruction (if any) is
|
||||
used.
|
||||
|
||||
Build-time variables are available as environment variables to commands
|
||||
run by the Dockerfile's `RUN` instructions, and can be used for variable
|
||||
expansion in other Dockerfile instructions. An environment variable defined
|
||||
by an `ENV` instruction always overrides an `ARG` of the same name. This
|
||||
mechanism is not meant for passing secret values.
|
||||
**--build-arg** *variable*
|
||||
name and value of a **buildarg**.
|
||||
|
||||
For example, if you want to pass a value for `http_proxy`, use
|
||||
`--build-arg=http_proxy="http://some.proxy.url"`
|
||||
|
||||
See also https://docs.docker.com/reference/dockerfile/#arg and
|
||||
https://docs.docker.com/reference/cli/docker/buildx/build/#build-arg.
|
||||
Users pass these values at build-time. Docker uses the `buildargs` as the
|
||||
environment context for command(s) run via the Dockerfile's `RUN` instruction
|
||||
or for variable expansion in other Dockerfile instructions. This is not meant
|
||||
for passing secret values. [Read more about the buildargs instruction](https://docs.docker.com/engine/reference/builder/#arg)
|
||||
|
||||
**--cache-from** ""
|
||||
Set image that will be used as a build cache source.
|
||||
|
||||
@@ -48,10 +48,10 @@ Valid placeholders for the Go template are listed below:
|
||||
|
||||
$ docker container ls -a
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
a87ecb4f327c ubuntu:26.04 /bin/sh -c #(nop) MA 20 minutes ago Exit 0 desperate_brattain
|
||||
a87ecb4f327c ubuntu:24.04 /bin/sh -c #(nop) MA 20 minutes ago Exit 0 desperate_brattain
|
||||
01946d9d34d8 busybox /bin/sh -c #(nop) MA 33 minutes ago Exit 0 thirsty_bell
|
||||
c1d3b0166030 acffc0358b9e /bin/sh -c yum -y up 2 weeks ago Exit 1 determined_torvalds
|
||||
41d50ecd2f57 ubuntu:26.04 /bin/sh -c #(nop) MA 2 weeks ago Exit 0 drunk_pike
|
||||
41d50ecd2f57 ubuntu:24.04 /bin/sh -c #(nop) MA 2 weeks ago Exit 0 drunk_pike
|
||||
|
||||
## Display only IDs of all containers, including non-running
|
||||
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ The title REPOSITORY for the first title may seem confusing. It is essentially
|
||||
the image name. However, because you can tag a specific image, and multiple tags
|
||||
(image instances) can be associated with a single name, the name is really a
|
||||
repository for all tagged images of the same name. For example consider an image
|
||||
called ubuntu. It may be tagged with 26.04 or 24.04, etc. to manage different
|
||||
called ubuntu. It may be tagged with 24.04 or 22.04, etc. to manage different
|
||||
versions.
|
||||
|
||||
## Filters
|
||||
|
||||
+19
-19
@@ -27,17 +27,17 @@ Docker Engine uses the `:latest` tag as a default. This example pulls the
|
||||
Docker images can consist of multiple layers. In the example above, the image
|
||||
consists of a single layer; `e756f3fdd6a3`.
|
||||
|
||||
Layers can be reused by images. For example, the `debian:trixie` image shares
|
||||
its layer with the `debian:latest`. Pulling the `debian:trixie` image therefore
|
||||
Layers can be reused by images. For example, the `debian:bookworm` image shares
|
||||
its layer with the `debian:latest`. Pulling the `debian:bookworm` image therefore
|
||||
only pulls its metadata, but not its layers, because the layer is already present
|
||||
locally:
|
||||
|
||||
$ docker image pull debian:trixie
|
||||
$ docker image pull debian:bookworm
|
||||
|
||||
trixie: Pulling from library/debian
|
||||
bookworm: Pulling from library/debian
|
||||
Digest: sha256:3f1d6c17773a45c97bd8f158d665c9709d7b29ed7917ac934086ad96f92e4510
|
||||
Status: Downloaded newer image for debian:trixie
|
||||
docker.io/library/debian:trixie
|
||||
Status: Downloaded newer image for debian:bookworm
|
||||
docker.io/library/debian:bookworm
|
||||
|
||||
To see which images are present locally, use the **docker-images(1)**
|
||||
command:
|
||||
@@ -45,12 +45,12 @@ command:
|
||||
$ docker images
|
||||
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
debian trixie 4eacea30377a 8 days ago 124MB
|
||||
debian bookworm 4eacea30377a 8 days ago 124MB
|
||||
debian latest 4eacea30377a 8 days ago 124MB
|
||||
|
||||
Docker uses a content-addressable image store, and the image ID is a SHA256
|
||||
digest covering the image's configuration and layers. In the example above,
|
||||
`debian:trixie` and `debian:latest` have the same image ID because they are
|
||||
`debian:bookworm` and `debian:latest` have the same image ID because they are
|
||||
the *same* image tagged with different names. Because they are the same image,
|
||||
their layers are stored only once and do not consume extra disk space.
|
||||
|
||||
@@ -64,8 +64,8 @@ in the online documentation.
|
||||
So far, you've pulled images by their name (and "tag"). Using names and tags is
|
||||
a convenient way to work with images. When using tags, you can `docker image pull` an
|
||||
image again to make sure you have the most up-to-date version of that image.
|
||||
For example, `docker image pull ubuntu:26.04` pulls the latest version of the Ubuntu
|
||||
26.04 image.
|
||||
For example, `docker image pull ubuntu:24.04` pulls the latest version of the Ubuntu
|
||||
24.04 image.
|
||||
|
||||
In some cases you don't want images to be updated to newer versions, but prefer
|
||||
to use a fixed version of an image. Docker enables you to pull an image by its
|
||||
@@ -74,15 +74,15 @@ of an image to pull. Doing so, allows you to "pin" an image to that version,
|
||||
and guarantee that the image you're using is always the same.
|
||||
|
||||
To know the digest of an image, pull the image first. Let's pull the latest
|
||||
`ubuntu:26.04` image from Docker Hub:
|
||||
`ubuntu:24.04` image from Docker Hub:
|
||||
|
||||
$ docker image pull ubuntu:26.04
|
||||
$ docker image pull ubuntu:24.04
|
||||
|
||||
26.04: Pulling from library/ubuntu
|
||||
24.04: Pulling from library/ubuntu
|
||||
125a6e411906: Pull complete
|
||||
Digest: sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30
|
||||
Status: Downloaded newer image for ubuntu:26.04
|
||||
docker.io/library/ubuntu:26.04
|
||||
Status: Downloaded newer image for ubuntu:24.04
|
||||
docker.io/library/ubuntu:24.04
|
||||
|
||||
Docker prints the digest of the image after the pull has finished. In the example
|
||||
above, the digest of the image is:
|
||||
@@ -159,11 +159,11 @@ images that are present locally:
|
||||
|
||||
$ docker image ls --filter reference=ubuntu
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
ubuntu 24.04 8a3cdc4d1ad3 3 weeks ago 77.9MB
|
||||
ubuntu noble 8a3cdc4d1ad3 3 weeks ago 77.9MB
|
||||
ubuntu 26.04 35a88802559d 6 weeks ago 78.1MB
|
||||
ubuntu 22.04 8a3cdc4d1ad3 3 weeks ago 77.9MB
|
||||
ubuntu jammy 8a3cdc4d1ad3 3 weeks ago 77.9MB
|
||||
ubuntu 24.04 35a88802559d 6 weeks ago 78.1MB
|
||||
ubuntu latest 35a88802559d 6 weeks ago 78.1MB
|
||||
ubuntu resolute 35a88802559d 6 weeks ago 78.1MB
|
||||
ubuntu noble 35a88802559d 6 weeks ago 78.1MB
|
||||
|
||||
## Cancel a pull
|
||||
|
||||
|
||||
@@ -62,8 +62,8 @@ The following example outputs all events that were generated in the last 3 minut
|
||||
relative to the current time on the client machine:
|
||||
|
||||
# docker events --since '3m'
|
||||
2015-05-12T11:51:30.999999999Z07:00 4386fb97867d: (from ubuntu:26.04) die
|
||||
2015-05-12T15:52:12.999999999Z07:00 4386fb97867d: (from ubuntu:26.04) stop
|
||||
2015-05-12T11:51:30.999999999Z07:00 4386fb97867d: (from ubuntu:24.04) die
|
||||
2015-05-12T15:52:12.999999999Z07:00 4386fb97867d: (from ubuntu:24.04) stop
|
||||
2015-05-12T15:53:45.999999999Z07:00 7805c1d35632: (from redis:7.2) die
|
||||
2015-05-12T15:54:03.999999999Z07:00 7805c1d35632: (from redis:7.2) stop
|
||||
|
||||
@@ -97,21 +97,21 @@ Lines. For information about JSON Lines, refer to https://jsonlines.org .
|
||||
## Filters
|
||||
|
||||
$ docker events --filter 'event=stop'
|
||||
2014-05-10T17:42:14.999999999Z07:00 container stop 4386fb97867d (image=ubuntu:26.04)
|
||||
2014-05-10T17:42:14.999999999Z07:00 container stop 4386fb97867d (image=ubuntu:24.04)
|
||||
2014-09-03T17:42:14.999999999Z07:00 container stop 7805c1d35632 (image=redis:7.2)
|
||||
|
||||
$ docker events --filter 'image=ubuntu:26.04'
|
||||
2014-05-10T17:42:14.999999999Z07:00 container start 4386fb97867d (image=ubuntu:26.04)
|
||||
2014-05-10T17:42:14.999999999Z07:00 container die 4386fb97867d (image=ubuntu:26.04)
|
||||
2014-05-10T17:42:14.999999999Z07:00 container stop 4386fb97867d (image=ubuntu:26.04)
|
||||
$ docker events --filter 'image=ubuntu:24.04'
|
||||
2014-05-10T17:42:14.999999999Z07:00 container start 4386fb97867d (image=ubuntu:24.04)
|
||||
2014-05-10T17:42:14.999999999Z07:00 container die 4386fb97867d (image=ubuntu:24.04)
|
||||
2014-05-10T17:42:14.999999999Z07:00 container stop 4386fb97867d (image=ubuntu:24.04)
|
||||
|
||||
$ docker events --filter 'container=7805c1d35632'
|
||||
2014-05-10T17:42:14.999999999Z07:00 container die 7805c1d35632 (image=redis:7.2)
|
||||
2014-09-03T15:49:29.999999999Z07:00 container stop 7805c1d35632 (image= redis:7.2)
|
||||
|
||||
$ docker events --filter 'container=7805c1d35632' --filter 'container=4386fb97867d'
|
||||
2014-09-03T15:49:29.999999999Z07:00 container die 4386fb97867d (image=ubuntu:26.04)
|
||||
2014-05-10T17:42:14.999999999Z07:00 container stop 4386fb97867d (image=ubuntu:26.04)
|
||||
2014-09-03T15:49:29.999999999Z07:00 container die 4386fb97867d (image=ubuntu:24.04)
|
||||
2014-05-10T17:42:14.999999999Z07:00 container stop 4386fb97867d (image=ubuntu:24.04)
|
||||
2014-05-10T17:42:14.999999999Z07:00 container die 7805c1d35632 (image=redis:7.2)
|
||||
2014-09-03T15:49:29.999999999Z07:00 container stop 7805c1d35632 (image=redis:7.2)
|
||||
|
||||
|
||||
@@ -71,8 +71,8 @@ Server:
|
||||
seccomp
|
||||
Profile: builtin
|
||||
cgroupns
|
||||
Kernel Version: 6.8.0-31-generic
|
||||
Operating System: Ubuntu 24.04 LTS
|
||||
Kernel Version: 5.15.0-25-generic
|
||||
Operating System: Ubuntu 22.04 LTS
|
||||
OSType: linux
|
||||
Architecture: x86_64
|
||||
CPUs: 1
|
||||
|
||||
@@ -88,20 +88,13 @@ if [ "$CGO_ENABLED" = "1" ] && [ "$(go env GOOS)" != "windows" ]; then
|
||||
fi
|
||||
export GO_BUILDMODE
|
||||
|
||||
# Omit DWARF debug information to reduce binary size, but retain the symbol
|
||||
# table for tools that inspect Go binaries. Pass GO_LDFLAGS="-w=0" to retain DWARF.
|
||||
GO_LDFLAGS="-w ${GO_LDFLAGS:-}"
|
||||
|
||||
# Quotes are interpreted by Go's -ldflags parser, not the shell.
|
||||
# shellcheck disable=SC2089
|
||||
{
|
||||
GO_LDFLAGS="$GO_LDFLAGS -X \"github.com/docker/cli/cli/version.GitCommit=${GITCOMMIT}\""
|
||||
GO_LDFLAGS="$GO_LDFLAGS -X \"github.com/docker/cli/cli/version.BuildTime=${BUILDTIME}\""
|
||||
GO_LDFLAGS="$GO_LDFLAGS -X \"github.com/docker/cli/cli/version.Version=${VERSION}\""
|
||||
if test -n "${PLATFORM}"; then
|
||||
GO_LDFLAGS="$GO_LDFLAGS -X \"github.com/docker/cli/cli/version.PlatformName=${PLATFORM}\""
|
||||
fi
|
||||
}
|
||||
GO_LDFLAGS="${GO_LDFLAGS:-}"
|
||||
GO_LDFLAGS="$GO_LDFLAGS -X \"github.com/docker/cli/cli/version.GitCommit=${GITCOMMIT}\""
|
||||
GO_LDFLAGS="$GO_LDFLAGS -X \"github.com/docker/cli/cli/version.BuildTime=${BUILDTIME}\""
|
||||
GO_LDFLAGS="$GO_LDFLAGS -X \"github.com/docker/cli/cli/version.Version=${VERSION}\""
|
||||
if test -n "${PLATFORM}"; then
|
||||
GO_LDFLAGS="$GO_LDFLAGS -X \"github.com/docker/cli/cli/version.PlatformName=${PLATFORM}\""
|
||||
fi
|
||||
if [ "$CGO_ENABLED" = "1" ] && [ "$GO_LINKMODE" = "static" ] && [ "$(go env GOOS)" = "linux" ]; then
|
||||
GO_LDFLAGS="$GO_LDFLAGS -linkmode external -extldflags -static"
|
||||
fi
|
||||
@@ -135,7 +128,7 @@ if [ -n "$GO_STRIP" ]; then
|
||||
# /usr/local/go/pkg/tool/linux_amd64/link: /usr/local/go/pkg/tool/linux_amd64/link: running strip failed: exit status 1
|
||||
# llvm-strip: error: unsupported load command (cmd=0x5)
|
||||
# more info: https://github.com/docker/cli/pull/3717
|
||||
GO_LDFLAGS="$GO_LDFLAGS -s"
|
||||
GO_LDFLAGS="$GO_LDFLAGS -s -w"
|
||||
fi
|
||||
export GO_LDFLAGS="$GO_LDFLAGS" # https://github.com/koalaman/shellcheck/issues/2064
|
||||
|
||||
|
||||
+27
-28
@@ -21,11 +21,11 @@ require (
|
||||
github.com/distribution/reference v0.6.0
|
||||
github.com/docker/cli-docs-tool v0.11.0
|
||||
github.com/docker/distribution v2.8.3+incompatible
|
||||
github.com/docker/docker-credential-helpers v0.9.12
|
||||
github.com/docker/docker-credential-helpers v0.9.9
|
||||
github.com/docker/go-connections v0.8.2
|
||||
github.com/docker/go-units v0.5.0
|
||||
github.com/fvbommel/sortorder v1.2.1
|
||||
github.com/go-jose/go-jose/v4 v4.1.7
|
||||
github.com/fvbommel/sortorder v1.2.0
|
||||
github.com/go-jose/go-jose/v4 v4.1.5
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/google/go-cmp v0.7.0
|
||||
@@ -33,12 +33,12 @@ require (
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/mattn/go-runewidth v0.0.31
|
||||
github.com/moby/go-archive v0.3.3
|
||||
github.com/moby/moby/api v1.56.2-0.20261106011722-402d0a16f131
|
||||
github.com/moby/moby/client v0.6.3-0.20261106011722-402d0a16f131
|
||||
github.com/moby/moby/api v1.56.1
|
||||
github.com/moby/moby/client v0.6.2
|
||||
github.com/moby/patternmatcher v0.6.1
|
||||
github.com/moby/swarmkit/v2 v2.1.3
|
||||
github.com/moby/swarmkit/v2 v2.1.2
|
||||
github.com/moby/sys/atomicwriter v0.1.0
|
||||
github.com/moby/sys/capability v0.5.0
|
||||
github.com/moby/sys/capability v0.4.0
|
||||
github.com/moby/sys/sequential v0.7.0
|
||||
github.com/moby/sys/signal v0.7.1
|
||||
github.com/moby/sys/symlink v0.3.0
|
||||
@@ -52,25 +52,25 @@ require (
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/spf13/pflag v1.0.10
|
||||
github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.72.0
|
||||
go.opentelemetry.io/otel v1.47.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.47.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.47.0
|
||||
go.opentelemetry.io/otel/metric v1.47.0
|
||||
go.opentelemetry.io/otel/sdk v1.47.0
|
||||
go.opentelemetry.io/otel/sdk/metric v1.47.0
|
||||
go.opentelemetry.io/otel/trace v1.47.0
|
||||
go.yaml.in/yaml/v3 v3.0.6
|
||||
golang.org/x/sync v0.24.0
|
||||
golang.org/x/sys v0.49.1-0.20261022125458-f5cb0306ac0e // includes fix for https://go.dev/issue/82324
|
||||
golang.org/x/term v0.47.0
|
||||
golang.org/x/text v0.43.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0
|
||||
go.opentelemetry.io/otel v1.46.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.46.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.46.0
|
||||
go.opentelemetry.io/otel/metric v1.46.0
|
||||
go.opentelemetry.io/otel/sdk v1.46.0
|
||||
go.opentelemetry.io/otel/sdk/metric v1.46.0
|
||||
go.opentelemetry.io/otel/trace v1.46.0
|
||||
go.yaml.in/yaml/v3 v3.0.5
|
||||
golang.org/x/sync v0.23.0
|
||||
golang.org/x/sys v0.48.0
|
||||
golang.org/x/term v0.46.0
|
||||
golang.org/x/text v0.42.0
|
||||
gotest.tools/v3 v3.5.2
|
||||
tags.cncf.io/container-device-interface v1.1.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ansiterm v0.0.0-20261013165250-51075c6ea6bc // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20261006220739-8c912ac31dd4 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.3 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
@@ -87,7 +87,7 @@ require (
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.20.2 // indirect
|
||||
github.com/klauspost/compress v1.20.1 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/sys/user v0.4.1 // indirect
|
||||
github.com/moby/sys/userns v0.2.1 // indirect
|
||||
@@ -99,14 +99,13 @@ require (
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
go.etcd.io/raft/v3 v3.6.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.47.0 // indirect
|
||||
go.opentelemetry.io/otel/log v1.47.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.11.0 // indirect
|
||||
golang.org/x/mod v0.42.0 // indirect
|
||||
golang.org/x/net v0.62.0 // indirect
|
||||
golang.org/x/mod v0.41.0 // indirect
|
||||
golang.org/x/net v0.60.0 // indirect
|
||||
golang.org/x/time v0.16.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260928230214-8a89bd6388cc // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260928230214-8a89bd6388cc // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260825221802-da73d73af1c5 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5 // indirect
|
||||
google.golang.org/grpc v1.83.2 // indirect
|
||||
google.golang.org/protobuf v1.36.12 // indirect
|
||||
)
|
||||
|
||||
+58
-58
@@ -2,8 +2,8 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
|
||||
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20261013165250-51075c6ea6bc h1:58s5YzGPNAP7+e1uemaL0ax/NPSeJOHdRpRIowd+JDk=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20261013165250-51075c6ea6bc/go.mod h1:DMNF6Kxv+EcuUvVuNkvC3f+BjEEmc/Fn9aU+qiD8zpU=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20261006220739-8c912ac31dd4 h1:m2xcjRABtG288vnlV3U/PKh/HnPURxZp50RKNUwBxM8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20261006220739-8c912ac31dd4/go.mod h1:MTUE7ZuZO89FAtAwozGg6AWD83pcdefnEq5gF82MB8s=
|
||||
github.com/Microsoft/go-winio v0.6.3 h1:M/52tsoyTfwaxajLnXZm7PqkbMGRH8iSWP+8fcg9MQ4=
|
||||
github.com/Microsoft/go-winio v0.6.3/go.mod h1:ma0QpxizD4fyyzJ1C7MIblymTD2Nxz5Mho/3CepwIZg=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
@@ -35,8 +35,8 @@ github.com/docker/cli-docs-tool v0.11.0 h1:7d8QARFb7QEobizqxmEM7fOteZEHwH/zWgHQt
|
||||
github.com/docker/cli-docs-tool v0.11.0/go.mod h1:ma8BKiisUo8D6W05XEYIh3oa1UbgrZhi1nowyKFJa8Q=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker-credential-helpers v0.9.12 h1:hAgjJcMuC17DPf0Kl/HQSZQ7cxVo+wEA8Oo1SzkmqFg=
|
||||
github.com/docker/docker-credential-helpers v0.9.12/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
|
||||
github.com/docker/docker-credential-helpers v0.9.9 h1:BkydjIgZ46JnDbqyM2p2fc63KMw6y+KHL3Em/2AGJ7w=
|
||||
github.com/docker/docker-credential-helpers v0.9.9/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
|
||||
github.com/docker/go-connections v0.8.2 h1:9d9DEokx5W7qlr0shkFXIxEA7+TTD+llwzcykSlxMNc=
|
||||
github.com/docker/go-connections v0.8.2/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q=
|
||||
github.com/docker/go-events v0.1.0 h1:J8VX4H7Ta8mmBhv/K/24x1kosKOrEEnYmGjcdFHTOW0=
|
||||
@@ -49,10 +49,10 @@ github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
||||
github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc=
|
||||
github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE=
|
||||
github.com/fvbommel/sortorder v1.2.1 h1:ASc85RbthwLEqzuiCk7WQQiopfyGWQiEYZVJ3Qa4A+U=
|
||||
github.com/fvbommel/sortorder v1.2.1/go.mod h1:LbhO04ijZIeUuvz9B9BkI/qYrpZZEn1gWhxv4QjUKVs=
|
||||
github.com/go-jose/go-jose/v4 v4.1.7 h1:Nac/98uT5LPkfbiFuYa8ktf62a2VxwQ4xbq1GK8pV5E=
|
||||
github.com/go-jose/go-jose/v4 v4.1.7/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||
github.com/fvbommel/sortorder v1.2.0 h1:TRIiRiGX+djh3Yf4FVxmWmAcYfIr5dH0NbzJWOSAWZk=
|
||||
github.com/fvbommel/sortorder v1.2.0/go.mod h1:LbhO04ijZIeUuvz9B9BkI/qYrpZZEn1gWhxv4QjUKVs=
|
||||
github.com/go-jose/go-jose/v4 v4.1.5 h1:RjgjO2LOtWOJKUC5wpwY9LR3B3vwVAz6JS2YHfYU6eA=
|
||||
github.com/go-jose/go-jose/v4 v4.1.5/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
|
||||
github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
@@ -78,8 +78,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.20.2 h1:v5tiZvm1KGLyg5d5oXdXe3lsSPrbEUiKoXGia//I7Qo=
|
||||
github.com/klauspost/compress v1.20.2/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
|
||||
github.com/klauspost/compress v1.20.1 h1:T7kKElXUMXrUJ2E9QhQhxFtcK5rPyLdsGZvdbLMPdiQ=
|
||||
github.com/klauspost/compress v1.20.1/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/mattn/go-runewidth v0.0.31 h1:1oCV4ReTlosDBc6rYRw5cL8S/4y8iv5oRl4SJ5IBgwo=
|
||||
@@ -88,18 +88,18 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/go-archive v0.3.3 h1:OxxR9paxsluYi+zDUEXTTaIxtkK3viymW+Ka7vRhhME=
|
||||
github.com/moby/go-archive v0.3.3/go.mod h1:Npdv43fFqlhZW7Xo8fbm3ZMYFvAGNviUPqX21VERbcE=
|
||||
github.com/moby/moby/api v1.56.2-0.20261106011722-402d0a16f131 h1:tPz9ahj8F7AjQw62XQFP65kmoxF3rXTYSit3q06/yQc=
|
||||
github.com/moby/moby/api v1.56.2-0.20261106011722-402d0a16f131/go.mod h1:pRZ1QRtx6AVhdckeFYo4DUX4ASNF0SCllhyY6aj2mgg=
|
||||
github.com/moby/moby/client v0.6.3-0.20261106011722-402d0a16f131 h1:ReIO7lalQVE4BetZuIvrxScg8Rxv4Sk74XRs06ryRDU=
|
||||
github.com/moby/moby/client v0.6.3-0.20261106011722-402d0a16f131/go.mod h1:dPyRteJDuLdP8to3kWmNAU/tbMwSFCE88yKHvY/nZ9k=
|
||||
github.com/moby/moby/api v1.56.1 h1:PpWkvVPB7Fr/No8w+TfyJ/I6rWZ2YPZhT3JorIg+06c=
|
||||
github.com/moby/moby/api v1.56.1/go.mod h1:sZ+THbVWkjOmBPPfbnzdD/G1LuIexWhqlSHHPTDQ1Uk=
|
||||
github.com/moby/moby/client v0.6.2 h1:ekSPlMccrZGcw6Scb8T9D39qE0mB+XupU/yS0zNw9N4=
|
||||
github.com/moby/moby/client v0.6.2/go.mod h1:DGcnO7qmPJrqobx/ggQgQ/AUk+2wgVdQv7uxB0/mEsc=
|
||||
github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U=
|
||||
github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||
github.com/moby/swarmkit/v2 v2.1.3 h1:UcwtwkIRjr75qSgUWCTIuzKUzAXlidxsiqVMnyxSF1w=
|
||||
github.com/moby/swarmkit/v2 v2.1.3/go.mod h1:KhkxT93Hm4wHoNUPJ4JRD384pS7OODFGzJWoDRj9bLE=
|
||||
github.com/moby/swarmkit/v2 v2.1.2 h1:1WDZAI6HVYNKdCG4zlXnTAPyLsLwuhRGWlHoOUf5Z6I=
|
||||
github.com/moby/swarmkit/v2 v2.1.2/go.mod h1:GQ6T0ij2oBbWX10OHwpvK449xfXkQMZ8J+B+eQ4mgp4=
|
||||
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
||||
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
|
||||
github.com/moby/sys/capability v0.5.0 h1:Bm4oD9xGCtZguPnaoQy1/jvKTSwZHMvM0FrnxNYtGYU=
|
||||
github.com/moby/sys/capability v0.5.0/go.mod h1:i+0cXvNSriGrL3C6sxnmlmGL5HVU0OdxocizXdC8A+g=
|
||||
github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk=
|
||||
github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I=
|
||||
github.com/moby/sys/mount v0.3.5 h1:eS3fsZTjHaBihwjp4/+5Z3jxqLXYsbwxqpVSfFv3M00=
|
||||
github.com/moby/sys/mount v0.3.5/go.mod h1:WUQDO+/uCiCIkIztx8SrwIDVn2dtMFRBebRhpDFT71M=
|
||||
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
|
||||
@@ -155,65 +155,63 @@ go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ=
|
||||
go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.72.0 h1:LxwW/9ctSCv+QkE/cLR7M91ZIkXNMqJtEMi1vCw9U8s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.72.0/go.mod h1:tOsftB4SslBwwErVEPaenU2RpThXWPIU8DoJHEC4dyw=
|
||||
go.opentelemetry.io/otel v1.47.0 h1:j7ALJ/zgkS7Z6aeJW09p8VC9804bC+PpeTfCD4XPnOM=
|
||||
go.opentelemetry.io/otel v1.47.0/go.mod h1:8wS9O2qfXrYrzp6hIF/HOYJJf/wIhFPhR2xLuP+iXQU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.47.0 h1:LaLVGJtIzHcvHjVs2OftmKcc+M9mdOqS8vZ1fBD1Yes=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.47.0/go.mod h1:vF6H5sNDuQBJWgSX00iZgbIqk2MZZoVMH0ar5t5bOpw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.47.0 h1:julhjPeUH/q/7hinbSdDdqt5h7Zw9YWmRlWRhI0jd54=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.47.0/go.mod h1:Ao2mz688LH/tFf0yMAenidq6k2YNSx6SIY2q6jDACck=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.47.0 h1:UFpxOpYPmMNUtOWhdb+nC1WELIgVf8z9higURrbzYU4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.47.0/go.mod h1:YBGjxe3lt0jtXoEXxGrGhv/jM7oUBUDVK7zhAvNyEjc=
|
||||
go.opentelemetry.io/otel/log v1.47.0 h1:cOTS1CcLbSQeZKanGJ+0JpF/+t4PELi3O3bbl2lqCcI=
|
||||
go.opentelemetry.io/otel/log v1.47.0/go.mod h1:9byitSQ5pLC6PpqwGXjqdMKya6ZTswHRZh2vvXT33nw=
|
||||
go.opentelemetry.io/otel/metric v1.47.0 h1:4PptaldXx3Eat1XjMZ68pPJEs5wrhlemctZE9a3UdWY=
|
||||
go.opentelemetry.io/otel/metric v1.47.0/go.mod h1:ADGSXxRrXM6bjbvLo535EstVFlPpPYZm4LBKixjDHwU=
|
||||
go.opentelemetry.io/otel/metric/x v0.69.0 h1:DjRLr15H83v+hCW7JA9NoJvOkYTtmq5YoDRbe9deYpM=
|
||||
go.opentelemetry.io/otel/metric/x v0.69.0/go.mod h1:uVvsMPMFFyj/HUQfrUnH3JjnOQ1dwFDorgFLRBasM0k=
|
||||
go.opentelemetry.io/otel/sdk v1.47.0 h1:zWXEr4j2lFefG87TU6Yg8a7ngfohIKFZHKp0Hf5hC6I=
|
||||
go.opentelemetry.io/otel/sdk v1.47.0/go.mod h1:VUc24kiOeoGsxG8G9ULx3fWKvB7jMhnGE8Oi607lgR0=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.47.0 h1:lfISg2j93VT6yqdk9OfUaZmw/GfcZqCCV3jdXtsPnKw=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.47.0/go.mod h1:ypLp+mW1Nt2x+Szt3b5/i1syodyts49lMOwxpDI3VGw=
|
||||
go.opentelemetry.io/otel/trace v1.47.0 h1:JOjX/Oci8K94QHddo+bbfya/Ai/nf6/dt9ZfrFNWSrM=
|
||||
go.opentelemetry.io/otel/trace v1.47.0/go.mod h1:jNaSLa2PZEYFG6fRjJABAu+bw4FS08uDmPg28lTghu0=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 h1:3g7B90UzBltIDKq1/5mrTGxTnOFDV0ICOhLoxiZ8jlg=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0/go.mod h1:Ef8SuTh59BT7+ofpDxN9z+yOlc4t2GjLmKDgYNJL/NU=
|
||||
go.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc=
|
||||
go.opentelemetry.io/otel v1.46.0/go.mod h1:Gj3SEScelsNC45tp4nSxRYlS+f5iez7W8XPMCt905kE=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.46.0 h1:qkDYCAFiZXLcs1L4aY+tP2wguQ4kURANqHOQMA2et2s=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.46.0/go.mod h1:tkipS4DRzmpAmvg+Gw4++O1IdDq6TVDnvnYU6cmbQVs=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0 h1:OFnwLJr+pF3iHrlGSzbxyuo6/6HyBlnlN1CWEJmBVcw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0/go.mod h1:716wFneO0ov19A2beH5hjfh9AK5z/VWNAtDijp1Y0/g=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.46.0 h1:w53CDeOA/Kurp7yRsegSr6pbbr759dOvJ+yNmWM6Hxs=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.46.0/go.mod h1:BOmGMCbAtvcJiSJ+hLuhgPLdDbimnraSl8irz3iY8sY=
|
||||
go.opentelemetry.io/otel/metric v1.46.0 h1:yBnkXvgV7AXFILZc5K6IZe/CBFF3OS7BJ8ov6/lj0K8=
|
||||
go.opentelemetry.io/otel/metric v1.46.0/go.mod h1:iPmdWqifKUdzziPkvvzIJXITl56fQx2mGM/DHLB3/2o=
|
||||
go.opentelemetry.io/otel/metric/x v0.68.0 h1:TA/cBT23D3MnxYPwHL7YFOdYGdx0A0v+s7Mzotpd1dU=
|
||||
go.opentelemetry.io/otel/metric/x v0.68.0/go.mod h1:agudOmvWhwUTjgibWDzxD2PoWYnpw5Ht5jISYOD2Hd4=
|
||||
go.opentelemetry.io/otel/sdk v1.46.0 h1:h5CNQQjEbuQXY/JfZtgt3i7HVFV3aHPO2OAwO2eTYPI=
|
||||
go.opentelemetry.io/otel/sdk v1.46.0/go.mod h1:GAERFXFt5SYCEB+YiKUbMBeza6UaDH7GmGOZEfh2gSM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.46.0 h1:0piZ26EG4RBfebb2jhDH6ERCYHoVWduc3kLgPCwSnSE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.46.0/go.mod h1:I1PbKrdVc8Qu8HYVDNtqVIwLwjNrhsV/uFuxfwg8mO4=
|
||||
go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c=
|
||||
go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI=
|
||||
go.opentelemetry.io/proto/otlp v1.11.0 h1:5rrYs0Ykyj50sdU/JU0x8etU+LubXWb+gED6TbEdMIk=
|
||||
go.opentelemetry.io/proto/otlp v1.11.0/go.mod h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT72hLMhv8VwA8E=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
go.yaml.in/yaml/v3 v3.0.6 h1:zcDfvjXEqTQmpjniUBLc91xYJMB2c4QOFxEF/LCEckM=
|
||||
go.yaml.in/yaml/v3 v3.0.6/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
|
||||
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
|
||||
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.42.0 h1:ICeL3t2L30ljSPHHxDnR4fqVcBt/zR2zJAb9juavmQg=
|
||||
golang.org/x/mod v0.42.0/go.mod h1:u5fzIrRInkL8MaO1cbRkUHT64v303YIT5KEqpNr7jRs=
|
||||
golang.org/x/mod v0.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c=
|
||||
golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.62.0 h1:18ELalfM5+XNRwzM2nYqXsZQ9ByS1uhj2O/U7+5jqRY=
|
||||
golang.org/x/net v0.62.0/go.mod h1:WgDCOTH8iwtB66T4/GfI94AHo/hhdb7Hah9NDseQfiI=
|
||||
golang.org/x/net v0.60.0 h1:79p50tfZlm0J9YfoDsSi639qSXNGVwEzOPLCxM2FsYU=
|
||||
golang.org/x/net v0.60.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.24.0 h1:iqiDrGoDgyuvAKrhLQthUEzU/R378N78gXbBjxed7oA=
|
||||
golang.org/x/sync v0.24.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0=
|
||||
golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk=
|
||||
golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.49.1-0.20261022125458-f5cb0306ac0e h1:y3PdhEKVIFYc4c6gNZPEC7qPIoa9uH/2zIQEc0mw4R4=
|
||||
golang.org/x/sys v0.49.1-0.20261022125458-f5cb0306ac0e/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
|
||||
golang.org/x/term v0.47.0 h1:cpyOwQkr2Nzxe2p6KnrTG7Ei2wtzjsuSjhpXXepZ/BM=
|
||||
golang.org/x/term v0.47.0/go.mod h1:efAfAuG6RKABvg1ArGebRkvX6LXul14SM67o2e4mUCY=
|
||||
golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
|
||||
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
|
||||
golang.org/x/term v0.46.0 h1:3+OXuTbaKDgwk8jTi3aSLHRlmWqHEUDUtxnbFigO4YE=
|
||||
golang.org/x/term v0.46.0/go.mod h1:+K02xbkittuwc0Am4abfA3Fc+XRGXkvBXNO88NCXPoc=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.43.0 h1:1QivrlhwAsnMOcqgOdl9my7s9OyZl8O5/UGUTJVXoWc=
|
||||
golang.org/x/text v0.43.0/go.mod h1:hbSIYA/amXcRXTFSZqh8tWHEoqRvvbKPJ2uz/KU+a+s=
|
||||
golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI=
|
||||
golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E=
|
||||
golang.org/x/time v0.16.0 h1:vMb6ptszcQMkcwiRTAuNNU50gom6++Q/6gY2hDM6VDE=
|
||||
golang.org/x/time v0.16.0/go.mod h1:rVKOqvZeKvrDKTQiAHJ7wmwP0RzleSphoEA9RcdLA0s=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -226,10 +224,10 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260928230214-8a89bd6388cc h1:rZHRz0ogq4Pid1IKtA/ivHi8XONVF5tqUQXA2TtgpkE=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260928230214-8a89bd6388cc/go.mod h1:K/n0XLazCJHjD73YuMyNJsN38BPPy1kfFnKxUXaThFU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260928230214-8a89bd6388cc h1:4bNTbnb44EqGVy9HaQxSY2jnafSUdgV3qHtedvNpDKg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260928230214-8a89bd6388cc/go.mod h1:OaIUM3+LpYcK2GXM4FTmhWoIq371Owdr+Cc7/BsYHHc=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260825221802-da73d73af1c5 h1:izFU9hz7aeLI/Mi1J0991ae+xcwRLr7hTqWnB/9aIIU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260825221802-da73d73af1c5/go.mod h1:3LhxRw4YYkf+ylAfgaY9JlVLFKhokkCV8duhLLe7+t0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5 h1:1VUiZAXyC+zmiFYi+WLtBzr68Cj8wOofHjjrA/kkizc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260825221802-da73d73af1c5/go.mod h1:DjtHYE8FKJLivXcBEjGwndXfIC23G0VpXiXKqG179uA=
|
||||
google.golang.org/grpc v1.83.2 h1:EManeRomTObA0BU7I8vXgg/78uE5MJ9M8B39EX2WscU=
|
||||
google.golang.org/grpc v1.83.2/go.mod h1:YPI1hK3kDked6iHvgX3tR0y+nX/qpMFKhPgFsokw1S8=
|
||||
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
|
||||
@@ -237,5 +235,7 @@ google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||
pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=
|
||||
pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
|
||||
tags.cncf.io/container-device-interface v1.1.1 h1:YPwQz4xg8PlQ0yT/baR0BtLpTQROe4l6M1yuRgAu1vc=
|
||||
tags.cncf.io/container-device-interface v1.1.1/go.mod h1:S1PSJWYPD4Iom0/39mvr/VVFCfG0Yt14j20d0OYrY2M=
|
||||
|
||||
+5
-7
@@ -1,7 +1,5 @@
|
||||
package ansiterm
|
||||
|
||||
import "slices"
|
||||
|
||||
type csiEntryState struct {
|
||||
baseState
|
||||
}
|
||||
@@ -15,11 +13,11 @@ func (csiState csiEntryState) Handle(b byte) (s state, e error) {
|
||||
}
|
||||
|
||||
switch {
|
||||
case slices.Contains(alphabetics, b):
|
||||
case sliceContains(alphabetics, b):
|
||||
return csiState.parser.ground, nil
|
||||
case slices.Contains(csiCollectables, b):
|
||||
case sliceContains(csiCollectables, b):
|
||||
return csiState.parser.csiParam, nil
|
||||
case slices.Contains(executors, b):
|
||||
case sliceContains(executors, b):
|
||||
return csiState, csiState.parser.execute()
|
||||
}
|
||||
|
||||
@@ -35,9 +33,9 @@ func (csiState csiEntryState) Transition(s state) error {
|
||||
return csiState.parser.csiDispatch()
|
||||
case csiState.parser.csiParam:
|
||||
switch {
|
||||
case slices.Contains(csiParams, csiState.parser.context.currentChar):
|
||||
case sliceContains(csiParams, csiState.parser.context.currentChar):
|
||||
_ = csiState.parser.collectParam()
|
||||
case slices.Contains(intermeds, csiState.parser.context.currentChar):
|
||||
case sliceContains(intermeds, csiState.parser.context.currentChar):
|
||||
_ = csiState.parser.collectInter()
|
||||
}
|
||||
}
|
||||
|
||||
+3
-5
@@ -1,7 +1,5 @@
|
||||
package ansiterm
|
||||
|
||||
import "slices"
|
||||
|
||||
type csiParamState struct {
|
||||
baseState
|
||||
}
|
||||
@@ -15,11 +13,11 @@ func (csiState csiParamState) Handle(b byte) (s state, e error) {
|
||||
}
|
||||
|
||||
switch {
|
||||
case slices.Contains(alphabetics, b):
|
||||
case sliceContains(alphabetics, b):
|
||||
return csiState.parser.ground, nil
|
||||
case slices.Contains(csiCollectables, b):
|
||||
case sliceContains(csiCollectables, b):
|
||||
return csiState, csiState.parser.collectParam()
|
||||
case slices.Contains(executors, b):
|
||||
case sliceContains(executors, b):
|
||||
return csiState, csiState.parser.execute()
|
||||
}
|
||||
|
||||
|
||||
+3
-5
@@ -1,7 +1,5 @@
|
||||
package ansiterm
|
||||
|
||||
import "slices"
|
||||
|
||||
type escapeIntermediateState struct {
|
||||
baseState
|
||||
}
|
||||
@@ -14,11 +12,11 @@ func (escState escapeIntermediateState) Handle(b byte) (s state, e error) {
|
||||
}
|
||||
|
||||
switch {
|
||||
case slices.Contains(intermeds, b):
|
||||
case sliceContains(intermeds, b):
|
||||
return escState, escState.parser.collectInter()
|
||||
case slices.Contains(executors, b):
|
||||
case sliceContains(executors, b):
|
||||
return escState, escState.parser.execute()
|
||||
case slices.Contains(escapeIntermediateToGroundBytes, b):
|
||||
case sliceContains(escapeIntermediateToGroundBytes, b):
|
||||
return escState.parser.ground, nil
|
||||
}
|
||||
|
||||
|
||||
+3
-5
@@ -1,7 +1,5 @@
|
||||
package ansiterm
|
||||
|
||||
import "slices"
|
||||
|
||||
type escapeState struct {
|
||||
baseState
|
||||
}
|
||||
@@ -18,11 +16,11 @@ func (escState escapeState) Handle(b byte) (s state, e error) {
|
||||
return escState.parser.csiEntry, nil
|
||||
case b == ANSI_OSC_STRING_ENTRY:
|
||||
return escState.parser.oscString, nil
|
||||
case slices.Contains(executors, b):
|
||||
case sliceContains(executors, b):
|
||||
return escState, escState.parser.execute()
|
||||
case slices.Contains(escapeToGroundBytes, b):
|
||||
case sliceContains(escapeToGroundBytes, b):
|
||||
return escState.parser.ground, nil
|
||||
case slices.Contains(intermeds, b):
|
||||
case sliceContains(intermeds, b):
|
||||
return escState.parser.escapeIntermediate, nil
|
||||
}
|
||||
|
||||
|
||||
+2
-4
@@ -1,7 +1,5 @@
|
||||
package ansiterm
|
||||
|
||||
import "slices"
|
||||
|
||||
type groundState struct {
|
||||
baseState
|
||||
}
|
||||
@@ -15,10 +13,10 @@ func (gs groundState) Handle(b byte) (s state, e error) {
|
||||
}
|
||||
|
||||
switch {
|
||||
case slices.Contains(printables, b):
|
||||
case sliceContains(printables, b):
|
||||
return gs, gs.parser.print()
|
||||
|
||||
case slices.Contains(executors, b):
|
||||
case sliceContains(executors, b):
|
||||
return gs, gs.parser.execute()
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -20,12 +20,12 @@ type AnsiParser struct {
|
||||
oscString state
|
||||
stateMap []state
|
||||
|
||||
logf func(string, ...any)
|
||||
logf func(string, ...interface{})
|
||||
}
|
||||
|
||||
type Option func(*AnsiParser)
|
||||
|
||||
func WithLogf(f func(string, ...any)) Option {
|
||||
func WithLogf(f func(string, ...interface{})) Option {
|
||||
return func(ap *AnsiParser) {
|
||||
ap.logf = f
|
||||
}
|
||||
@@ -45,7 +45,7 @@ func CreateParser(initialState string, evtHandler AnsiEventHandler, opts ...Opti
|
||||
logger := log.New(logFile, "", log.LstdFlags)
|
||||
if ap.logf != nil {
|
||||
l := ap.logf
|
||||
ap.logf = func(s string, v ...any) {
|
||||
ap.logf = func(s string, v ...interface{}) {
|
||||
l(s, v...)
|
||||
logger.Printf(s, v...)
|
||||
}
|
||||
@@ -55,7 +55,7 @@ func CreateParser(initialState string, evtHandler AnsiEventHandler, opts ...Opti
|
||||
}
|
||||
|
||||
if ap.logf == nil {
|
||||
ap.logf = func(string, ...any) {}
|
||||
ap.logf = func(string, ...interface{}) {}
|
||||
}
|
||||
|
||||
ap.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: ap}}
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ func getInts(params []string, minCount int, dflt int) []int {
|
||||
|
||||
if len(ints) < minCount {
|
||||
remaining := minCount - len(ints)
|
||||
for range remaining {
|
||||
for i := 0; i < remaining; i++ {
|
||||
ints = append(ints, dflt)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,7 +1,5 @@
|
||||
package ansiterm
|
||||
|
||||
import "slices"
|
||||
|
||||
type state interface {
|
||||
Enter() error
|
||||
Exit() error
|
||||
@@ -34,7 +32,7 @@ func (base baseState) Handle(b byte) (s state, e error) {
|
||||
return base.parser.escape, nil
|
||||
case b == OSC_STRING:
|
||||
return base.parser.oscString, nil
|
||||
case slices.Contains(toGroundBytes, b):
|
||||
case sliceContains(toGroundBytes, b):
|
||||
return base.parser.ground, nil
|
||||
}
|
||||
|
||||
@@ -54,7 +52,7 @@ func (base baseState) Transition(s state) error {
|
||||
execBytes = append(execBytes, 0x99)
|
||||
execBytes = append(execBytes, 0x9A)
|
||||
|
||||
if slices.Contains(execBytes, base.parser.context.currentChar) {
|
||||
if sliceContains(execBytes, base.parser.context.currentChar) {
|
||||
return base.parser.execute()
|
||||
}
|
||||
}
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package ansiterm
|
||||
|
||||
func sliceContains(bytes []byte, b byte) bool {
|
||||
for _, v := range bytes {
|
||||
if v == b {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
|
||||
+90
-96
@@ -1,17 +1,14 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// ===========================================================================================================
|
||||
//===========================================================================================================
|
||||
// IMPORTANT NOTE:
|
||||
//
|
||||
// The methods below make extensive use of the "unsafe" package to obtain the required pointers.
|
||||
@@ -29,50 +26,51 @@ import (
|
||||
// -- The value is not referenced by the method after passing the pointer to Windows
|
||||
//
|
||||
// See http://golang.org/doc/go1.3.
|
||||
// ===========================================================================================================
|
||||
//===========================================================================================================
|
||||
|
||||
var (
|
||||
kernel32DLL = windows.NewLazyDLL("kernel32.dll")
|
||||
kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo")
|
||||
setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo")
|
||||
setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition")
|
||||
setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode")
|
||||
getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
|
||||
setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize")
|
||||
scrollConsoleScreenBufferProc = kernel32DLL.NewProc("ScrollConsoleScreenBufferA")
|
||||
setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute")
|
||||
setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo")
|
||||
writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW")
|
||||
readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW")
|
||||
waitForSingleObjectProc = kernel32DLL.NewProc("WaitForSingleObject")
|
||||
)
|
||||
|
||||
// Console modes
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
|
||||
// Windows Console constants
|
||||
const (
|
||||
ENABLE_PROCESSED_INPUT = windows.ENABLE_PROCESSED_INPUT
|
||||
ENABLE_LINE_INPUT = windows.ENABLE_LINE_INPUT
|
||||
ENABLE_ECHO_INPUT = windows.ENABLE_ECHO_INPUT
|
||||
ENABLE_WINDOW_INPUT = windows.ENABLE_WINDOW_INPUT
|
||||
ENABLE_MOUSE_INPUT = windows.ENABLE_MOUSE_INPUT
|
||||
ENABLE_INSERT_MODE = windows.ENABLE_INSERT_MODE
|
||||
ENABLE_QUICK_EDIT_MODE = windows.ENABLE_QUICK_EDIT_MODE
|
||||
ENABLE_EXTENDED_FLAGS = windows.ENABLE_EXTENDED_FLAGS
|
||||
ENABLE_AUTO_POSITION = windows.ENABLE_AUTO_POSITION
|
||||
ENABLE_VIRTUAL_TERMINAL_INPUT = windows.ENABLE_VIRTUAL_TERMINAL_INPUT
|
||||
// Console modes
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
|
||||
ENABLE_PROCESSED_INPUT = 0x0001
|
||||
ENABLE_LINE_INPUT = 0x0002
|
||||
ENABLE_ECHO_INPUT = 0x0004
|
||||
ENABLE_WINDOW_INPUT = 0x0008
|
||||
ENABLE_MOUSE_INPUT = 0x0010
|
||||
ENABLE_INSERT_MODE = 0x0020
|
||||
ENABLE_QUICK_EDIT_MODE = 0x0040
|
||||
ENABLE_EXTENDED_FLAGS = 0x0080
|
||||
ENABLE_AUTO_POSITION = 0x0100
|
||||
ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200
|
||||
|
||||
ENABLE_PROCESSED_OUTPUT = windows.ENABLE_PROCESSED_OUTPUT
|
||||
ENABLE_WRAP_AT_EOL_OUTPUT = windows.ENABLE_WRAP_AT_EOL_OUTPUT
|
||||
ENABLE_VIRTUAL_TERMINAL_PROCESSING = windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
DISABLE_NEWLINE_AUTO_RETURN = windows.DISABLE_NEWLINE_AUTO_RETURN
|
||||
ENABLE_LVB_GRID_WORLDWIDE = windows.ENABLE_LVB_GRID_WORLDWIDE
|
||||
)
|
||||
ENABLE_PROCESSED_OUTPUT = 0x0001
|
||||
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
|
||||
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
|
||||
DISABLE_NEWLINE_AUTO_RETURN = 0x0008
|
||||
ENABLE_LVB_GRID_WORLDWIDE = 0x0010
|
||||
|
||||
// Character attributes
|
||||
//
|
||||
// Foreground and background attributes can be combined to produce colors.
|
||||
// Clearing all foreground or background color bits produces black; setting
|
||||
// all color bits produces white.
|
||||
//
|
||||
// See https://learn.microsoft.com/windows/console/char-info-str.
|
||||
const (
|
||||
// Character attributes
|
||||
// Note:
|
||||
// -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan).
|
||||
// Clearing all foreground or background colors results in black; setting all creates white.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes.
|
||||
FOREGROUND_BLUE uint16 = 0x0001
|
||||
FOREGROUND_GREEN uint16 = 0x0002
|
||||
FOREGROUND_RED uint16 = 0x0004
|
||||
@@ -88,29 +86,23 @@ const (
|
||||
COMMON_LVB_MASK uint16 = 0xFF00
|
||||
COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000
|
||||
COMMON_LVB_UNDERSCORE uint16 = 0x8000
|
||||
)
|
||||
|
||||
// Input event types
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
|
||||
const (
|
||||
KEY_EVENT = windows.KEY_EVENT
|
||||
MOUSE_EVENT = windows.MOUSE_EVENT
|
||||
WINDOW_BUFFER_SIZE_EVENT = windows.WINDOW_BUFFER_SIZE_EVENT
|
||||
MENU_EVENT = windows.MENU_EVENT
|
||||
FOCUS_EVENT = windows.FOCUS_EVENT
|
||||
)
|
||||
// Input event types
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
|
||||
KEY_EVENT = 0x0001
|
||||
MOUSE_EVENT = 0x0002
|
||||
WINDOW_BUFFER_SIZE_EVENT = 0x0004
|
||||
MENU_EVENT = 0x0008
|
||||
FOCUS_EVENT = 0x0010
|
||||
|
||||
// WaitForSingleObject return codes.
|
||||
const (
|
||||
WAIT_ABANDONED = windows.WAIT_ABANDONED
|
||||
WAIT_FAILED = windows.WAIT_FAILED
|
||||
WAIT_SIGNALED = windows.WAIT_OBJECT_0
|
||||
WAIT_TIMEOUT = 0x00000102 // Keep as untyped int for backward compat; windows.WAIT_TIMEOUT is typed as syscall.Errno.
|
||||
)
|
||||
// WaitForSingleObject return codes
|
||||
WAIT_ABANDONED = 0x00000080
|
||||
WAIT_FAILED = 0xFFFFFFFF
|
||||
WAIT_SIGNALED = 0x0000000
|
||||
WAIT_TIMEOUT = 0x00000102
|
||||
|
||||
// WaitForSingleObject wait durations.
|
||||
const (
|
||||
WAIT_INFINITE = windows.INFINITE
|
||||
// WaitForSingleObject wait duration
|
||||
WAIT_INFINITE = 0xFFFFFFFF
|
||||
WAIT_ONE_SECOND = 1000
|
||||
WAIT_HALF_SECOND = 500
|
||||
WAIT_QUARTER_SECOND = 250
|
||||
@@ -130,8 +122,6 @@ type (
|
||||
Visible int32
|
||||
}
|
||||
|
||||
// CONSOLE_SCREEN_BUFFER_INFO is identical to [windows.ConsoleScreenBufferInfo]
|
||||
// but implements [fmt.Stringer].
|
||||
CONSOLE_SCREEN_BUFFER_INFO struct {
|
||||
Size COORD
|
||||
CursorPosition COORD
|
||||
@@ -140,11 +130,17 @@ type (
|
||||
MaximumWindowSize COORD
|
||||
}
|
||||
|
||||
// COORD is identical to [windows.Coord] but implements [fmt.Stringer].
|
||||
COORD windows.Coord
|
||||
COORD struct {
|
||||
X int16
|
||||
Y int16
|
||||
}
|
||||
|
||||
// SMALL_RECT is identical to [windows.SmallRect] but implements [fmt.Stringer].
|
||||
SMALL_RECT windows.SmallRect
|
||||
SMALL_RECT struct {
|
||||
Left int16
|
||||
Top int16
|
||||
Right int16
|
||||
Bottom int16
|
||||
}
|
||||
|
||||
// INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
|
||||
@@ -193,45 +189,43 @@ func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error
|
||||
// SetConsoleCursorPosition location of the console cursor.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx.
|
||||
func SetConsoleCursorPosition(handle uintptr, coord COORD) error {
|
||||
return windows.SetConsoleCursorPosition(windows.Handle(handle), windows.Coord(coord))
|
||||
r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord))
|
||||
use(coord)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// GetConsoleMode gets the console mode for the given handle.
|
||||
// GetConsoleMode gets the console mode for given file descriptor
|
||||
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx.
|
||||
func GetConsoleMode(handle uintptr) (mode uint32, err error) {
|
||||
err = windows.GetConsoleMode(windows.Handle(handle), &mode)
|
||||
err = syscall.GetConsoleMode(syscall.Handle(handle), &mode)
|
||||
return mode, err
|
||||
}
|
||||
|
||||
// SetConsoleMode sets the console mode for the given handle.
|
||||
// SetConsoleMode sets the console mode for given file descriptor
|
||||
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
|
||||
func SetConsoleMode(handle uintptr, mode uint32) error {
|
||||
return windows.SetConsoleMode(windows.Handle(handle), mode)
|
||||
r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0)
|
||||
use(mode)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer.
|
||||
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx.
|
||||
func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
|
||||
var info windows.ConsoleScreenBufferInfo
|
||||
if err := windows.GetConsoleScreenBufferInfo(windows.Handle(handle), &info); err != nil {
|
||||
info := CONSOLE_SCREEN_BUFFER_INFO{}
|
||||
err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &CONSOLE_SCREEN_BUFFER_INFO{
|
||||
Size: COORD(info.Size),
|
||||
CursorPosition: COORD(info.CursorPosition),
|
||||
Attributes: info.Attributes,
|
||||
Window: SMALL_RECT(info.Window),
|
||||
MaximumWindowSize: COORD(info.MaximumWindowSize),
|
||||
}, nil
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error {
|
||||
r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char)))
|
||||
runtime.KeepAlive(scrollRect)
|
||||
runtime.KeepAlive(clipRect)
|
||||
runtime.KeepAlive(destOrigin)
|
||||
runtime.KeepAlive(char)
|
||||
use(scrollRect)
|
||||
use(clipRect)
|
||||
use(destOrigin)
|
||||
use(char)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
@@ -239,7 +233,7 @@ func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect S
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx.
|
||||
func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error {
|
||||
r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord))
|
||||
runtime.KeepAlive(coord)
|
||||
use(coord)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
@@ -248,7 +242,7 @@ func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error {
|
||||
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx.
|
||||
func SetConsoleTextAttribute(handle uintptr, attribute uint16) error {
|
||||
r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0)
|
||||
runtime.KeepAlive(attribute)
|
||||
use(attribute)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
@@ -257,8 +251,8 @@ func SetConsoleTextAttribute(handle uintptr, attribute uint16) error {
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx.
|
||||
func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error {
|
||||
r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect)))
|
||||
runtime.KeepAlive(isAbsolute)
|
||||
runtime.KeepAlive(rect)
|
||||
use(isAbsolute)
|
||||
use(rect)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
@@ -266,9 +260,9 @@ func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) erro
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx.
|
||||
func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error {
|
||||
r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion)))
|
||||
runtime.KeepAlive(buffer)
|
||||
runtime.KeepAlive(bufferSize)
|
||||
runtime.KeepAlive(bufferCoord)
|
||||
use(buffer)
|
||||
use(bufferSize)
|
||||
use(bufferCoord)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
@@ -276,7 +270,7 @@ func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bu
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx.
|
||||
func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error {
|
||||
r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count)))
|
||||
runtime.KeepAlive(buffer)
|
||||
use(buffer)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
@@ -284,19 +278,15 @@ func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) erro
|
||||
// It returns true if the handle was signaled; false otherwise.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx.
|
||||
func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) {
|
||||
event, err := windows.WaitForSingleObject(windows.Handle(handle), msWait)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
switch event {
|
||||
case windows.WAIT_ABANDONED, uint32(windows.WAIT_TIMEOUT):
|
||||
r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait)))
|
||||
switch r1 {
|
||||
case WAIT_ABANDONED, WAIT_TIMEOUT:
|
||||
return false, nil
|
||||
case windows.WAIT_OBJECT_0:
|
||||
case WAIT_SIGNALED:
|
||||
return true, nil
|
||||
default:
|
||||
return false, nil
|
||||
}
|
||||
use(msWait)
|
||||
return false, err
|
||||
}
|
||||
|
||||
// String helpers
|
||||
@@ -331,3 +321,7 @@ func coordToPointer(c COORD) uintptr {
|
||||
// Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass.
|
||||
return uintptr(*((*uint32)(unsafe.Pointer(&c))))
|
||||
}
|
||||
|
||||
// use is a no-op, but the compiler cannot see that it is.
|
||||
// Calling use(p) ensures that p is kept live until that point.
|
||||
func use(p interface{}) {}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
|
||||
+33
-11
@@ -1,12 +1,10 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
const (
|
||||
horizontal = iota
|
||||
vertical
|
||||
line
|
||||
column
|
||||
)
|
||||
|
||||
func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT {
|
||||
@@ -60,20 +58,44 @@ func (h *windowsAnsiEventHandler) moveCursor(moveMode int, param int) error {
|
||||
position.X += int16(param)
|
||||
case vertical:
|
||||
position.Y += int16(param)
|
||||
case line:
|
||||
position.X = 0
|
||||
position.Y += int16(param)
|
||||
case column:
|
||||
position.X = int16(param) - 1
|
||||
}
|
||||
|
||||
return h.setCursorPosition(position, h.getCursorWindow(info))
|
||||
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) moveCursorLine(param int) error {
|
||||
return h.moveCursor(line, param)
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
position := info.CursorPosition
|
||||
position.X = 0
|
||||
position.Y += int16(param)
|
||||
|
||||
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error {
|
||||
return h.moveCursor(column, param)
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
position := info.CursorPosition
|
||||
position.X = int16(param) - 1
|
||||
|
||||
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+13
-3
@@ -1,4 +1,4 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
@@ -50,7 +50,12 @@ func (h *windowsAnsiEventHandler) clearRange(attributes uint16, fromCoord COORD,
|
||||
coordStart.X, coordStart.Y = xCurrent, yCurrent
|
||||
coordEnd.X, coordEnd.Y = xEnd, yEnd
|
||||
|
||||
return h.clearRect(attributes, coordStart, coordEnd)
|
||||
err = h.clearRect(attributes, coordStart, coordEnd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD, toCoord COORD) error {
|
||||
@@ -70,5 +75,10 @@ func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD,
|
||||
buffer[i] = char
|
||||
}
|
||||
|
||||
return WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, ®ion)
|
||||
err := WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, ®ion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+11
-4
@@ -1,4 +1,4 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
@@ -39,8 +39,9 @@ func (h *windowsAnsiEventHandler) deleteLines(param int) error {
|
||||
if start >= sr.top && start <= sr.bottom {
|
||||
sr.top = start
|
||||
return h.scroll(param, sr, info)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) insertLines(param int) error {
|
||||
@@ -71,7 +72,10 @@ func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSO
|
||||
Attributes: h.attributes,
|
||||
}
|
||||
|
||||
return ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char)
|
||||
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) deleteCharacters(param int) error {
|
||||
@@ -107,5 +111,8 @@ func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *
|
||||
Attributes: h.attributes,
|
||||
}
|
||||
|
||||
return ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char)
|
||||
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
|
||||
+33
-19
@@ -1,4 +1,4 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
@@ -169,7 +169,9 @@ func (h *windowsAnsiEventHandler) executeLF() error {
|
||||
return err
|
||||
}
|
||||
h.logf("Resetting cursor position for LF without CR")
|
||||
return SetConsoleCursorPosition(h.fd, pos)
|
||||
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -371,7 +373,7 @@ func (h *windowsAnsiEventHandler) CUP(row int, col int) error {
|
||||
}
|
||||
|
||||
window := h.getCursorWindow(info)
|
||||
position := COORD{X: window.Left + int16(col) - 1, Y: window.Top + int16(row) - 1}
|
||||
position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1}
|
||||
return h.setCursorPosition(position, window)
|
||||
}
|
||||
|
||||
@@ -421,7 +423,7 @@ func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error {
|
||||
targetWidth = 132
|
||||
}
|
||||
if info.Size.X < targetWidth {
|
||||
if err := SetConsoleScreenBufferSize(h.fd, COORD{X: targetWidth, Y: info.Size.Y}); err != nil {
|
||||
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
|
||||
h.logf("set buffer failed: %v", err)
|
||||
return err
|
||||
}
|
||||
@@ -434,12 +436,12 @@ func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error {
|
||||
return err
|
||||
}
|
||||
if info.Size.X > targetWidth {
|
||||
if err := SetConsoleScreenBufferSize(h.fd, COORD{X: targetWidth, Y: info.Size.Y}); err != nil {
|
||||
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
|
||||
h.logf("set buffer failed: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return SetConsoleCursorPosition(h.fd, COORD{X: 0, Y: 0})
|
||||
return SetConsoleCursorPosition(h.fd, COORD{0, 0})
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) ED(param int) error {
|
||||
@@ -466,15 +468,15 @@ func (h *windowsAnsiEventHandler) ED(param int) error {
|
||||
switch param {
|
||||
case 0:
|
||||
start = info.CursorPosition
|
||||
end = COORD{X: info.Size.X - 1, Y: info.Size.Y - 1}
|
||||
end = COORD{info.Size.X - 1, info.Size.Y - 1}
|
||||
|
||||
case 1:
|
||||
start = COORD{X: 0, Y: 0}
|
||||
start = COORD{0, 0}
|
||||
end = info.CursorPosition
|
||||
|
||||
case 2:
|
||||
start = COORD{X: 0, Y: 0}
|
||||
end = COORD{X: info.Size.X - 1, Y: info.Size.Y - 1}
|
||||
start = COORD{0, 0}
|
||||
end = COORD{info.Size.X - 1, info.Size.Y - 1}
|
||||
}
|
||||
|
||||
err = h.clearRange(h.attributes, start, end)
|
||||
@@ -493,7 +495,9 @@ func (h *windowsAnsiEventHandler) ED(param int) error {
|
||||
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||
return err
|
||||
}
|
||||
return SetConsoleWindowInfo(h.fd, true, window)
|
||||
if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -521,18 +525,23 @@ func (h *windowsAnsiEventHandler) EL(param int) error {
|
||||
switch param {
|
||||
case 0:
|
||||
start = info.CursorPosition
|
||||
end = COORD{X: info.Size.X, Y: info.CursorPosition.Y}
|
||||
end = COORD{info.Size.X, info.CursorPosition.Y}
|
||||
|
||||
case 1:
|
||||
start = COORD{X: 0, Y: info.CursorPosition.Y}
|
||||
start = COORD{0, info.CursorPosition.Y}
|
||||
end = info.CursorPosition
|
||||
|
||||
case 2:
|
||||
start = COORD{X: 0, Y: info.CursorPosition.Y}
|
||||
end = COORD{X: info.Size.X, Y: info.CursorPosition.Y}
|
||||
start = COORD{0, info.CursorPosition.Y}
|
||||
end = COORD{info.Size.X, info.CursorPosition.Y}
|
||||
}
|
||||
|
||||
return h.clearRange(h.attributes, start, end)
|
||||
err = h.clearRange(h.attributes, start, end)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) IL(param int) error {
|
||||
@@ -602,7 +611,12 @@ func (h *windowsAnsiEventHandler) SGR(params []int) error {
|
||||
if h.inverted {
|
||||
attributes = invertAttributes(attributes)
|
||||
}
|
||||
return SetConsoleTextAttribute(h.fd, attributes)
|
||||
err := SetConsoleTextAttribute(h.fd, attributes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *windowsAnsiEventHandler) SU(param int) error {
|
||||
@@ -688,8 +702,8 @@ func (h *windowsAnsiEventHandler) Flush() error {
|
||||
}
|
||||
|
||||
charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}}
|
||||
size := COORD{X: 1, Y: 1}
|
||||
position := COORD{X: 0, Y: 0}
|
||||
size := COORD{1, 1}
|
||||
position := COORD{0, 0}
|
||||
region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y}
|
||||
if err := WriteConsoleOutput(h.fd, charInfo, size, position, ®ion); err != nil {
|
||||
return err
|
||||
|
||||
+3
-33
@@ -408,10 +408,7 @@ func (ctx *genericEncrypter) EncryptWithAuthData(plaintext, aad []byte) (*JSONWe
|
||||
(*obj.protected)[k] = makeRawMessage(b)
|
||||
}
|
||||
|
||||
authData, err := obj.computeAuthData()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authData := obj.computeAuthData()
|
||||
parts, err := ctx.cipher.encrypt(cek, authData, plaintext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -431,13 +428,6 @@ func (ctx *genericEncrypter) Options() EncrypterOptions {
|
||||
}
|
||||
}
|
||||
|
||||
func validateContentEncryptionKeySize(cek []byte, cipher contentCipher) error {
|
||||
if len(cek) != cipher.keySize() {
|
||||
return ErrInvalidKeySize
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decrypt and validate the object and return the plaintext. This
|
||||
// function does not support multi-recipient. If you desire multi-recipient
|
||||
// decryption use DecryptMulti instead.
|
||||
@@ -495,10 +485,7 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error)
|
||||
tag: obj.tag,
|
||||
}
|
||||
|
||||
authData, err := obj.computeAuthData()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authData := obj.computeAuthData()
|
||||
|
||||
var plaintext []byte
|
||||
recipient := obj.recipients[0]
|
||||
@@ -508,10 +495,6 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error)
|
||||
if err != nil {
|
||||
return nil, ErrCryptoFailure
|
||||
}
|
||||
err = validateContentEncryptionKeySize(cek, cipher)
|
||||
if err != nil {
|
||||
return nil, ErrCryptoFailure
|
||||
}
|
||||
|
||||
// Found a valid CEK -- let's try to decrypt.
|
||||
plaintext, err = cipher.decrypt(cek, authData, parts)
|
||||
@@ -537,12 +520,6 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error)
|
||||
//
|
||||
// Automatically decompresses plaintext, but returns an error if the decompressed
|
||||
// data would be >250kB or >3x the size of the compressed data, whichever is larger.
|
||||
//
|
||||
// Calling DecryptMulti() with PBES2 enabled can result in excessive CPU work.
|
||||
// The PBES2 key unwrapping algorithms are intentionally expensive, and have to
|
||||
// be run for each recipient. To be safe: don't allow PBES2 algorithms in calls
|
||||
// to ParseEncrypted / ParseEncryptedJSON. If your application requires PBES2,
|
||||
// prefer Decrypt(), which will only process single-recipient messages.
|
||||
func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Header, []byte, error) {
|
||||
globalHeaders := obj.mergedHeaders(nil)
|
||||
|
||||
@@ -576,10 +553,7 @@ func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Heade
|
||||
tag: obj.tag,
|
||||
}
|
||||
|
||||
authData, err := obj.computeAuthData()
|
||||
if err != nil {
|
||||
return -1, Header{}, nil, err
|
||||
}
|
||||
authData := obj.computeAuthData()
|
||||
|
||||
index := -1
|
||||
var plaintext []byte
|
||||
@@ -598,10 +572,6 @@ func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Heade
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
err = validateContentEncryptionKeySize(cek, cipher)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Found a valid CEK -- let's try to decrypt.
|
||||
plaintext, err = cipher.decrypt(cek, authData, parts)
|
||||
|
||||
+32
-6
@@ -30,6 +30,30 @@ import (
|
||||
"github.com/go-jose/go-jose/v4/json"
|
||||
)
|
||||
|
||||
// Helper function to serialize known-good objects.
|
||||
// Precondition: value is not a nil pointer.
|
||||
func mustSerializeJSON(value interface{}) []byte {
|
||||
out, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// We never want to serialize the top-level value "null," since it's not a
|
||||
// valid JOSE message. But if a caller passes in a nil pointer to this method,
|
||||
// MarshalJSON will happily serialize it as the top-level value "null". If
|
||||
// that value is then embedded in another operation, for instance by being
|
||||
// base64-encoded and fed as input to a signing algorithm
|
||||
// (https://github.com/go-jose/go-jose/issues/22), the result will be
|
||||
// incorrect. Because this method is intended for known-good objects, and a nil
|
||||
// pointer is not a known-good object, we are free to panic in this case.
|
||||
// Note: It's not possible to directly check whether the data pointed at by an
|
||||
// interface is a nil pointer, so we do this hacky workaround.
|
||||
// https://groups.google.com/forum/#!topic/golang-nuts/wnH302gBa4I
|
||||
if string(out) == "null" {
|
||||
panic("Tried to serialize a nil pointer.")
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Strip all newlines and whitespace
|
||||
func stripWhitespace(data string) string {
|
||||
buf := strings.Builder{}
|
||||
@@ -98,8 +122,6 @@ func inflate(input []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
// byteBuffer represents a slice of bytes that can be serialized to url-safe base64.
|
||||
//
|
||||
// A nil byteBuffer represents an empty slice of bytes.
|
||||
type byteBuffer struct {
|
||||
data []byte
|
||||
}
|
||||
@@ -147,13 +169,13 @@ func (b *byteBuffer) UnmarshalJSON(data []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
b.data = decoded
|
||||
*b = *newBuffer(decoded)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *byteBuffer) base64() string {
|
||||
return base64.RawURLEncoding.EncodeToString(b.bytes())
|
||||
return base64.RawURLEncoding.EncodeToString(b.data)
|
||||
}
|
||||
|
||||
func (b *byteBuffer) bytes() []byte {
|
||||
@@ -164,8 +186,12 @@ func (b *byteBuffer) bytes() []byte {
|
||||
return b.data
|
||||
}
|
||||
|
||||
func (b *byteBuffer) bigInt() *big.Int {
|
||||
return new(big.Int).SetBytes(b.bytes())
|
||||
func (b byteBuffer) bigInt() *big.Int {
|
||||
return new(big.Int).SetBytes(b.data)
|
||||
}
|
||||
|
||||
func (b byteBuffer) toInt() int {
|
||||
return int(b.bigInt().Int64())
|
||||
}
|
||||
|
||||
func base64EncodeLen(sl []byte) int {
|
||||
|
||||
-13
@@ -671,19 +671,6 @@ func (d *decodeState) object(v reflect.Value) {
|
||||
for _, i := range f.index {
|
||||
if subv.Kind() == reflect.Ptr {
|
||||
if subv.IsNil() {
|
||||
// If a struct embeds a pointer to an unexported type,
|
||||
// it is not possible to set a newly allocated value
|
||||
// since the field is unexported.
|
||||
//
|
||||
// See https://golang.org/issue/21357
|
||||
if !subv.CanSet() {
|
||||
d.saveError(fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v", subv.Type().Elem()))
|
||||
// Invalidate subv to ensure d.value(subv) skips over
|
||||
// the JSON value without assigning it to subv.
|
||||
subv = reflect.Value{}
|
||||
destring = false
|
||||
break
|
||||
}
|
||||
subv.Set(reflect.New(subv.Type().Elem()))
|
||||
}
|
||||
subv = subv.Elem()
|
||||
|
||||
+1
-13
@@ -1025,19 +1025,7 @@ func typeFields(t reflect.Type) []field {
|
||||
// Scan f.typ for fields to include.
|
||||
for i := 0; i < f.typ.NumField(); i++ {
|
||||
sf := f.typ.Field(i)
|
||||
if sf.Anonymous {
|
||||
t := sf.Type
|
||||
if t.Kind() == reflect.Pointer {
|
||||
t = t.Elem()
|
||||
}
|
||||
if !sf.IsExported() && t.Kind() != reflect.Struct {
|
||||
// Ignore embedded fields of unexported non-struct types.
|
||||
continue
|
||||
}
|
||||
// Do not ignore embedded fields of unexported struct types
|
||||
// since they may have exported fields.
|
||||
} else if !sf.IsExported() {
|
||||
// Ignore unexported non-embedded fields.
|
||||
if sf.PkgPath != "" && !sf.Anonymous { // unexported
|
||||
continue
|
||||
}
|
||||
tag := sf.Tag.Get("json")
|
||||
|
||||
+25
-59
@@ -25,12 +25,6 @@ import (
|
||||
"github.com/go-jose/go-jose/v4/json"
|
||||
)
|
||||
|
||||
// MaxRecipients is the maximum number of recipients of a JWE at parse time.
|
||||
// Higher values mean more potential work done across untrusted input.
|
||||
//
|
||||
// If modifying MaxRecipients, do it before any parsing occurs.
|
||||
var MaxRecipients = 32
|
||||
|
||||
// rawJSONWebEncryption represents a raw JWE JSON object. Used for parsing/serializing.
|
||||
type rawJSONWebEncryption struct {
|
||||
Protected *byteBuffer `json:"protected,omitempty"`
|
||||
@@ -90,18 +84,14 @@ func (obj JSONWebEncryption) mergedHeaders(recipient *recipientInfo) rawHeader {
|
||||
}
|
||||
|
||||
// Get the additional authenticated data from a JWE object.
|
||||
func (obj JSONWebEncryption) computeAuthData() ([]byte, error) {
|
||||
func (obj JSONWebEncryption) computeAuthData() []byte {
|
||||
var protected string
|
||||
|
||||
switch {
|
||||
case obj.original != nil && obj.original.Protected != nil:
|
||||
protected = obj.original.Protected.base64()
|
||||
case obj.protected != nil:
|
||||
serializedProtected, err := json.Marshal(obj.protected)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
protected = base64.RawURLEncoding.EncodeToString(serializedProtected)
|
||||
protected = base64.RawURLEncoding.EncodeToString(mustSerializeJSON((obj.protected)))
|
||||
default:
|
||||
protected = ""
|
||||
}
|
||||
@@ -112,7 +102,7 @@ func (obj JSONWebEncryption) computeAuthData() ([]byte, error) {
|
||||
output = append(output, []byte(base64.RawURLEncoding.EncodeToString(obj.aad))...)
|
||||
}
|
||||
|
||||
return output, nil
|
||||
return output
|
||||
}
|
||||
|
||||
func containsKeyAlgorithm(haystack []KeyAlgorithm, needle KeyAlgorithm) bool {
|
||||
@@ -138,10 +128,11 @@ func containsContentEncryption(haystack []ContentEncryption, needle ContentEncry
|
||||
// https://datatracker.ietf.org/doc/html/rfc7516#section-3.1
|
||||
// https://datatracker.ietf.org/doc/html/rfc7516#section-3.2
|
||||
//
|
||||
// The keyAlgorithms and contentEncryption parameters contain the allowable algorithms in the "alg" and "enc"
|
||||
// header parameters respectively. They must be non-empty. Non-matching algorithms cause a parse error.
|
||||
//
|
||||
// Deprecated: use ParseEncryptedJSON or ParseEncryptedCompact depending on which serialization you expect.
|
||||
// The keyAlgorithms and contentEncryption parameters are used to validate the "alg" and "enc"
|
||||
// header parameters respectively. They must be nonempty, and each "alg" or "enc" header in
|
||||
// parsed data must contain a value that is present in the corresponding parameter. That
|
||||
// includes the protected and unprotected headers as well as all recipients. To accept
|
||||
// multiple algorithms, pass a slice of all the algorithms you want to accept.
|
||||
func ParseEncrypted(input string,
|
||||
keyEncryptionAlgorithms []KeyAlgorithm,
|
||||
contentEncryption []ContentEncryption,
|
||||
@@ -154,13 +145,9 @@ func ParseEncrypted(input string,
|
||||
return ParseEncryptedCompact(input, keyEncryptionAlgorithms, contentEncryption)
|
||||
}
|
||||
|
||||
// ParseEncryptedJSON parses a message in JWE JSON Serialization. Messages with
|
||||
// more than [MaxRecipients] recipients are rejected.
|
||||
// ParseEncryptedJSON parses a message in JWE JSON Serialization.
|
||||
//
|
||||
// https://datatracker.ietf.org/doc/html/rfc7516#section-3.2
|
||||
//
|
||||
// The keyAlgorithms and contentEncryption parameters contain the allowable algorithms in the "alg" and "enc"
|
||||
// header parameters respectively. They must be non-empty. Any non-allowed algorithms will cause parsing to fail.
|
||||
func ParseEncryptedJSON(
|
||||
input string,
|
||||
keyEncryptionAlgorithms []KeyAlgorithm,
|
||||
@@ -190,9 +177,6 @@ func (parsed *rawJSONWebEncryption) sanitized(
|
||||
if len(contentEncryption) == 0 {
|
||||
return nil, errors.New("go-jose/go-jose: no content encryption algorithms provided")
|
||||
}
|
||||
if len(parsed.Recipients) > MaxRecipients {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: too many recipients in JWE; maximum is %d", MaxRecipients)
|
||||
}
|
||||
|
||||
obj := &JSONWebEncryption{
|
||||
original: parsed,
|
||||
@@ -211,11 +195,21 @@ func (parsed *rawJSONWebEncryption) sanitized(
|
||||
}
|
||||
}
|
||||
|
||||
protected, err := parseProtectedHeader(parsed.Protected)
|
||||
if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
|
||||
err := json.Unmarshal(parsed.Protected.bytes(), &obj.protected)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: invalid protected header: %s, %s", err, parsed.Protected.base64())
|
||||
}
|
||||
}
|
||||
|
||||
// Note: this must be called _after_ we parse the protected header,
|
||||
// otherwise fields from the protected header will not get picked up.
|
||||
var err error
|
||||
mergedHeaders := obj.mergedHeaders(nil)
|
||||
obj.Header, err = mergedHeaders.sanitized()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("go-jose/go-jose: cannot sanitize merged headers: %v (%v)", err, mergedHeaders)
|
||||
}
|
||||
obj.protected = protected
|
||||
|
||||
if len(parsed.Recipients) == 0 {
|
||||
obj.recipients = []recipientInfo{
|
||||
@@ -270,14 +264,6 @@ func (parsed *rawJSONWebEncryption) sanitized(
|
||||
}
|
||||
}
|
||||
|
||||
// Note: this must be called _after_ we parse the protected header,
|
||||
// otherwise fields from the protected header will not get picked up.
|
||||
mergedHeaders := obj.mergedHeaders(nil)
|
||||
obj.Header, err = mergedHeaders.sanitized()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: cannot sanitize merged headers: %w", err)
|
||||
}
|
||||
|
||||
obj.iv = parsed.Iv.bytes()
|
||||
obj.ciphertext = parsed.Ciphertext.bytes()
|
||||
obj.tag = parsed.Tag.bytes()
|
||||
@@ -301,9 +287,6 @@ func validateAlgEnc(headers rawHeader, keyAlgorithms []KeyAlgorithm, contentEncr
|
||||
// ParseEncryptedCompact parses a message in JWE Compact Serialization.
|
||||
//
|
||||
// https://datatracker.ietf.org/doc/html/rfc7516#section-3.1
|
||||
//
|
||||
// The keyAlgorithms and contentEncryption parameters contain the allowable algorithms in the "alg" and "enc"
|
||||
// header parameters respectively. They must be non-empty. Any non-allowed algorithms will cause parsing to fail.
|
||||
func ParseEncryptedCompact(
|
||||
input string,
|
||||
keyAlgorithms []KeyAlgorithm,
|
||||
@@ -371,10 +354,7 @@ func (obj JSONWebEncryption) CompactSerialize() (string, error) {
|
||||
return "", ErrNotSupported
|
||||
}
|
||||
|
||||
serializedProtected, err := json.Marshal(obj.protected)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
serializedProtected := mustSerializeJSON(obj.protected)
|
||||
|
||||
return base64JoinWithDots(
|
||||
serializedProtected,
|
||||
@@ -386,13 +366,7 @@ func (obj JSONWebEncryption) CompactSerialize() (string, error) {
|
||||
}
|
||||
|
||||
// FullSerialize serializes an object using the full JSON serialization format.
|
||||
//
|
||||
// It returns "" if obj cannot be serialized, for example if it has no recipients.
|
||||
func (obj JSONWebEncryption) FullSerialize() string {
|
||||
if len(obj.recipients) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
raw := rawJSONWebEncryption{
|
||||
Unprotected: obj.unprotected,
|
||||
Iv: newBuffer(obj.iv),
|
||||
@@ -418,16 +392,8 @@ func (obj JSONWebEncryption) FullSerialize() string {
|
||||
}
|
||||
|
||||
if obj.protected != nil {
|
||||
serializedProtected, err := json.Marshal(obj.protected)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
raw.Protected = newBuffer(serializedProtected)
|
||||
raw.Protected = newBuffer(mustSerializeJSON(obj.protected))
|
||||
}
|
||||
|
||||
out, err := json.Marshal(raw)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(out)
|
||||
return string(mustSerializeJSON(raw))
|
||||
}
|
||||
|
||||
+24
-74
@@ -30,7 +30,6 @@ import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"net/url"
|
||||
"reflect"
|
||||
@@ -178,29 +177,13 @@ func (k JSONWebKey) MarshalJSON() ([]byte, error) {
|
||||
// UnmarshalJSON reads a key from its JSON representation.
|
||||
//
|
||||
// Returns ErrUnsupportedKeyType for unrecognized or unsupported "kty" header values.
|
||||
//
|
||||
// Directly unmarshaling a JWK is not safe for untrusted input.
|
||||
func (k *JSONWebKey) UnmarshalJSON(data []byte) error {
|
||||
return k.unmarshalJSON(data, true)
|
||||
}
|
||||
|
||||
// unmarshalJSON reads a key from its JSON representation.
|
||||
//
|
||||
// If allowPrivate is false, a JWK with private key material is rejected and the
|
||||
// function is safe for use against untrusted input.
|
||||
func (k *JSONWebKey) unmarshalJSON(data []byte, allowPrivate bool) (err error) {
|
||||
func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
|
||||
var raw rawJSONWebKey
|
||||
err = json.Unmarshal(data, &raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !allowPrivate &&
|
||||
(raw.K != nil || raw.D != nil || raw.P != nil || raw.Q != nil ||
|
||||
raw.Dp != nil || raw.Dq != nil || raw.Qi != nil) {
|
||||
return errors.New("go-jose/go-jose: JWK contains private parameters")
|
||||
}
|
||||
|
||||
certs, err := parseCertificateChain(raw.X5c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("go-jose/go-jose: failed to unmarshal x5c field: %s", err)
|
||||
@@ -250,7 +233,7 @@ func (k *JSONWebKey) unmarshalJSON(data []byte, allowPrivate bool) (err error) {
|
||||
keyPub = key
|
||||
}
|
||||
case "oct":
|
||||
if len(certs) > 0 {
|
||||
if certPub != nil {
|
||||
return errors.New("go-jose/go-jose: invalid JWK, found 'oct' (symmetric) key with cert chain")
|
||||
}
|
||||
key, err = raw.symmetricKey()
|
||||
@@ -289,8 +272,10 @@ func (k *JSONWebKey) unmarshalJSON(data []byte, allowPrivate bool) (err error) {
|
||||
return ErrUnsupportedKeyType
|
||||
}
|
||||
|
||||
if len(certs) > 0 && (certPub == nil || !reflect.DeepEqual(certPub, keyPub)) {
|
||||
return errors.New("go-jose/go-jose: invalid JWK, public keys in key and x5c fields do not match")
|
||||
if certPub != nil && keyPub != nil {
|
||||
if !reflect.DeepEqual(certPub, keyPub) {
|
||||
return errors.New("go-jose/go-jose: invalid JWK, public keys in key and x5c fields do not match")
|
||||
}
|
||||
}
|
||||
|
||||
*k = JSONWebKey{Key: key, KeyID: raw.Kid, Algorithm: raw.Alg, Use: raw.Use, Certificates: certs}
|
||||
@@ -407,9 +392,6 @@ func ecThumbprintInput(curve elliptic.Curve, x, y *big.Int) (string, error) {
|
||||
}
|
||||
|
||||
func rsaThumbprintInput(n *big.Int, e int) (string, error) {
|
||||
if n == nil || e <= 0 {
|
||||
return "", errors.New("go-jose/go-jose: invalid RSA key")
|
||||
}
|
||||
return fmt.Sprintf(rsaThumbprintTemplate,
|
||||
newBufferFromInt(uint64(e)).base64(),
|
||||
newBuffer(n.Bytes()).base64()), nil
|
||||
@@ -523,41 +505,14 @@ func (k *JSONWebKey) Valid() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// MaxRSAModulusBits is the largest RSA modulus size, in bits, that will be
|
||||
// accepted when parsing a JWK or verifying an x5c certificate chain with
|
||||
// [Header.Certificates]. Applications that need larger keys can raise this
|
||||
// limit.
|
||||
//
|
||||
// If modifying MaxRSAModulusBits, do it before any parsing occurs.
|
||||
var MaxRSAModulusBits = 4096
|
||||
|
||||
func (key rawJSONWebKey) rsaPublicKey() (*rsa.PublicKey, error) {
|
||||
return rsaPublicKey(key.N, key.E)
|
||||
}
|
||||
|
||||
func rsaPublicKey(N, E *byteBuffer) (*rsa.PublicKey, error) {
|
||||
if N == nil || E == nil {
|
||||
if key.N == nil || key.E == nil {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key, missing n/e values")
|
||||
}
|
||||
|
||||
n := N.bigInt()
|
||||
if n.BitLen() > MaxRSAModulusBits {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key, modulus too large")
|
||||
}
|
||||
|
||||
e := new(big.Int).SetBytes(E.bytes())
|
||||
if !e.IsInt64() {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key, bad e value")
|
||||
}
|
||||
|
||||
eInt64 := e.Int64()
|
||||
if eInt64 < 2 || eInt64 > math.MaxInt {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key, bad e value")
|
||||
}
|
||||
|
||||
return &rsa.PublicKey{
|
||||
N: n,
|
||||
E: int(eInt64),
|
||||
N: key.N.bigInt(),
|
||||
E: key.E.toInt(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -601,11 +556,11 @@ func (key rawJSONWebKey) ecPublicKey() (*ecdsa.PublicKey, error) {
|
||||
// The length of this octet string MUST be the full size of a coordinate for
|
||||
// the curve specified in the "crv" parameter.
|
||||
// https://tools.ietf.org/html/rfc7518#section-6.2.1.2
|
||||
if curveSize(curve) != len(key.X.bytes()) {
|
||||
if curveSize(curve) != len(key.X.data) {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: invalid EC public key, wrong length for x")
|
||||
}
|
||||
|
||||
if curveSize(curve) != len(key.Y.bytes()) {
|
||||
if curveSize(curve) != len(key.Y.data) {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: invalid EC public key, wrong length for y")
|
||||
}
|
||||
|
||||
@@ -718,21 +673,16 @@ func (key rawJSONWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: invalid RSA private key, missing %s value(s)", strings.Join(missing, ", "))
|
||||
}
|
||||
|
||||
pubKey, err := rsaPublicKey(key.N, key.E)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n := pubKey.N
|
||||
p, q := key.P.bigInt(), key.Q.bigInt()
|
||||
if p.BitLen()+q.BitLen() > n.BitLen()+1 || new(big.Int).Mul(p, q).Cmp(n) != 0 {
|
||||
return nil, errors.New("go-jose/go-jose: invalid RSA private key, p * q != n")
|
||||
}
|
||||
|
||||
rv := &rsa.PrivateKey{
|
||||
PublicKey: *pubKey,
|
||||
D: key.D.bigInt(),
|
||||
Primes: []*big.Int{p, q},
|
||||
PublicKey: rsa.PublicKey{
|
||||
N: key.N.bigInt(),
|
||||
E: key.E.toInt(),
|
||||
},
|
||||
D: key.D.bigInt(),
|
||||
Primes: []*big.Int{
|
||||
key.P.bigInt(),
|
||||
key.Q.bigInt(),
|
||||
},
|
||||
}
|
||||
|
||||
if key.Dp != nil {
|
||||
@@ -745,7 +695,7 @@ func (key rawJSONWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) {
|
||||
rv.Precomputed.Qinv = key.Qi.bigInt()
|
||||
}
|
||||
|
||||
err = rv.Validate()
|
||||
err := rv.Validate()
|
||||
return rv, err
|
||||
}
|
||||
|
||||
@@ -819,16 +769,16 @@ func (key rawJSONWebKey) ecPrivateKey() (*ecdsa.PrivateKey, error) {
|
||||
// The length of this octet string MUST be the full size of a coordinate for
|
||||
// the curve specified in the "crv" parameter.
|
||||
// https://tools.ietf.org/html/rfc7518#section-6.2.1.2
|
||||
if curveSize(curve) != len(key.X.bytes()) {
|
||||
if curveSize(curve) != len(key.X.data) {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: invalid EC private key, wrong length for x")
|
||||
}
|
||||
|
||||
if curveSize(curve) != len(key.Y.bytes()) {
|
||||
if curveSize(curve) != len(key.Y.data) {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: invalid EC private key, wrong length for y")
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/rfc7518#section-6.2.2.1
|
||||
if dSize(curve) != len(key.D.bytes()) {
|
||||
if dSize(curve) != len(key.D.data) {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: invalid EC private key, wrong length for d")
|
||||
}
|
||||
|
||||
|
||||
+33
-80
@@ -27,12 +27,6 @@ import (
|
||||
"github.com/go-jose/go-jose/v4/json"
|
||||
)
|
||||
|
||||
// MaxSignatures is the maximum number of signatures in a JWS at parse time.
|
||||
// Higher values mean more potential work done across untrusted input.
|
||||
//
|
||||
// If modifying MaxSignatures, do it before any parsing occurs.
|
||||
var MaxSignatures = 32
|
||||
|
||||
// rawJSONWebSignature represents a raw JWS JSON object. Used for parsing/serializing.
|
||||
type rawJSONWebSignature struct {
|
||||
Payload *byteBuffer `json:"payload,omitempty"`
|
||||
@@ -92,11 +86,6 @@ type Signature struct {
|
||||
// Verify() after parsing to validate the signature and obtain the payload.
|
||||
//
|
||||
// https://datatracker.ietf.org/doc/html/rfc7515#section-7
|
||||
//
|
||||
// The signatureAlgorithms parameter contains the allowable algorithms in the "alg" header parameter.
|
||||
// It must be non-empty. Non-matching algorithms cause a parse error.
|
||||
//
|
||||
// Deprecated: call ParseSignedJSON or ParseSignedCompact depending on which serialization you expect.
|
||||
func ParseSigned(
|
||||
signature string,
|
||||
signatureAlgorithms []SignatureAlgorithm,
|
||||
@@ -119,9 +108,6 @@ func ParseSigned(
|
||||
// Verify() after parsing to validate the signature and obtain the payload.
|
||||
//
|
||||
// https://datatracker.ietf.org/doc/html/rfc7515#section-7.1
|
||||
//
|
||||
// The signatureAlgorithms parameter contains the allowable algorithms in the "alg" header parameter.
|
||||
// It must be non-empty. Non-matching algorithms cause a parse error.
|
||||
func ParseSignedCompact(
|
||||
signature string,
|
||||
signatureAlgorithms []SignatureAlgorithm,
|
||||
@@ -139,9 +125,6 @@ func ParseSignedCompact(
|
||||
// parsing. Call Verify() after parsing to validate the signature and obtain the payload.
|
||||
//
|
||||
// https://datatracker.ietf.org/doc/html/rfc7515#appendix-F
|
||||
//
|
||||
// The signatureAlgorithms parameter contains the allowable algorithms in the "alg" header parameter.
|
||||
// It must be non-empty. Any non-allowed algorithms will cause parsing to fail.
|
||||
func ParseDetached(
|
||||
signature string,
|
||||
payload []byte,
|
||||
@@ -174,11 +157,7 @@ func (obj JSONWebSignature) computeAuthData(payload []byte, signature *Signature
|
||||
authData.WriteString(signature.original.Protected.base64())
|
||||
} else if signature.protected != nil {
|
||||
protectedHeader = signature.protected
|
||||
serializedProtected, err := json.Marshal(protectedHeader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authData.WriteString(base64.RawURLEncoding.EncodeToString(serializedProtected))
|
||||
authData.WriteString(base64.RawURLEncoding.EncodeToString(mustSerializeJSON(protectedHeader)))
|
||||
}
|
||||
|
||||
needsBase64 := true
|
||||
@@ -201,13 +180,9 @@ func (obj JSONWebSignature) computeAuthData(payload []byte, signature *Signature
|
||||
return authData.Bytes(), nil
|
||||
}
|
||||
|
||||
// ParseSignedJSON parses a message in JWS JSON Serialization. Messages with
|
||||
// more than [MaxSignatures] signatures are rejected.
|
||||
// ParseSignedJSON parses a message in JWS JSON Serialization.
|
||||
//
|
||||
// https://datatracker.ietf.org/doc/html/rfc7515#section-7.2
|
||||
//
|
||||
// The signatureAlgorithms parameter contains the allowable algorithms in the "alg" header parameter.
|
||||
// It must be non-empty. Non-matching algorithms cause a parse error.
|
||||
func ParseSignedJSON(
|
||||
input string,
|
||||
signatureAlgorithms []SignatureAlgorithm,
|
||||
@@ -261,9 +236,6 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
|
||||
if parsed.Payload == nil {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: missing payload in JWS message")
|
||||
}
|
||||
if len(parsed.Signatures) > MaxSignatures {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: too many signatures in JWS; maximum is %d", MaxSignatures)
|
||||
}
|
||||
|
||||
obj := &JSONWebSignature{
|
||||
payload: parsed.Payload.bytes(),
|
||||
@@ -273,13 +245,14 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
|
||||
if len(parsed.Signatures) == 0 {
|
||||
// No signatures array, must be flattened serialization
|
||||
signature := Signature{}
|
||||
prot, err := parseProtectedHeader(parsed.Protected)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
|
||||
signature.protected = &rawHeader{}
|
||||
err := json.Unmarshal(parsed.Protected.bytes(), signature.protected)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
signature.protected = prot
|
||||
|
||||
// Check that there is not a nonce in the unprotected header
|
||||
if parsed.Header != nil && parsed.Header.getNonce() != "" {
|
||||
return nil, ErrUnprotectedNonce
|
||||
@@ -302,17 +275,17 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
|
||||
Signature: parsed.Signature,
|
||||
}
|
||||
|
||||
mergedHeaders := signature.mergedHeaders()
|
||||
alg := mergedHeaders.getSignatureAlgorithm()
|
||||
if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
|
||||
return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms)
|
||||
}
|
||||
|
||||
signature.Header, err = mergedHeaders.sanitized()
|
||||
var err error
|
||||
signature.Header, err = signature.mergedHeaders().sanitized()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
alg := SignatureAlgorithm(signature.Header.Algorithm)
|
||||
if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
|
||||
return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms)
|
||||
}
|
||||
|
||||
if signature.header != nil {
|
||||
signature.Unprotected, err = signature.header.sanitized()
|
||||
if err != nil {
|
||||
@@ -337,31 +310,30 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
|
||||
}
|
||||
|
||||
for i, sig := range parsed.Signatures {
|
||||
prot, err := parseProtectedHeader(sig.Protected)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if sig.Protected != nil && len(sig.Protected.bytes()) > 0 {
|
||||
obj.Signatures[i].protected = &rawHeader{}
|
||||
err := json.Unmarshal(sig.Protected.bytes(), obj.Signatures[i].protected)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
obj.Signatures[i].protected = prot
|
||||
|
||||
// Check that there is not a nonce in the unprotected header
|
||||
if sig.Header != nil && sig.Header.getNonce() != "" {
|
||||
return nil, ErrUnprotectedNonce
|
||||
}
|
||||
|
||||
obj.Signatures[i].header = sig.Header
|
||||
|
||||
mergedHeaders := obj.Signatures[i].mergedHeaders()
|
||||
alg := mergedHeaders.getSignatureAlgorithm()
|
||||
if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
|
||||
return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms)
|
||||
}
|
||||
|
||||
obj.Signatures[i].Header, err = mergedHeaders.sanitized()
|
||||
var err error
|
||||
obj.Signatures[i].Header, err = obj.Signatures[i].mergedHeaders().sanitized()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
alg := SignatureAlgorithm(obj.Signatures[i].Header.Algorithm)
|
||||
if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
|
||||
return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms)
|
||||
}
|
||||
|
||||
if obj.Signatures[i].header != nil {
|
||||
obj.Signatures[i].Unprotected, err = obj.Signatures[i].header.sanitized()
|
||||
if err != nil {
|
||||
@@ -387,6 +359,7 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
|
||||
// Copy value of sig
|
||||
original := sig
|
||||
|
||||
obj.Signatures[i].header = sig.Header
|
||||
obj.Signatures[i].original = &original
|
||||
}
|
||||
|
||||
@@ -451,10 +424,7 @@ func (obj JSONWebSignature) compactSerialize(detached bool) (string, error) {
|
||||
return "", ErrNotSupported
|
||||
}
|
||||
|
||||
serializedProtected, err := json.Marshal(obj.Signatures[0].protected)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
serializedProtected := mustSerializeJSON(obj.Signatures[0].protected)
|
||||
|
||||
var payload []byte
|
||||
if !detached {
|
||||
@@ -479,23 +449,14 @@ func (obj JSONWebSignature) DetachedCompactSerialize() (string, error) {
|
||||
}
|
||||
|
||||
// FullSerialize serializes an object using the full JSON serialization format.
|
||||
//
|
||||
// It returns "" if obj cannot be serialized.
|
||||
func (obj JSONWebSignature) FullSerialize() string {
|
||||
raw := rawJSONWebSignature{
|
||||
Payload: newBuffer(obj.payload),
|
||||
}
|
||||
|
||||
if len(obj.Signatures) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
if len(obj.Signatures) == 1 {
|
||||
if obj.Signatures[0].protected != nil {
|
||||
serializedProtected, err := json.Marshal(obj.Signatures[0].protected)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
serializedProtected := mustSerializeJSON(obj.Signatures[0].protected)
|
||||
raw.Protected = newBuffer(serializedProtected)
|
||||
}
|
||||
raw.Header = obj.Signatures[0].header
|
||||
@@ -509,18 +470,10 @@ func (obj JSONWebSignature) FullSerialize() string {
|
||||
}
|
||||
|
||||
if signature.protected != nil {
|
||||
serializedProtected, err := json.Marshal(signature.protected)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
raw.Signatures[i].Protected = newBuffer(serializedProtected)
|
||||
raw.Signatures[i].Protected = newBuffer(mustSerializeJSON(signature.protected))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out, err := json.Marshal(raw)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(out)
|
||||
return string(mustSerializeJSON(raw))
|
||||
}
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ var ErrNotValidYet = errors.New("go-jose/go-jose/jwt: validation failed, token n
|
||||
var ErrExpired = errors.New("go-jose/go-jose/jwt: validation failed, token is expired (exp)")
|
||||
|
||||
// ErrIssuedInTheFuture indicates that the iat field is in the future.
|
||||
var ErrIssuedInTheFuture = errors.New("go-jose/go-jose/jwt: validation failed, token issued in the future (iat)")
|
||||
var ErrIssuedInTheFuture = errors.New("go-jose/go-jose/jwt: validation field, token issued in the future (iat)")
|
||||
|
||||
// ErrInvalidContentType indicates that token requires JWT cty header.
|
||||
var ErrInvalidContentType = errors.New("go-jose/go-jose/jwt: expected content type to be JWT (cty header)")
|
||||
|
||||
+17
-12
@@ -85,12 +85,7 @@ func (t *NestedJSONWebToken) Decrypt(decryptionKey interface{}) (*JSONWebToken,
|
||||
return sig, nil
|
||||
}
|
||||
|
||||
// ParseSigned parses a JWT in the JWS Compact Serialization.
|
||||
//
|
||||
// https://datatracker.ietf.org/doc/html/rfc7515#section-3.1
|
||||
//
|
||||
// The signatureAlgorithms parameter contains the allowable algorithms in the "alg" header parameter.
|
||||
// It must be non-empty. Non-matching algorithms cause a parse error.
|
||||
// ParseSigned parses token from JWS form.
|
||||
func ParseSigned(s string, signatureAlgorithms []jose.SignatureAlgorithm) (*JSONWebToken, error) {
|
||||
sig, err := jose.ParseSignedCompact(s, signatureAlgorithms)
|
||||
if err != nil {
|
||||
@@ -147,10 +142,13 @@ func parseEncryptedCompact(
|
||||
return enc, nil
|
||||
}
|
||||
|
||||
// ParseEncrypted parses a JWT in the JWE Compact Serialization.
|
||||
// ParseEncrypted parses token from JWE form.
|
||||
//
|
||||
// The keyAlgorithms and contentEncryption parameters contain the allowable algorithms in the "alg" and "enc"
|
||||
// header parameters respectively. They must be non-empty. Non-matching algorithms cause a parse error.
|
||||
// The keyAlgorithms and contentEncryption parameters are used to validate the "alg" and "enc"
|
||||
// header parameters respectively. They must be nonempty, and each "alg" or "enc" header in
|
||||
// parsed data must contain a value that is present in the corresponding parameter. That
|
||||
// includes the protected and unprotected headers as well as all recipients. To accept
|
||||
// multiple algorithms, pass a slice of all the algorithms you want to accept.
|
||||
func ParseEncrypted(s string,
|
||||
keyAlgorithms []jose.KeyAlgorithm,
|
||||
contentEncryption []jose.ContentEncryption,
|
||||
@@ -166,10 +164,17 @@ func ParseEncrypted(s string,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ParseSignedAndEncrypted parses a signed-then-encrypted token in the JWE Compact Serialization.
|
||||
// ParseSignedAndEncrypted parses signed-then-encrypted token from JWE form.
|
||||
//
|
||||
// The encryptionKeyAlgorithms, contentEncryption, and signatureAlgorithms parameters contain the allowable
|
||||
// algorithms. They must be non-empty. Non-matching algorithms cause a parse error.
|
||||
// The encryptionKeyAlgorithms and contentEncryption parameters are used to validate the "alg" and "enc"
|
||||
// header parameters, respectively, of the outer JWE. They must be nonempty, and each "alg" or "enc"
|
||||
// header in parsed data must contain a value that is present in the corresponding parameter. That
|
||||
// includes the protected and unprotected headers as well as all recipients. To accept
|
||||
// multiple algorithms, pass a slice of all the algorithms you want to accept.
|
||||
//
|
||||
// The signatureAlgorithms parameter is used to validate the "alg" header parameter of the
|
||||
// inner JWS. It must be nonempty, and the "alg" header in the inner JWS must contain a value
|
||||
// that is present in the parameter.
|
||||
func ParseSignedAndEncrypted(s string,
|
||||
encryptionKeyAlgorithms []jose.KeyAlgorithm,
|
||||
contentEncryption []jose.ContentEncryption,
|
||||
|
||||
+37
-43
@@ -18,7 +18,6 @@ package jose
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
@@ -211,20 +210,13 @@ type Header struct {
|
||||
|
||||
// Certificates verifies & returns the certificate chain present
|
||||
// in the x5c header field of a message, if one was present. Returns
|
||||
// an error if there was no x5c header present, any certificate in the
|
||||
// chain has an RSA key larger than [MaxRSAModulusBits], or the chain could
|
||||
// an error if there was no x5c header present or the chain could
|
||||
// not be validated with the given verify options.
|
||||
func (h Header) Certificates(opts x509.VerifyOptions) ([][]*x509.Certificate, error) {
|
||||
if len(h.certificates) == 0 {
|
||||
return nil, ErrMissingX5cHeader
|
||||
}
|
||||
|
||||
for _, cert := range h.certificates {
|
||||
if pub, ok := cert.PublicKey.(*rsa.PublicKey); ok && pub.N.BitLen() > MaxRSAModulusBits {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key in x5c certificate, modulus too large")
|
||||
}
|
||||
}
|
||||
|
||||
leaf := h.certificates[0]
|
||||
if opts.Intermediates == nil {
|
||||
opts.Intermediates = x509.NewCertPool()
|
||||
@@ -305,10 +297,9 @@ func (parsed rawHeader) getEPK() (*JSONWebKey, error) {
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
// RFC 7518 Section 4.6.1.1: the "epk" header is the ephemeral public key
|
||||
// of the originator. Reject private key material before parsing it.
|
||||
epk := new(JSONWebKey)
|
||||
if err := epk.unmarshalJSON(*v, false); err != nil {
|
||||
var epk *JSONWebKey
|
||||
err := json.Unmarshal(*v, &epk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return epk, nil
|
||||
@@ -334,6 +325,20 @@ func (parsed rawHeader) getTag() (*byteBuffer, error) {
|
||||
return parsed.getByteBuffer(headerTag)
|
||||
}
|
||||
|
||||
// getJWK extracts parsed "jwk" from the raw JSON.
|
||||
func (parsed rawHeader) getJWK() (*JSONWebKey, error) {
|
||||
v := parsed[headerJWK]
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
var jwk *JSONWebKey
|
||||
err := json.Unmarshal(*v, &jwk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return jwk, nil
|
||||
}
|
||||
|
||||
// getCritical extracts parsed "crit" from the raw JSON. If omitted, it
|
||||
// returns an empty slice.
|
||||
func (parsed rawHeader) getCritical() ([]string, error) {
|
||||
@@ -419,14 +424,10 @@ func (parsed rawHeader) sanitized() (h Header, err error) {
|
||||
}
|
||||
switch k {
|
||||
case headerJWK:
|
||||
// RFC 7515 Section 4.1.3 and RFC 7516 Section 4.1.5: the "jwk"
|
||||
// header is the public key that corresponds to the key used to
|
||||
// sign the JWS or encrypt the JWE. Reject private key material
|
||||
// before parsing it.
|
||||
jwk := new(JSONWebKey)
|
||||
err = jwk.unmarshalJSON(*v, false)
|
||||
var jwk *JSONWebKey
|
||||
err = json.Unmarshal(*v, &jwk)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to unmarshal JWK: %w", err)
|
||||
err = fmt.Errorf("failed to unmarshal JWK: %v: %#v", err, string(*v))
|
||||
return
|
||||
}
|
||||
h.JSONWebKey = jwk
|
||||
@@ -498,8 +499,22 @@ func parseCertificateChain(chain []string) ([]*x509.Certificate, error) {
|
||||
}
|
||||
|
||||
func (parsed rawHeader) isSet(k HeaderKey) bool {
|
||||
_, ok := parsed[k]
|
||||
return ok
|
||||
dvr := parsed[k]
|
||||
if dvr == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
var dv interface{}
|
||||
err := json.Unmarshal(*dvr, &dv)
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if dvStr, ok := dv.(string); ok {
|
||||
return dvStr != ""
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Merge headers from src into dst, giving precedence to headers from l.
|
||||
@@ -549,24 +564,3 @@ func makeRawMessage(b []byte) *json.RawMessage {
|
||||
rm := json.RawMessage(b)
|
||||
return &rm
|
||||
}
|
||||
|
||||
// parseProtectedHeader parses a `byteBuffer` into a `*rawHeader`.
|
||||
//
|
||||
// The byteBuffer represents a base64-decoded "protected" header, which
|
||||
// is specified to contain a JSON object.
|
||||
//
|
||||
// If the input is nil or empty, returns `nil, nil`.
|
||||
//
|
||||
// `rawHeader` is a map type and so can be nil. When this function
|
||||
// returns a non-nil `*rawHeader`, the map is guaranteed to be non-nil.
|
||||
func parseProtectedHeader(in *byteBuffer) (*rawHeader, error) {
|
||||
if in == nil || len(in.bytes()) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
var header rawHeader
|
||||
err := json.Unmarshal(in.bytes(), &header)
|
||||
if err != nil || header == nil {
|
||||
return nil, errors.New("go-jose/go-jose: invalid protected header")
|
||||
}
|
||||
return &header, nil
|
||||
}
|
||||
|
||||
+1
-4
@@ -321,10 +321,7 @@ func (ctx *genericSigner) Sign(payload []byte) (*JSONWebSignature, error) {
|
||||
protected[k] = v
|
||||
}
|
||||
|
||||
serializedProtected, err := json.Marshal(protected)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: Error marshaling JSON: %s", err)
|
||||
}
|
||||
serializedProtected := mustSerializeJSON(protected)
|
||||
needsBase64 := true
|
||||
|
||||
if b64, ok := protected[headerB64]; ok {
|
||||
|
||||
+1
-1
@@ -421,7 +421,7 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: invalid P2S: %v", err)
|
||||
}
|
||||
if p2s == nil || len(p2s.bytes()) == 0 {
|
||||
if p2s == nil || len(p2s.data) == 0 {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: invalid P2S: must be present")
|
||||
}
|
||||
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
# This containerfile can be used to run the go-jose tests and cli
|
||||
|
||||
FROM golang:1.27-trixie
|
||||
ENV GOTOOLCHAIN=local
|
||||
|
||||
COPY . /src
|
||||
WORKDIR /src
|
||||
|
||||
# Install the jose-util cli, which will also build the library
|
||||
RUN go build -o /usr/local/bin/jose-util ./jose-util
|
||||
|
||||
# By default, run the tests
|
||||
CMD ["go", "test", "./..."]
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
# Threat model
|
||||
|
||||
## What this project does and where untrusted input enters
|
||||
go-jose is a Go implementation of JOSE family of algorithms.
|
||||
|
||||
It is a library which will parse attacker-controlled data in network-reachable
|
||||
services.
|
||||
|
||||
## Components that matter most / least
|
||||
The primary attack surface of interest is parsing and validating JWS, JWE, JWK,
|
||||
etc when this library is used to implement authentication and authorization.
|
||||
|
||||
## How to exercise it
|
||||
Testing is primarily done by Golang unit tests, which can be run with the
|
||||
tests.Container file's default CMD.
|
||||
|
||||
## How you rate severity
|
||||
Any authentication bypass enabled by a go-jose issue is a high+ severity.
|
||||
|
||||
Denial-of-service attacks are of interest when the functions may be used in a protocol like OIDC, ACME, etc
|
||||
which could have a server processing attacker-controlled data.
|
||||
|
||||
## Anything to leave alone
|
||||
Any bug which only affects the jose-util CLI tool, but it can be used to exercise the library.
|
||||
|
||||
+1
-2
@@ -659,8 +659,7 @@ func (s *Scratch) validateNorm() (err error) {
|
||||
if v >= 0 {
|
||||
total += int(v)
|
||||
} else {
|
||||
// -1 takes one cell. Adding -v would let a wrapped -32768 pass.
|
||||
total++
|
||||
total -= int(v)
|
||||
}
|
||||
}
|
||||
defer func() {
|
||||
|
||||
-6
@@ -3,7 +3,6 @@ package fse
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -124,11 +123,6 @@ func (s *Scratch) readNCount() error {
|
||||
remaining -= count
|
||||
gotTotal += count
|
||||
}
|
||||
if count > math.MaxInt16 {
|
||||
// Only one symbol filling a tableLog 15 table, which cannot be decoded.
|
||||
// Truncated, it would leave the decoding table unwritten.
|
||||
return fmt.Errorf("corruption detected (count %d > %d)", count, math.MaxInt16)
|
||||
}
|
||||
s.norm[charnum&0xff] = int16(count)
|
||||
charnum++
|
||||
previous0 = count == 0
|
||||
|
||||
-4
@@ -54,10 +54,6 @@ func ReadTable(in []byte, s *Scratch) (s2 *Scratch, remain []byte, err error) {
|
||||
if len(in) < int(iSize) {
|
||||
return s, nil, fmt.Errorf("input too small for table, want %d bytes, have %d", iSize, len(in))
|
||||
}
|
||||
// The low nibble is the weights' FSE tableLog - 5, which the format limits to 6.
|
||||
if in[0]&15+5 > 6 {
|
||||
return s, nil, errors.New("corrupt input: weights tableLog too big")
|
||||
}
|
||||
// FSE compressed weights
|
||||
s.fse.DecompressLimit = 255
|
||||
hw := s.huffWeight[:]
|
||||
|
||||
-3
@@ -219,9 +219,6 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
|
||||
if len(contents) == 0 {
|
||||
return nil, errors.New("no content provided")
|
||||
}
|
||||
if o.Level < speedNotSet || o.Level >= speedLast {
|
||||
return nil, fmt.Errorf("unknown encoder level %d", o.Level)
|
||||
}
|
||||
d := dict{
|
||||
id: o.ID,
|
||||
litEnc: nil,
|
||||
|
||||
-12
@@ -69,10 +69,6 @@ var (
|
||||
// No CRC value is being generated and not all CRC values of the Snappy stream are checked.
|
||||
// However, it provides really fast recompression of Snappy streams.
|
||||
// The converter can be reused to avoid allocations, even after errors.
|
||||
//
|
||||
// Deprecated: Decode the stream with s2.NewReader, which reads Snappy streams,
|
||||
// and compress the output with an Encoder. This validates the input and
|
||||
// compresses much better.
|
||||
type SnappyConverter struct {
|
||||
r io.Reader
|
||||
err error
|
||||
@@ -377,14 +373,6 @@ func decodeSnappy(blk *blockEnc, src []byte) error {
|
||||
offset = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
|
||||
}
|
||||
|
||||
// A zstd match is at least zstdMinMatch bytes. A shorter copy
|
||||
// cannot be represented as a sequence and would underflow the
|
||||
// matchLen computation below, producing an out-of-range match
|
||||
// length code.
|
||||
if length < zstdMinMatch {
|
||||
return ErrSnappyCorrupt
|
||||
}
|
||||
|
||||
if offset <= 0 || blk.size+lits < int(offset) /*|| length > len(blk)-d */ {
|
||||
println("offset <= 0 || blk.size+lits < int(offset)", offset, blk.size+lits, int(offset), blk.size, lits)
|
||||
|
||||
|
||||
-1
@@ -52,7 +52,6 @@ func (es *EndpointSettings) Copy() *EndpointSettings {
|
||||
epCopy.Aliases = slices.Clone(es.Aliases)
|
||||
epCopy.DNSNames = slices.Clone(es.DNSNames)
|
||||
epCopy.DriverOpts = maps.Clone(es.DriverOpts)
|
||||
epCopy.MacAddress = slices.Clone(es.MacAddress)
|
||||
|
||||
return &epCopy
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
testdata/rapid/**
|
||||
+2
-2
@@ -108,7 +108,7 @@ const DummyHost = "api.moby.localhost"
|
||||
// overriding the version and disable API-version negotiation.
|
||||
//
|
||||
// This version may be lower than the version of the api library module used.
|
||||
const MaxAPIVersion = "1.57"
|
||||
const MaxAPIVersion = "1.56"
|
||||
|
||||
// MinAPIVersion is the minimum API version supported by the client. API versions
|
||||
// below this version are not considered when performing API-version negotiation.
|
||||
@@ -436,7 +436,7 @@ func (cli *Client) dialer() func(context.Context) (net.Conn, error) {
|
||||
return dialPipeContext(ctx, cli.addr)
|
||||
default:
|
||||
if tlsConfig := cli.tlsConfig(); tlsConfig != nil {
|
||||
return (&tls.Dialer{Config: tlsConfig}).DialContext(ctx, cli.proto, cli.addr)
|
||||
return tls.Dial(cli.proto, cli.addr, tlsConfig)
|
||||
}
|
||||
return net.Dial(cli.proto, cli.addr)
|
||||
}
|
||||
|
||||
+1
-3
@@ -100,10 +100,8 @@ func (cli *Client) setupHijackConn(req *http.Request, proto string) (retConn net
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
// Closing the body ends the otelhttp span. A 101 response has no body,
|
||||
// so this does not close the connection.
|
||||
_ = resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusSwitchingProtocols {
|
||||
_ = resp.Body.Close()
|
||||
return nil, "", fmt.Errorf("unable to upgrade to %s, received %d", proto, resp.StatusCode)
|
||||
}
|
||||
|
||||
|
||||
+9
-60
@@ -22,7 +22,7 @@ file {
|
||||
java_package: "com.google.protobuf"
|
||||
java_outer_classname: "TimestampProto"
|
||||
java_multiple_files: true
|
||||
go_package: "google.golang.org/protobuf/types/known/timestamppb"
|
||||
go_package: "github.com/golang/protobuf/ptypes/timestamp"
|
||||
cc_enable_arenas: true
|
||||
objc_class_prefix: "GPB"
|
||||
csharp_namespace: "Google.Protobuf.WellKnownTypes"
|
||||
@@ -53,7 +53,7 @@ file {
|
||||
java_package: "com.google.protobuf"
|
||||
java_outer_classname: "DurationProto"
|
||||
java_multiple_files: true
|
||||
go_package: "google.golang.org/protobuf/types/known/durationpb"
|
||||
go_package: "github.com/golang/protobuf/ptypes/duration"
|
||||
cc_enable_arenas: true
|
||||
objc_class_prefix: "GPB"
|
||||
csharp_namespace: "Google.Protobuf.WellKnownTypes"
|
||||
@@ -157,7 +157,7 @@ file {
|
||||
java_package: "com.google.protobuf"
|
||||
java_outer_classname: "WrappersProto"
|
||||
java_multiple_files: true
|
||||
go_package: "google.golang.org/protobuf/types/known/wrapperspb"
|
||||
go_package: "github.com/golang/protobuf/ptypes/wrappers"
|
||||
cc_enable_arenas: true
|
||||
objc_class_prefix: "GPB"
|
||||
csharp_namespace: "Google.Protobuf.WellKnownTypes"
|
||||
@@ -484,13 +484,6 @@ file {
|
||||
type_name: ".google.protobuf.FieldOptions"
|
||||
json_name: "options"
|
||||
}
|
||||
field {
|
||||
name: "proto3_optional"
|
||||
number: 17
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_BOOL
|
||||
json_name: "proto3Optional"
|
||||
}
|
||||
enum_type {
|
||||
name: "Type"
|
||||
value {
|
||||
@@ -860,7 +853,7 @@ file {
|
||||
number: 31
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_BOOL
|
||||
default_value: "true"
|
||||
default_value: "false"
|
||||
json_name: "ccEnableArenas"
|
||||
}
|
||||
field {
|
||||
@@ -1412,7 +1405,7 @@ file {
|
||||
java_package: "com.google.protobuf"
|
||||
java_outer_classname: "DescriptorProtos"
|
||||
optimize_for: SPEED
|
||||
go_package: "google.golang.org/protobuf/types/descriptorpb"
|
||||
go_package: "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor"
|
||||
cc_enable_arenas: true
|
||||
objc_class_prefix: "GPB"
|
||||
csharp_namespace: "Google.Protobuf.Reflection"
|
||||
@@ -5215,7 +5208,7 @@ file {
|
||||
java_package: "com.google.protobuf"
|
||||
java_outer_classname: "AnyProto"
|
||||
java_multiple_files: true
|
||||
go_package: "google.golang.org/protobuf/types/known/anypb"
|
||||
go_package: "github.com/golang/protobuf/ptypes/any"
|
||||
objc_class_prefix: "GPB"
|
||||
csharp_namespace: "Google.Protobuf.WellKnownTypes"
|
||||
}
|
||||
@@ -10597,7 +10590,7 @@ file {
|
||||
syntax: "proto3"
|
||||
}
|
||||
file {
|
||||
name: "go.etcd.io/raft/v3/raftpb/raft.proto"
|
||||
name: "go.etcd.io/etcd/raft/v3/raftpb/raft.proto"
|
||||
package: "raftpb"
|
||||
dependency: "gogoproto/gogo.proto"
|
||||
message_type {
|
||||
@@ -10780,16 +10773,6 @@ file {
|
||||
}
|
||||
json_name: "commit"
|
||||
}
|
||||
field {
|
||||
name: "vote"
|
||||
number: 13
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_UINT64
|
||||
options {
|
||||
65001: 0
|
||||
}
|
||||
json_name: "vote"
|
||||
}
|
||||
field {
|
||||
name: "snapshot"
|
||||
number: 9
|
||||
@@ -10797,7 +10780,7 @@ file {
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".raftpb.Snapshot"
|
||||
options {
|
||||
65001: 1
|
||||
65001: 0
|
||||
}
|
||||
json_name: "snapshot"
|
||||
}
|
||||
@@ -10826,22 +10809,8 @@ file {
|
||||
number: 12
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_BYTES
|
||||
options {
|
||||
65001: 1
|
||||
}
|
||||
json_name: "context"
|
||||
}
|
||||
field {
|
||||
name: "responses"
|
||||
number: 14
|
||||
label: LABEL_REPEATED
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".raftpb.Message"
|
||||
options {
|
||||
65001: 0
|
||||
}
|
||||
json_name: "responses"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "HardState"
|
||||
@@ -11110,26 +11079,6 @@ file {
|
||||
name: "MsgPreVoteResp"
|
||||
number: 18
|
||||
}
|
||||
value {
|
||||
name: "MsgStorageAppend"
|
||||
number: 19
|
||||
}
|
||||
value {
|
||||
name: "MsgStorageAppendResp"
|
||||
number: 20
|
||||
}
|
||||
value {
|
||||
name: "MsgStorageApply"
|
||||
number: 21
|
||||
}
|
||||
value {
|
||||
name: "MsgStorageApplyResp"
|
||||
number: 22
|
||||
}
|
||||
value {
|
||||
name: "MsgForgetLeader"
|
||||
number: 23
|
||||
}
|
||||
}
|
||||
enum_type {
|
||||
name: "ConfChangeTransition"
|
||||
@@ -11181,7 +11130,7 @@ file {
|
||||
package: "docker.swarmkit.v1"
|
||||
dependency: "github.com/docker/swarmkit/api/objects.proto"
|
||||
dependency: "github.com/docker/swarmkit/api/types.proto"
|
||||
dependency: "go.etcd.io/raft/v3/raftpb/raft.proto"
|
||||
dependency: "go.etcd.io/etcd/raft/v3/raftpb/raft.proto"
|
||||
dependency: "gogoproto/gogo.proto"
|
||||
dependency: "github.com/docker/swarmkit/protobuf/plugin/plugin.proto"
|
||||
message_type {
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ type CopierFrom interface {
|
||||
// Copy takes the fields from src and copies them into the target object.
|
||||
//
|
||||
// Calling this method with a nil receiver or a nil src may panic.
|
||||
CopyFrom(src any)
|
||||
CopyFrom(src interface{})
|
||||
}
|
||||
|
||||
// Copy copies src into dst. dst and src must have the same type.
|
||||
@@ -24,7 +24,7 @@ type CopierFrom interface {
|
||||
//
|
||||
// If the copy cannot be performed, this function will panic. Make sure to test
|
||||
// types that use this function.
|
||||
func Copy(dst, src any) {
|
||||
func Copy(dst, src interface{}) {
|
||||
switch dst := dst.(type) {
|
||||
case *types.Any:
|
||||
src := src.(*types.Any)
|
||||
|
||||
+2
-2
@@ -73,7 +73,7 @@ func customIndexer(kind string, annotations *Annotations) (bool, [][]byte, error
|
||||
return len(converted) != 0, converted, nil
|
||||
}
|
||||
|
||||
func fromArgs(args ...any) ([]byte, error) {
|
||||
func fromArgs(args ...interface{}) ([]byte, error) {
|
||||
if len(args) != 1 {
|
||||
return nil, fmt.Errorf("must provide only a single argument")
|
||||
}
|
||||
@@ -86,7 +86,7 @@ func fromArgs(args ...any) ([]byte, error) {
|
||||
return []byte(arg), nil
|
||||
}
|
||||
|
||||
func prefixFromArgs(args ...any) ([]byte, error) {
|
||||
func prefixFromArgs(args ...interface{}) ([]byte, error) {
|
||||
val, err := fromArgs(args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
-16
@@ -5,21 +5,6 @@ from https://github.com/syndtr/gocapability/commit/42c35b4376354fd5.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.5.0] - 2026-10-23
|
||||
|
||||
### Breaking changes
|
||||
* Go 1.24 or later is now required. (#264)
|
||||
|
||||
### Fixed
|
||||
* [LastCap] no longer reads `/proc/sys/kernel/cap_last_cap`, querying the
|
||||
kernel via `prctl(PR_CAPBSET_READ)` instead. This makes the package work
|
||||
when `/proc` is not mounted, and fixes a possible panic or infinite loop
|
||||
when `/proc/sys/kernel/cap_last_cap` contains a bogus value (for example,
|
||||
if something is mounted over `/proc`). (#265, #269)
|
||||
|
||||
### Changed
|
||||
* Minor code cleanups. (#187)
|
||||
|
||||
## [0.4.0] - 2024-11-11
|
||||
|
||||
### Added
|
||||
@@ -119,7 +104,6 @@ This is an initial release since the fork.
|
||||
[SetAmbient]: https://pkg.go.dev/github.com/moby/sys/capability#SetAmbient
|
||||
|
||||
<!-- Minor releases. -->
|
||||
[0.5.0]: https://github.com/moby/sys/releases/tag/capability%2Fv0.5.0
|
||||
[0.4.0]: https://github.com/moby/sys/releases/tag/capability%2Fv0.4.0
|
||||
[0.3.0]: https://github.com/moby/sys/releases/tag/capability%2Fv0.3.0
|
||||
[0.2.0]: https://github.com/moby/sys/releases/tag/capability%2Fv0.2.0
|
||||
|
||||
+15
-63
@@ -13,6 +13,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
@@ -24,75 +25,26 @@ const (
|
||||
linuxCapVer3 = 0x20080522
|
||||
)
|
||||
|
||||
// capValid reports whether the running kernel supports capability c.
|
||||
func capValid(c Cap) (bool, error) {
|
||||
err := prctl(syscall.PR_CAPBSET_READ, uintptr(c), 0)
|
||||
if errors.Is(err, syscall.EINVAL) {
|
||||
return false, nil
|
||||
}
|
||||
return err == nil, err
|
||||
}
|
||||
|
||||
// lastCap returns the highest capability supported by the running kernel.
|
||||
var lastCap = sync.OnceValues(func() (Cap, error) {
|
||||
last, err := findLastCap()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("unable to get last capability: %w", err)
|
||||
}
|
||||
return last, nil
|
||||
})
|
||||
|
||||
func findLastCap() (Cap, error) {
|
||||
// Based on the fact Go 1.24+ supports Linux >= 3.2, and
|
||||
// - CAP_WAKE_ALARM (35) was added in 3.0;
|
||||
// - CAP_CHECKPOINT_RESTORE (40) was added in 5.9, and it is
|
||||
// the last added capability as of October 2026 (Linux 7.3);
|
||||
//
|
||||
// the last capability is at least minLastCap, and most probably
|
||||
// lastKnownCap (but newer kernels may have more).
|
||||
//
|
||||
// maxLastCap is the highest capability which can be represented
|
||||
// by the kernel capability ABI v3 (two 32-bit words per set).
|
||||
const (
|
||||
minLastCap = CAP_WAKE_ALARM
|
||||
lastKnownCap = CAP_CHECKPOINT_RESTORE
|
||||
maxLastCap = Cap(63)
|
||||
)
|
||||
|
||||
// Start from lastKnownCap, and go up if it's valid, or down if it's
|
||||
// not. For most kernels, this takes two syscalls.
|
||||
c := lastKnownCap
|
||||
ok, err := capValid(c)
|
||||
f, err := os.Open("/proc/sys/kernel/cap_last_cap")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if ok {
|
||||
// Go up while the next one is valid.
|
||||
for c < maxLastCap {
|
||||
ok, err := capValid(c + 1)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
c++
|
||||
}
|
||||
return c, nil
|
||||
|
||||
buf := make([]byte, 11)
|
||||
l, err := f.Read(buf)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// Go down until a valid one is found.
|
||||
for c > minLastCap {
|
||||
c--
|
||||
ok, err := capValid(c)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if ok {
|
||||
return c, nil
|
||||
}
|
||||
buf = buf[:l]
|
||||
|
||||
last, err := strconv.Atoi(strings.TrimSpace(string(buf)))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return 0, fmt.Errorf("PR_CAPBSET_READ returned EINVAL for %s", minLastCap)
|
||||
}
|
||||
return Cap(last), nil
|
||||
})
|
||||
|
||||
func capUpperMask() uint32 {
|
||||
last, err := lastCap()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user