Compare commits

...
141 Commits
Author SHA1 Message Date
Paweł Gronowski 7c0f1b261a Merge pull request #7493 from vvoland/update-docker
vendor: github.com/moby/moby master
2026-11-06 02:29:17 +01:00
Paweł Gronowski e863f84b15 vendor: github.com/moby/moby/client v0.7.0-dev (402d0a16f131)
full diff: https://github.com/moby/moby/compare/client/v0.6.2...402d0a16f131

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-11-06 02:23:19 +01:00
Paweł Gronowski e969249cf5 vendor: github.com/moby/moby/api v1.57.0-dev (402d0a16f131)
full diff: https://github.com/moby/moby/compare/api/v1.56.1...402d0a16f131

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-11-06 02:21:44 +01:00
Paweł Gronowski bad50f6bbe Merge pull request #7492 from thaJeztah/bump_capability
vendor: github.com/moby/sys/capability v0.5.0
2026-11-06 01:14:22 +01:00
Sebastiaan van Stijn 89e99a7ee4 Merge pull request #7393 from renovate-bot/renovate/psampaz-go-mod-outdated-0.x
chore(deps): update psampaz/go-mod-outdated docker tag to v0.9.0
2026-11-06 00:37:20 +01:00
Sebastiaan van Stijn e63c04ae28 vendor: github.com/moby/sys/capability v0.5.0
full diff: https://github.com/moby/sys/compare/capability/v0.4.0...capability/v0.5.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-06 00:23:28 +01:00
Sebastiaan van Stijn c3a866740e Merge pull request #7488 from thaJeztah/docs_trixie
docs: update example versions of debian an ubuntu
2026-11-06 00:05:21 +01:00
Sebastiaan van Stijn dfe5bf3073 Merge pull request #7489 from thaJeztah/bump_go127
update to go1.27.3
2026-11-05 23:59:05 +01:00
Sebastiaan van Stijn 85af295d30 update to go1.27.3
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-05 23:47:28 +01:00
Sebastiaan van Stijn de692998a4 Merge pull request #7490 from thaJeztah/bump_x_sys
vendor: golang.org/x/sys f5cb0306ac0e (fix for go1.27)
2026-11-05 23:46:40 +01:00
Sebastiaan van Stijn 873db34f4b Merge pull request #7491 from thaJeztah/bump_golangci
update to golangci-lint 2.14 (for go1.27)
2026-11-05 23:46:11 +01:00
Sebastiaan van Stijn 66da404208 Merge pull request #7486 from thaJeztah/bump_trixie
update to debian trixie
2026-11-05 23:39:05 +01:00
Sebastiaan van Stijn a0f7df60ba update to debian trixie
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-05 23:29:15 +01:00
Sebastiaan van Stijn 8fa64e724a vendor: golang.org/x/sys f5cb0306ac0e (fix for go1.27)
includes a fix for https://go.dev/issue/82324

full diff: https://github.com/golang/sys/compare/v0.49.0...f5cb0306ac0e4b93b83ddd53c36d6693af3214e3

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-05 23:23:39 +01:00
Sebastiaan van Stijn e2aefc6e1a docs: update examples for ubuntu LTS versions
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-05 23:19:42 +01:00
Sebastiaan van Stijn 26a4786788 update to golangci-lint 2.14 (for go1.27)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-05 23:13:02 +01:00
Sebastiaan van Stijn 8f1203743d fix linting
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-05 23:12:57 +01:00
Mend Renovate 32a838bf17 chore(deps): update psampaz/go-mod-outdated docker tag to v0.9.0
Signed-off-by: Mend Renovate <bot@renovateapp.com>
2026-11-05 21:28:50 +00:00
Paweł Gronowski cbb0dabae0 Merge pull request #7485 from thaJeztah/bump_alpine
update to alpine 3.24
2026-11-05 22:27:33 +01:00
Paweł Gronowski d216e46795 Merge pull request #7487 from thaJeztah/update_runners
ci: replace retired macOS 14 runner with macOS 26
2026-11-05 22:27:15 +01:00
Sebastiaan van Stijn 1c6c7ffcc8 docs: update examples to use debian trixie
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-05 22:24:31 +01:00
Sebastiaan van Stijn 11626f30d0 ci: replace retired macOS 14 runner with macOS 26
GitHub Actions retired macOS 14 runners on November 2, 2026.
Replace macos-14 with macos-26 to continue testing on supported
macOS versions.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-05 22:12:03 +01:00
Sebastiaan van Stijn 7817ee1c5c update to alpine 3.24
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-05 22:02:33 +01:00
Sebastiaan van Stijn 6b88c47537 Merge pull request #7480 from thaJeztah/bump_ansiterm
vendor: github.com/Azure/go-ansiterm 51075c6ea6bc
2026-11-05 21:28:03 +01:00
Sebastiaan van Stijn 2b3688febb Merge pull request #7481 from dperny/fix-container-names-fallback
cli/command/formatter: restore fallback for container names with slashes
2026-11-05 20:13:15 +01:00
Sebastiaan van Stijn 28f460abf3 Merge pull request #7483 from renovate-bot/renovate/docker-compose-bin-5.x
chore(deps): update docker/compose-bin docker tag to v5.7.0
2026-11-05 19:48:39 +01:00
Mend Renovate 1f6f73a7be chore(deps): update docker/compose-bin docker tag to v5.7.0
Signed-off-by: Mend Renovate <bot@renovateapp.com>
2026-11-05 16:52:38 +00:00
Sebastiaan van Stijn f9ad558f5d Merge pull request #7482 from nicksieger/nicksieger/fix-help-run
fix: propagate leading --help to subcommands with a local help flag
2026-11-05 17:49:18 +01:00
Sebastiaan van Stijn dd422f424c Merge pull request #7433 from jsternberg/trace-and-metrics-shutdown
cli-plugins/plugin: add OnFinalize hook for shutting down otel providers
2026-11-05 17:48:40 +01:00
Nick Sieger 965590b378 fix: propagate leading --help to subcommands with a local help flag
- --help before a subcommand is parsed as the root's persistent flag and
  stripped from args, which works for most subcommands since they share
  the same flag object with root
- run/create register their own local help flag (no -h, to avoid a
  shorthand clash with --hostname), which shadows root's and never saw
  the value, so the container ran instead of printing usage
- propagate the parsed value into a subcommand's local help flag when
  one shadows the root's, in HandleGlobalFlags

Fixes #7473

Signed-off-by: Nick Sieger <nick@nicksieger.com>
2026-11-05 09:52:46 -06:00
Drew ErnyandClaude Opus 5.5 191aab9fe8 cli/command/formatter: restore fallback for container names with slashes
Since commit f7a909d56b, ContainerContext.Names returns an empty string
when truncating and every name of the container contains a slash. Before
that change, all names were printed in that case.

Classic Swarm prefixes container names with the node-name
("/<node-name>/<container-name>"), so `docker ps` against a classic Swarm
API printed an empty NAMES column.

Restore the fallback to printing all names when no name without slashes
is found.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Drew Erny <derny@mirantis.com>
2026-11-05 08:53:09 -06:00
Sebastiaan van Stijn 682373a887 vendor: github.com/Azure/go-ansiterm 51075c6ea6bc
full diff: https://github.com/Azure/go-ansiterm/compare/8c912ac31dd4...51075c6ea6bc

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-05 13:44:53 +01:00
Sebastiaan van Stijn 949b412ae3 Merge pull request #7478 from thaJeztah/codecov_oidc_step2
ci: use OIDC authentication for Codecov uploads (remaining workflows)
2026-11-05 11:27:55 +01:00
Sebastiaan van Stijn 57393ea18e ci: use OIDC authentication for Codecov uploads (remaining workflows)
follow-up to 18958e4c02, which updated
the e2e workflow, but forgot to update the other workflows.

Replace the CODECOV_TOKEN secret with GitHub Actions OIDC authentication.

Codecov supports tokenless uploads for public repositories, but
authenticated uploads are still needed to protect coverage results on
protected branches from unauthorized uploads.

Grant `id-token: write` at the job level to allow Codecov to request
a short-lived OIDC token. This permission does not grant repository
write access, and scoping it to the job avoids granting it to other
jobs added to the workflow in the future.

Coverage uploads from forked pull requests continue to use Codecov's
tokenless upload mechanism.

See https://github.com/codecov/codecov-action/blob/v7.1.1/README.md#using-oidc

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-05 10:54:27 +01:00
Sebastiaan van Stijn 84e55d46d7 Merge pull request #7477 from thaJeztah/codecov_oidc
ci: use OIDC authentication for Codecov uploads
2026-11-05 10:39:45 +01:00
Sebastiaan van Stijn 18958e4c02 ci: use OIDC authentication for Codecov uploads
Replace the CODECOV_TOKEN secret with GitHub Actions OIDC authentication.

Codecov supports tokenless uploads for public repositories, but
authenticated uploads are still needed to protect coverage results on
protected branches from unauthorized uploads.

Grant `id-token: write` at the job level to allow Codecov to request
a short-lived OIDC token. This permission does not grant repository
write access, and scoping it to the job avoids granting it to other
jobs added to the workflow in the future.

Coverage uploads from forked pull requests continue to use Codecov's
tokenless upload mechanism.

See https://github.com/codecov/codecov-action/blob/v7.1.1/README.md#using-oidc

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-05 10:22:53 +01:00
Sebastiaan van Stijn ab54f1f097 Merge pull request #7168 from hirehamir/fix/flaky-test-prune-prompt-termination
fix: flaky `TestPrunePromptTermination` test
2026-11-05 09:04:07 +01:00
Jonathan A. Sternberg d278c1ec68 cli-plugins/plugin: add OnFinalize hook for shutting down otel providers
OTEL providers provided by this library to plugins were not properly
shut down. Metrics from the CLI were forcibly flushed in a separate area
and the `buildx` command does its own flushing, but this didn't apply to
traces.

Add shutdown on post run for plugins using `OnFinalize`. This will allow
compose to use the tracer provider from this library rather than roll
its own custom one.

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2026-11-04 12:45:18 -06:00
Sebastiaan van Stijn fb2fe0eac7 Merge pull request #7468 from thaJeztah/bump_otels
vendor: go.opentelemetry.io/otel v1.47.0, contrib v0.72.0
2026-11-03 22:57:33 +01:00
Paweł Gronowski 920919bd15 Merge pull request #7469 from thaJeztah/bump_compress
vendor: github.com/klauspost/compress v1.20.2 (security)
2026-11-03 22:33:58 +01:00
Paweł Gronowski beafae2696 Merge pull request #7442 from thaJeztah/bump_creds_helpers
vendor: github.com/docker/docker-credential-helpers v0.9.12
2026-11-03 22:30:04 +01:00
Sebastiaan van Stijn b9456fd725 vendor: github.com/klauspost/compress v1.20.2
includes a fix for CVE-2026-116591 / [GHSA-fpmh-frq8-7rj8]

full diff: https://github.com/klauspost/compress/compare/v1.20.1...v1.20.2

[GHSA-fpmh-frq8-7rj8]: https://github.com/klauspost/compress/security/advisories/GHSA-fpmh-frq8-7rj8

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-03 22:27:00 +01:00
Sebastiaan van Stijn 7a75f75b96 vendor: go.opentelemetry.io/otel v1.47.0, contrib v0.72.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-03 22:23:13 +01:00
Paweł Gronowski 9762c1688f Merge pull request #7449 from thaJeztah/manifest_completion
manifest: annotate: add shell-completion for --os and --arch
2026-11-03 21:53:15 +01:00
Sebastiaan van Stijn b2f5d905c7 Merge pull request #7466 from thaJeztah/bump_swarmkit
vendor: github.com/moby/swarmkit/v2 v2.1.3
2026-11-03 21:20:00 +01:00
Sebastiaan van Stijn 77ebef3df8 vendor: github.com/moby/swarmkit/v2 v2.1.3
full diff: https://github.com/moby/swarmkit/compare/v2.1.2...v2.1.3

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-03 21:11:01 +01:00
Paweł Gronowski 6d15cedd97 Merge pull request #7465 from thaJeztah/bump_x_net
vendor: golang.org/x/net v0.62.0
2026-11-03 17:57:57 +01:00
Sebastiaan van Stijn 82b833e57a vendor: golang.org/x/net v0.62.0
full diff: https://github.com/golang/net/compare/v0.61.0...v0.62.0

This release addresss the following security issues:

- html: avoid quadratic complexity when coalescing text nodes

    When coalescing adjacent text nodes in addText and fosterParent,
    appending to an existing TextNode's Data via string concatenation
    (n.Data += text) reallocated and copied the accumulated string on every
    token. Inputs containing many short text runs separated by ignored end
    tags (such as "a") caused O(n^2) allocations and byte copies.

    Accumulate coalesced text in per-node byte slices during parsing and
    materialize Data strings once at the end of parse.

    Thanks to Markus Magnuson for reporting this issue.

    This is CVE-2026-78661 and Go issue https://go.dev/issue/82224.

- html: check all ancestor namespace transitions when rendering raw text

    In childTextNodesAreLiteral, walking up the tree previously stopped at
    the nearest foreign ancestor once an HTML integration point was found.
    However, that integration point may itself be a descendant of an element
    that was foster-parented into a foreign namespace (such as or
    fostered under ), causing a parser to resolve the
    subtree in a different foreign namespace upon re-parsing the rendered
    output.

    Continue walking the full ancestor chain and verify that every
    transition from a non-empty namespace occurs at an HTML integration
    point before emitting literal text.

    Thanks to Ali Sherif (https://www.linkedin.com/in/ali-sherif-13812b276) for reporting this issue.

    This is CVE-2026-97045 and Go issue https://go.dev/issue/82622.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-03 14:55:15 +01:00
Paweł Gronowski 997674f459 Merge pull request #7462 from thaJeztah/bump_jose2
vendor: github.com/go-jose/go-jose/v4 v4.1.7 (security)
2026-11-03 14:41:36 +01:00
Sebastiaan van Stijn 81e4a109a3 vendor: github.com/go-jose/go-jose/v4 v4.1.7
Fixed Security Issues

- Thumbprint: reject invalid RSA key [GHSA-r39w-98wm-9pp6]
- json: backport stdlib fix for embedded unexported field [GHSA-27pc-rm86-68pq]
- Detect if headers are set by presence in the map [GHSA-p9j4-2j95-j4rv]
- limit RSA size in certificate verify [GHSA-v6h2-qj3f-2h6v]
- Limit recipients and signatures in JWE/JWS [GHSA-c67m-wr4h-2ccg]

Fixed

- jwk: fix bug in x5c parsing
- reject base64-encoded "null" in protected headers

Deprecated

- deprecate ParseEncrypted / ParseSigned

full diff: https://github.com/go-jose/go-jose/compare/v4.1.6...v4.1.7

[GHSA-r39w-98wm-9pp6]: https://github.com/go-jose/go-jose/security/advisories/GHSA-r39w-98wm-9pp6
[GHSA-27pc-rm86-68pq]: https://github.com/go-jose/go-jose/security/advisories/GHSA-27pc-rm86-68pq
[GHSA-p9j4-2j95-j4rv]: https://github.com/go-jose/go-jose/security/advisories/GHSA-p9j4-2j95-j4rv
[GHSA-v6h2-qj3f-2h6v]: https://github.com/go-jose/go-jose/security/advisories/GHSA-v6h2-qj3f-2h6v
[GHSA-c67m-wr4h-2ccg]: https://github.com/go-jose/go-jose/security/advisories/GHSA-c67m-wr4h-2ccg

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-03 14:24:18 +01:00
Paweł Gronowski e7ece565b2 Merge pull request #7460 from thaJeztah/bump_yaml
vendor: go.yaml.in/yaml/v3 v3.0.6 (security)
2026-11-03 14:20:18 +01:00
Paweł Gronowski 4214721b3b Merge pull request #7443 from thaJeztah/bump_jose
vendor: github.com/go-jose/go-jose/v4 v4.1.6 (security)
2026-11-03 14:20:05 +01:00
Sebastiaan van Stijn 281291299e Merge pull request #7459 from renovate-bot/renovate/docker-compose-bin-5.x
chore(deps): update docker/compose-bin docker tag to v5.6.1
2026-11-03 12:01:01 +01:00
Sebastiaan van Stijn 796f9633b4 vendor: go.yaml.in/yaml/v3 v3.0.6
resolve: hint-class literal merge-key string "<<" so it's quoted on encode

full diff: https://github.com/yaml/go-yaml/compare/v3.0.5...v3.0.6

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-03 11:54:24 +01:00
Mend Renovate 29b22240bc chore(deps): update docker/compose-bin docker tag to v5.6.1
Signed-off-by: Mend Renovate <bot@renovateapp.com>
2026-11-03 10:45:47 +00:00
Sebastiaan van Stijn 19a353f2ea Merge pull request #7452 from renovate-bot/renovate/docker-buildx-bin-0.x
chore(deps): update docker/buildx-bin docker tag to v0.38.1
2026-11-03 11:44:17 +01:00
Mend Renovate 3bc38f9c19 chore(deps): update docker/buildx-bin docker tag to v0.38.1
Signed-off-by: Mend Renovate <bot@renovateapp.com>
2026-11-02 14:10:44 +00:00
Sebastiaan van Stijn 0ccbdf86a0 Merge pull request #7430 from docker/dependabot/github_actions/codeql-actions-da882c3ad8
build(deps): bump the codeql-actions group across 1 directory with 3 updates
2026-11-02 15:09:43 +01:00
Sebastiaan van Stijn fbafb4965c Merge pull request #7441 from docker/dependabot/github_actions/docker-actions-1541f28a00
build(deps): bump the docker-actions group across 1 directory with 2 updates
2026-11-02 15:08:48 +01:00
dependabot[bot] 276829e744 build(deps): bump the codeql-actions group across 1 directory with 3 updates
Bumps the codeql-actions group with 3 updates in the / directory: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.38.3 to 4.39.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/24c54180a607b1449ed407dd24f251e4e9147c8d...9b3254085494b55a0f7c4c2b3d2d52cc712ce370)

Updates `github/codeql-action/autobuild` from 4.38.3 to 4.39.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/24c54180a607b1449ed407dd24f251e4e9147c8d...9b3254085494b55a0f7c4c2b3d2d52cc712ce370)

Updates `github/codeql-action/analyze` from 4.38.3 to 4.39.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/24c54180a607b1449ed407dd24f251e4e9147c8d...9b3254085494b55a0f7c4c2b3d2d52cc712ce370)

---
updated-dependencies:
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.39.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: codeql-actions
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.39.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: codeql-actions
- dependency-name: github/codeql-action/init
  dependency-version: 4.39.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: codeql-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-11-02 08:46:14 +00:00
dependabot[bot] cc8c87844d build(deps): bump the docker-actions group across 1 directory with 2 updates
Bumps the docker-actions group with 2 updates in the / directory: [docker/github-builder/.github/workflows/bake.yml](https://github.com/docker/github-builder) and [docker/docker-agent-action/.github/workflows/review-pr.yml](https://github.com/docker/docker-agent-action).


Updates `docker/github-builder/.github/workflows/bake.yml` from 1.18.0 to 1.18.1
- [Release notes](https://github.com/docker/github-builder/releases)
- [Commits](https://github.com/docker/github-builder/compare/4345a1cea1e4cfb65c8a5e2b1b80f9e630068827...cbc9d42f8c89a55623392aadd03600965b80e963)

Updates `docker/docker-agent-action/.github/workflows/review-pr.yml` from 2.0.9 to 2.1.0
- [Release notes](https://github.com/docker/docker-agent-action/releases)
- [Commits](https://github.com/docker/docker-agent-action/compare/3654ec391b070e247de2e2e3c1ff2519b6378b3a...aaa657c53cc69ed15683cd8a985d86663a0e1594)

---
updated-dependencies:
- dependency-name: docker/docker-agent-action/.github/workflows/review-pr.yml
  dependency-version: 2.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: docker-actions
- dependency-name: docker/github-builder/.github/workflows/bake.yml
  dependency-version: 1.18.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: docker-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-11-02 08:43:09 +00:00
Sebastiaan van Stijn e512522843 manifest: annotate: add shell-completion for --os and --arch
With this patch;

    docker manifest annotate --os <TAB>
    aix        darwin     freebsd    illumos    js         nacl       openbsd    solaris    zos
    android    dragonfly  hurd       ios        linux      netbsd     plan9      windows

    docker manifest annotate --arch <TAB>
    386          arm          armbe        mips64       mips64p32le  ppc64        riscv64      sparc
    amd64        arm64        loong64      mips64le     mipsle       ppc64le      s390         sparc64
    amd64p32     arm64be      mips         mips64p32    ppc          riscv        s390x        wasm

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-30 15:03:10 +01:00
Sebastiaan van Stijn 8c8a77521a Merge pull request #7448 from thaJeztah/carry_7447
manifest: add loong64 to manifest annotate, and remove hard-coded os/arch list in validation
2026-10-30 14:59:17 +01:00
Sebastiaan van Stijn bf8066ca18 manifest: remove hard-coded os/arch list in validation
Replace the hardcoded list of supported OS/architecture combinations with
syntax validation using containerd/platforms.

This allows annotating manifests with platforms that are not explicitly
known to the CLI, while still rejecting missing or malformed values.

The validation uses a FormatAll/Parse roundtrip until containerd/platforms
provides a dedicated validation function.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-30 13:12:26 +01:00
吴小白 d35139c89f manifest: add loong64 to manifest annotate bash completion
Signed-off-by: 吴小白 <296015668@qq.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-30 11:25:59 +01:00
Sebastiaan van Stijn b32aa42608 Merge pull request #7445 from thaJeztah/geen_kabouters
scripts/build: omit DWARF debug information by default
2026-10-29 21:33:03 +01:00
Sebastiaan van Stijn 8ff6f243a2 scripts/build: omit DWARF debug information by default
Pass -w to the Go linker to reduce binary size while retaining the
symbol table for tools that inspect Go binaries.

For a linux/arm64 build, this reduces the CLI binary from 39,809,791
to 31,310,197 bytes: a saving of 8.5 MB (21.4%).

Place the default before caller-supplied GO_LDFLAGS so builds can
retain DWARF by passing GO_LDFLAGS="-w=0".

Before

    ls -l /go/src/github.com/docker/cli/build/docker-linux-arm64
    -rwxr-xr-x 1 root root 39809791 Oct 29 17:34 /go/src/github.com/docker/cli/build/docker-linux-arm64

After

    ls -l /go/src/github.com/docker/cli/build/docker-linux-arm64
    -rwxr-xr-x 1 root root 31310197 Oct 29 17:36 /go/src/github.com/docker/cli/build/docker-linux-arm64

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-29 19:06:26 +01:00
Sebastiaan van Stijn b9312b9d88 scripts/build: suppress shellcheck linting
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-29 18:29:37 +01:00
Sebastiaan van Stijn ccccec73b0 vendor: github.com/go-jose/go-jose/v4 v4.1.6
- contains a fix for CVE-2026-116587 / [GHSA-mgcc-cww5-fp2q]

full diff: https://github.com/go-jose/go-jose/compare/v4.1.5...v4.1.6

[GHSA-mgcc-cww5-fp2q]: https://github.com/go-jose/go-jose/security/advisories/GHSA-mgcc-cww5-fp2q

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-28 22:38:48 +01:00
Sebastiaan van Stijn dd8edb6863 vendor: github.com/docker/docker-credential-helpers v0.9.12
no changes in vendored code

full diff: https://github.com/docker/docker-credential-helpers/compare/v0.9.9...v0.9.12

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-28 14:23:04 +01:00
Sebastiaan van Stijn 66786b775a Merge pull request #7421 from thaJeztah/bump_x_deps
vendor: update golang.org/x/* dependencies
2026-10-27 10:20:11 +01:00
Paweł Gronowski 47e9dbf7b0 Merge pull request #7427 from renovate-bot/renovate/docker-actions
Update docker GitHub Actions
2026-10-26 20:12:30 +01:00
Mend Renovate abf2f34c74 Update docker GitHub Actions
Signed-off-by: Mend Renovate <bot@renovateapp.com>
2026-10-26 12:59:35 +00:00
Hamir dd50814004 fix: flaky TestPrunePromptTermination test
TerminatePrompt created a pipe for the prompt's stdin but discarded the
write end. Once the garbage collector finalized it, the write end was
closed, the prompt read EOF and treated it as "no", and the command
returned "prune has been cancelled" instead of prompt.ErrTerminated.

This keeps both ends of the pipe referenced and closes them in t.Cleanup.

This change also drops the OutBuffer().Len() check:
the writer hook only fires after
the write has completed, so the check proved nothing, and it raced with
the prompt's later writes under -race.

This change also applies the same fix to the identical copy in cmd/docker-trust.

Signed-off-by: Hamir <hirehamir@gmail.com>
2026-10-22 10:04:59 -07:00
Sebastiaan van Stijn 6d274590f2 Merge pull request #7414 from thaJeztah/interactive_login_nits
internal/oauth: assorted fixes and cleanups
2026-10-20 14:40:35 +02:00
Sebastiaan van Stijn 6998c79cfd vendor: golang.org/x/net v0.61.0
- quic: properly check for allowed frame types in a packet

full diff: https://github.com/golang/net/compare/v0.60.0...v0.61.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-20 13:41:27 +02:00
Sebastiaan van Stijn c7bdacad70 vendor: golang.org/x/text v0.43.0
- secure/bidirule: lazily precompute ASCII table
- unicode/bidi: avoid quadratic behavior in Paragraph.Order and Paragraph.Line

full diff: https://github.com/golang/text/compare/v0.42.0...v0.43.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-20 13:40:24 +02:00
Sebastiaan van Stijn 1faf23e25f vendor: golang.org/x/term v0.47.0
full diff: https://github.com/golang/term/compare/v0.46.0...v0.47.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-20 13:39:46 +02:00
Sebastiaan van Stijn b8dd18fe2c vendor: golang.org/x/sync v0.24.0
full diff: https://github.com/golang/sync/compare/v0.23.0...v0.24.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-20 13:39:09 +02:00
Sebastiaan van Stijn a3539bd5c9 vendor: golang.org/x/mod v0.42.0
full diff: https://github.com/golang/mod/compare/v0.41.0...v0.42.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-20 13:38:32 +02:00
Sebastiaan van Stijn adfb114576 vendor: golang.org/x/sys v0.49.0
- cpu: add amd64 v2/v3/v4 feature bits
- darwin: expose setpriority PRIO_DARWIN_* constants
- unix/darwin: add missing pwritev test case on darwin/arm64
- unix/darwin: add O_EXEC and O_SEARCH on darwin
- unix/darwin: pass fcntl data as unsafe.Pointer in FcntlF{lock,store} on darwin
- unix/linux: don't warn about closed stderr from child process
- unix/linux: unify ppc64x syscall wrappers
- unix: add listns syscall introduced in Linux 6.19
- unix: add Mmsghdr for linux
- unix: add PrctlArg5Ptr
- unix: align the getdents buffer
- unix: extend z/OS support
- unix: keep generated types compilable with current cgo
- unix: pass xattr data as unsafe.Pointer in BSD xattr syscalls
- unix: provide linux/sparc64 assembly for syscalls
- unix: return syscall error in *listxattrNS on BSD
- unix: update glibc to 2.44
- unix: update linux to v7.2
- unix: use the stat64 family and fix Stat_t on linux/sparc64
- windows: drop arm

full diff: https://github.com/golang/sys/compare/v0.48.0...v0.49.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-20 13:37:40 +02:00
Sebastiaan van Stijn 4e09976ddd Merge pull request #7419 from thaJeztah/bump_sortorder
vendor: github.com/fvbommel/sortorder v1.2.1
2026-10-20 13:23:25 +02:00
Sebastiaan van Stijn 69c9ccd358 Merge pull request #7417 from vvoland/update-go
Update to go1.26.10
2026-10-20 13:11:47 +02:00
Sebastiaan van Stijn 1600418944 vendor: github.com/fvbommel/sortorder v1.2.1
full diff: https://github.com/fvbommel/sortorder/compare/v1.2.0...v1.2.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-20 12:46:38 +02:00
Paweł Gronowski 1fab379bcc Update to go1.26.10
This release includes 1 security fix following the security policy:

- crypto/x509: mitigation for security concerns with a specific Certificate Authority

  We're blocking trust in a small set of intermediate certificates due to specific security concerns around their operation.

  Verify will now filter out chains which contain these intermediates, preventing them from being returned to the caller.

  We highly recommend immediately upgrading to this release.

  This is CVE-2026-111943 and Go issue https://go.dev/issue/82345.

release notes: https://go.dev/doc/devel/release#go1.26.10

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-10-20 12:35:48 +02:00
Sebastiaan van Stijn df9a0f430f internal/oauth: remove debug logs, and move them to the caller
Wrap errors in the OAuth manager instead of logging them, preserving
the underlying cause while allowing callers to detect startup failures.

Log failures at the fallback handler and scope the device-code login
result to its branch.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-19 21:07:33 +02:00
Sebastiaan van Stijn fa65e9a3a0 internal/oauth: cleanup output
- Remove extra newline before message
- Include the token in the URL (instead of requiring the user to manually
  enter it on the website).
- Improve the "call to action"; ENTER can be used to automatically open
  the browser (but the user can manually open it instead), and CTRL-C can
  be used to cancel the login.
- Remove the "Waiting for authentication in the browser…" message, which
  could be confusing if no browser was opened (yet), instead print a message
  after successfully requesting the browser to be opened.

When running `docker login`;

    docker login

    i Info → 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: NRJL-BLRL
    Open this URL to authenticate: https://login.docker.com/activate?user_code=NRJL-BLRL

    Press ENTER to open the URL in your browser, or Ctrl+C to cancel.

After pressing `ENTER`, it either prints the "success" message;

    Press ENTER to open the URL in your browser, or Ctrl+C to cancel.

    Opening browser…

or a failure when unable to launch a browser;

    Press ENTER to open the URL in your browser, or Ctrl+C to cancel.

    No browser found. Open the URL above manually to continue.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-19 21:07:27 +02:00
Sebastiaan van Stijn dc66c2a8d0 internal/oauth: handle error when failing to open browser
Before this patch, pressing `ENTER` to open the browser would silently
discard the error;

    docker login

    i Info → 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: VGTB-VKBG
    Press ENTER to open your browser or submit your device code here: https://login.docker.com/activate

    Waiting for authentication in the browser…

With this patch, a failure is printed, so that the user can manually open
the URL (or cancel the login);

    docker login

    i Info → 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: SZFX-BSGP
    Press ENTER to open your browser or submit your device code here: https://login.docker.com/activate

    Waiting for authentication in the browser…

    No browser found. Open the URL above manually to continue.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-19 21:05:24 +02:00
Sebastiaan van Stijn ae317ab44a internal/oauth: combine "web-based login" message with info note
Make the output less verbose, and combine the "web-based login" message
with the info message that's already printed.

Before this patch:

    docker login

    USING WEB-BASED LOGIN

    i Info → To sign in with credentials on the command line, use 'docker login -u <username>'

    Your one-time device confirmation code is: VVPV-NSSL
    Press ENTER to open your browser or submit your device code here: https://login.docker.com/activate

    Waiting for authentication in the browser…

With this patch:

    docker login

    i Info → 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: QBBD-PQNS
    Press ENTER to open your browser or submit your device code here: https://login.docker.com/activate

    Waiting for authentication in the browser…

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-19 21:05:18 +02:00
Sebastiaan van Stijn 3f2ad8bf05 internal/oauth: avoid opening browser after login cancellation
Check the context after reading stdin to avoid launching the browser
if login was canceled while waiting for ENTER.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-19 20:49:29 +02:00
Paweł Gronowski 6f8369014a Merge pull request #7408 from GitNimay/3833-unknown-command-version-flag
cmd/docker: fail on unknown command with --version
2026-10-19 17:06:27 +02:00
Nimesh Kulkarni e08aa72569 cmd/docker: fail on unknown command with --version
Running "docker nonexistent --version" printed the CLI version and
exited 0, so it couldn't be used to check whether a command or plugin
is available. Without "--version" the same invocation fails with an
"unknown command" error.

When no built-in command or plugin matches, runDocker falls through to
executing the root command, and cobra handles the "--version" flag
before the root command reports the unknown command. Unset the root
command's version in that fallback, so the standard unknown-command
error is returned.

A global "--version" flag ("docker --version nonexistent") is parsed
before the command name and still prints the version, as do
"docker --version" and "docker nonexistent --help".

Signed-off-by: Nimesh Kulkarni <167794819+GitNimay@users.noreply.github.com>
2026-10-19 19:35:05 +05:30
Paweł Gronowski f522fffe52 Merge pull request #7412 from vvoland/trust-clean
cmd/docker-trust: Inline some cli dependencies
2026-10-19 14:32:57 +02:00
Paweł Gronowski 5e1e84ee5d cmd/docker-trust: Use standard regexps for name validation
The plugin only used lazyregexp for two small, fixed name patterns.
Replaced it with regexp.MustCompile without changing validation.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-10-19 13:28:28 +02:00
Paweł Gronowski 00bf2d970d cmd/docker-trust: Remove unused command registration
Both entry points use NewRootCmd, which adds subcommands directly.
Removed the unused registry registration and constructor.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-10-19 13:28:28 +02:00
Paweł Gronowski 4a93a41589 cmd/docker-trust: Inline the JSON stream display helper
The plugin only needed progress display and an auxiliary callback.
Inlined that use while preserving cancellation and terminal handling.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-10-19 13:28:28 +02:00
Sebastiaan van Stijn e300e529d5 Merge pull request #2012 from kolyshkin/build-man
man/docker-build: fix/expand --build-arg
2026-10-19 10:43:49 +02:00
Kir Kolyshkin 72f6e50c62 man/docker-build: fix/expand --build-arg
Explain that variable value is optional and is taken from environment
if not set.

Clarify the meaning of ARG, and mention that ENV overrides ARG of the
same name.

Move example to the end, and refer to the Dockerfile and buildx docs
for more details (replacing the obsolete link).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2026-10-19 01:15:00 -07:00
Sebastiaan van Stijn 52a2671034 Merge pull request #7396 from docker/dependabot/github_actions/codeql-actions-073aea62d7
build(deps): bump the codeql-actions group with 3 updates
2026-10-16 16:24:33 +02:00
Sebastiaan van Stijn 1d02640576 Merge pull request #7391 from vvoland/revert-go
Revert "chore(deps): update dependency go to v1.27.1"
2026-10-16 16:23:50 +02:00
Paweł Gronowski 4d74583397 Merge pull request #7398 from thaJeztah/bump_version
bump version to 29.10.0
2026-10-16 14:46:12 +02:00
Sebastiaan van Stijn de4ddc4fae bump version to 29.10.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-15 21:32:57 +02:00
dependabot[bot] ccac941dd9 build(deps): bump the codeql-actions group with 3 updates
Bumps the codeql-actions group with 3 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.38.2 to 4.38.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2...24c54180a607b1449ed407dd24f251e4e9147c8d)

Updates `github/codeql-action/autobuild` from 4.38.2 to 4.38.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2...24c54180a607b1449ed407dd24f251e4e9147c8d)

Updates `github/codeql-action/analyze` from 4.38.2 to 4.38.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2...24c54180a607b1449ed407dd24f251e4e9147c8d)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.38.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-actions
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.38.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-actions
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.38.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-15 08:45:04 +00:00
Paweł Gronowski e6beb40c03 Revert "chore(deps): update dependency go to v1.27.1"
This reverts commit a3a2bb6118.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-10-14 21:00:31 +02:00
Paweł Gronowski dfc520dcc2 Merge pull request #7390 from renovate-bot/renovate/go-1.x
chore(deps): update dependency go to v1.27.1
2026-10-14 20:09:52 +02:00
Mend Renovate a3a2bb6118 chore(deps): update dependency go to v1.27.1
Signed-off-by: Mend Renovate <bot@renovateapp.com>
2026-10-14 18:03:30 +00:00
Sebastiaan van Stijn c11295afc4 Merge pull request #7388 from renovate-bot/renovate/tonistiigi-xx-1.x
chore(deps): update tonistiigi/xx docker tag to v1.10.0
2026-10-14 18:11:18 +02:00
Sebastiaan van Stijn 010e125d8b Merge pull request #7386 from renovate-bot/renovate/docker-buildx-bin-0.x
chore(deps): update docker/buildx-bin docker tag to v0.38.0
2026-10-14 18:10:45 +02:00
Sebastiaan van Stijn 5cdf229230 Merge pull request #7387 from renovate-bot/renovate/docker-compose-bin-5.x
chore(deps): update docker/compose-bin docker tag to v5.6.0
2026-10-14 18:10:28 +02:00
Mend Renovate 66f6797582 chore(deps): update tonistiigi/xx docker tag to v1.10.0
Signed-off-by: Mend Renovate <bot@renovateapp.com>
2026-10-14 16:02:38 +00:00
Mend Renovate cb8870a537 chore(deps): update docker/compose-bin docker tag to v5.6.0
Signed-off-by: Mend Renovate <bot@renovateapp.com>
2026-10-14 16:02:33 +00:00
Mend Renovate 529f66d2f9 chore(deps): update docker/buildx-bin docker tag to v0.38.0
Signed-off-by: Mend Renovate <bot@renovateapp.com>
2026-10-14 16:02:28 +00:00
Paweł Gronowski 4d6ff7d646 Merge pull request #7380 from renovate-bot/renovate/actions-upload-artifact-7.x
chore(deps): update actions/upload-artifact action to v7.0.2
2026-10-14 16:53:33 +02:00
Paweł Gronowski b997c5b7aa Merge pull request #7381 from renovate-bot/renovate/docker-actions
chore(deps): update docker/setup-buildx-action action to v4.4.1
2026-10-14 16:49:47 +02:00
Mend Renovate 1822903c1d chore(deps): update docker/setup-buildx-action action to v4.4.1
Signed-off-by: Mend Renovate <bot@renovateapp.com>
2026-10-14 14:34:17 +00:00
Mend Renovate 37013cb262 chore(deps): update actions/upload-artifact action to v7.0.2
Signed-off-by: Mend Renovate <bot@renovateapp.com>
2026-10-14 14:34:11 +00:00
Paweł Gronowski 61ee187552 Merge pull request #7251 from vvoland/add-renovate
Add Renovate config
2026-10-14 16:32:20 +02:00
Paweł Gronowski 433b13a249 Add Renovate config
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-10-14 15:25:17 +02:00
Sebastiaan van Stijn 5c8bfb2844 Merge pull request #7378 from thaJeztah/pr_7371_alt
cli-plugins: Add generic hook messages (alternative)
2026-10-13 17:27:57 +02:00
Paweł Gronowski 528a2ada2e Merge pull request #7375 from thaJeztah/bump_go_winio
vendor: github.com/Microsoft/go-winio v0.6.3
2026-10-13 17:25:25 +02:00
Nicolas Beck de8f4032ad cli-plugins: Add generic hook messages
Allow plugins to return informational messages without the next-steps heading
or indentation. Invoke each hook once and render generic messages before the
shared next-steps block.

Centralize grouping and formatting in PrintMessages, with a callback for
template evaluation and error handling. This avoids the need for an
intermediate EvaluatedMessage type and simplifies hook collection to return
the original responses.

Skip messages containing only whitespace while preserving empty lines
within non-empty messages. Keep PrintNextSteps as a deprecated wrapper
to preserve existing callers and output.

Update the printer tests and remove the obsolete appendMessages helper
and its tests.

Co-authored-by: Nicolas Beck <nicolas.beck@docker.com>
Signed-off-by: Nicolas Beck <nicolas.beck@docker.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-12 16:31:43 +02:00
Sebastiaan van Stijn e4078058de Merge pull request #7373 from TanvirTian/7372-fix-remote-context-download-error
fix: return remote context download errors
2026-10-10 16:03:08 +02:00
Sebastiaan van Stijn 8da8b00555 vendor: github.com/Microsoft/go-winio v0.6.3
- improve interoperability with stdlib sentinel errors and deprecate aliases

full diff: https://github.com/Microsoft/go-winio/compare/f19d9717deb0...v0.6.3

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-10 15:28:26 +02:00
Tanvir Tian 067d069f0c fix: return remote context download errors
Signed-off-by: Tanvir Tian <beachpilis@gmail.com>
2026-10-10 18:16:02 +06:00
Sebastiaan van Stijn 02fbbf3eb0 Merge pull request #7369 from nico1510/offload-plugin-guidance
cmd/docker: Add guidance for unavailable offload commands
2026-10-09 18:08:27 +02:00
Sebastiaan van Stijn 890976a13b Merge pull request #7370 from thaJeztah/bump_version
Bump version to 29.9.1
2026-10-09 15:12:08 +02:00
Sebastiaan van Stijn 23c66ccd61 Bump version to 29.9.1
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-09 13:45:39 +02:00
Nicolas Beck 3e686a8b59 cmd/docker: Add guidance for unavailable offload commands
Show installation guidance and a documentation link when the offload
plugin is missing or invalid. Handle this before command execution so
plugin-specific flags and --help also receive the guidance.

Signed-off-by: Nicolas Beck <nicolas.beck@docker.com>
2026-10-09 10:06:48 +00:00
Sebastiaan van Stijn f415da838b Merge pull request #7367 from thaJeztah/bump_trust_deps
cmd/docker-trust: update dependencies
2026-10-08 22:29:49 +02:00
Paweł Gronowski 45c2317672 Merge pull request #7366 from thaJeztah/bump_runewidth
vendor: github.com/mattn/go-runewidth v0.0.31
2026-10-08 22:27:38 +02:00
Paweł Gronowski 8308969eda Merge pull request #7368 from vvoland/update-docker
vendor: github.com/moby/moby/client v0.6.2
2026-10-08 22:26:44 +02:00
Sebastiaan van Stijn cf809998ab cmd/docker-trust: update dependencies
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-08 22:23:38 +02:00
Paweł Gronowski 730c880b35 vendor: github.com/moby/moby/client v0.6.2
full diff: https://github.com/moby/moby/compare/client/v0.6.1...client/v0.6.2

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-10-08 22:08:10 +02:00
Sebastiaan van Stijn e63e4fe498 vendor: github.com/mattn/go-runewidth v0.0.31
- Treat the remaining invisible format controls as zero width
- Treat bidi isolates and other invisible format characters as zero width
- Measure ambiguous Latin letters as one cell in East Asian locales
- Fix width mismatches found by the Hegel property tests
- Recognise CJK locales regardless of charset spelling

full diff: https://github.com/mattn/go-runewidth/compare/v0.0.30...v0.0.31

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-08 21:51:14 +02:00
Paweł Gronowski e7df01fe6e Merge pull request #7361 from thaJeztah/bump_go_connections
vendor: github.com/docker/go-connections v0.8.2
2026-10-08 20:31:48 +02:00
Sebastiaan van Stijn 2e51107855 Merge pull request #7363 from vvoland/update-go
Update to go1.26.9
2026-10-08 20:31:01 +02:00
Paweł Gronowski 949bf401dd vendor: golang.org/x/net v0.60.0
full diff: https://golang.org/x/net/compare/v0.59.0...v0.60.0

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-10-08 20:25:01 +02:00
Paweł Gronowski 9db9802127 Update to go1.26.9
This release includes 15 security fixes following the security policy:

- net/http: HTTP/2 server crash due to HPACK encoder race

  HTTP/2 servers could end up crashing due to inadvertently
  modifying its HPACK encoder concurrently. This happens because the
  server modifies the HPACK encoder from two goroutines without
  synchronization: one uses the encoder to encode a HEADERS frame as part
  of a response sent to a client and the other modifies the encoder's
  table size when handling a SETTINGS frame containing
  SETTINGS_HEADER_TABLE_SIZE that a client sends. A malicious client can
  repeatedly send a request while changing the header table size to crash
  the server.

  Fix this issue by not applying SETTINGS_HEADER_TABLE_SIZE immediately.
  Instead, buffer any SETTINGS_HEADER_TABLE_SIZE received, and only apply
  the new value prior to the next time the server writes a frame.

  Thanks to RyotaK (https://ryotak.net) of GMO Flatt Security Inc. for reporting this issue.

  This is CVE-2026-97032 and Go issue https://go.dev/issue/81867.

- net/http: HTTP/2 server memory exhaustion due to Trailer headers

  When "Trailer" headers are sent by a client, the HTTP server internally
  uses the header values to populate the Request.Trailer map passed to the
  server handler. Because Request.Trailer is a map, each entry incurs
  memory overhead. For HTTP/2 servers, a malicious client can exploit this
  by sending a "Trailer" header that declares a large number of fields,
  causing the server to allocate a disproportionate amount of memory while
  bypassing Server.MaxHeaderValueCount and Server.MaxHeaderBytes limits.
  This exploit is not applicable for HTTP/1 servers, which do not support
  multiplexing a large number of requests over one TCP connection, and
  whose Server.MaxHeaderBytes are calculated differently.

  Server.MaxHeaderValueCount and Server.MaxHeaderBytes limits are now
  applied towards the trailer fields declared in "Trailer" headers.

  Thanks to RyotaK (https://ryotak.net) of GMO Flatt Security Inc. for reporting this issue.

  This is CVE-2026-78659 and Go issue https://go.dev/issue/81857.

- crypto/tls: reject malformed ECH outer extension references

  Multiple ECH outer extension references are not
  permitted under RFC 9849; previously, a client
  could send a well-crafted packet that could
  trigger memory exhaustion in the server process
  by specifying multiple references.

  We now reject these as malformed and curb the
  memory amplification vector as a result.

  This is CVE-2026-97031 and Go issue https://go.dev/issue/81855.

- cmd/go: checksum bypass for golang.org/fips140

  Previously, a user operating inside of a malicious
  Go project that defines a bogus golang.org/fips140
  and operates a malicious GOMODPROXY the user chooses
  to connect to can serve an arbitrary module in its
  place.

  We now unpack the trusted ziphash for the bundled
  golang.org/fips140 module and construct its entry
  in the GOMODCACHE such that it can be verified by
  the toolchain.

  This is CVE-2026-94444 and Go issue https://go.dev/issue/81833.

- cmd/go: checksum database bypass for golang.org/toolchain

  Previously, a user operating inside of a malicious
  Go project that defines a bogus golang.org/toolchain
  go.sum entry and operates a malicious GOMODPROXY the
  user chooses to use can bypass the intended checksum.

  We now ensure that golang.org/toolchain always goes
  to the network for the canonical checksum.

  This is CVE-2026-94447 and Go issue https://go.dev/issue/81834.

- html/template: reset context tracking on consecutive template expressions

  When a JavaScript template literal contains
  consecutive expressions, the context tracking
  state was not properly reset upon entering a
  new expression.

  We now ensure that template-literal expression
  entries correctly reset context variables so all
  subsequent regular expression literals are
  accurately recognized and escaped.

  This is CVE-2026-94448 and Go issue https://go.dev/issue/81821.

- html/template: recognize yield as regexp preceder keyword

  A trusted template author may have previously
  written a valid template wherein the use of
  the yield keyword would not be correctly
  escaped.

  We now ensure that valid keyword uses are
  escaped and non-keyword uses are not escaped.

  This is CVE-2026-97030 and Go issue https://go.dev/issue/81823.

- net/textproto, mime/multipart: memory limit bypass when parsing MIME headers

  Parsing a multipart form could bypass memory limits and read an
  arbitrarily long line into memory when the remaining limit at the
  start of a part was less than 400 bytes.

  Multipart form memory limits are now properly enforced in this situation.

  Thanks to Jakub Ciolek (https://ciolek.dev) for reporting this issue.

  This is CVE-2026-94440 and Go issue https://go.dev/issue/81741.

- net/http: HTTP/1 client connection desynchronization after CONNECT rejection

  When http.Transport sends an HTTP/1 CONNECT request with a non-empty
  Request.Body, it writes the body directly to the connection without
  framing after the request headers. If the server rejects the CONNECT
  request with a non-2xx keep-alive response, Transport returns the
  connection to the idle pool. Because CONNECT requests do not have a
  request body, the server may interpret the trailing body bytes as a
  subsequent pipelined HTTP/1.1 request on the connection, leaving the
  pooled connection desynchronized and causing the next caller that reuses
  it to read the response to the injected request. In reverse proxies
  (including httputil.ReverseProxy) that forward CONNECT requests through
  a shared Transport, this can lead to cross-user response poisoning.

  The HTTP/1 transport now closes a connection after sending a CONNECT
  request, regardless of the response status.

  In addition, ReverseProxy now rejects incoming CONNECT requests
  with a 405 Method Not Allowed response. ReverseProxy has never handled
  CONNECT requests in a useful fashion (it does not convert the
  connection into a bidirectional tunnel), so we do not expect this
  change to negatively affect any current users.

  Thanks to Xclow3n (Rajat Raghav) for reporting this issue.

  This is CVE-2026-56866 and Go issue https://go.dev/issue/81740.

- net/http: HTTP/1 server connection desynchronization after 2xx CONNECT response

  When an HTTP server handler sent a 2xx response to an HTTP/1 CONNECT request
  and returned without hijacking the connection, the server improperly continued
  to read and serve requests from the connection. Since a 2xx response to an
  HTTP/1 CONNECT converts the connection into a tunnel, the server should not
  treat the connection as continuing to contain HTTP.

  The impact of this misbehavior is mostly limited to potential request smuggling,
  where an intermediate proxy considers the data on the connection to be tunneled
  and the server considers it to be HTTP.

  The HTTP/1 server now always closes a connection after responding to a CONNECT
  request, regardless of the response status.

  Thanks to Jakub Ciolek (https://ciolek.dev) for reporting this issue.

  This is CVE-2026-94439 and Go issue https://go.dev/issue/81744.

- net/http: excessive CPU consumption from repeated initial window changes

  A malicious HTTP/2 peer could cause excessive CPU consumption in the
  client or server by opening a large number of streams and then sending
  many small SETTINGS frames containing SETTINGS_INITIAL_WINDOW_SIZE values.

  The HTTP/2 client and server now efficiently handle changes to the
  initial window size (O(1) rather than O(number of streams)).

  Thanks to Jakub Ciolek (https://ciolek.dev) for reporting this issue.

  This is CVE-2026-78669 and Go issue https://go.dev/issue/81742.

- net/http: HTTP/2 transport accepts malformed framing-related headers

  Historically, we have been rather lax about malformed framing-related
  headers in our HTTP/2 implementation, as they cannot interfere with
  HTTP/2 framing. However, this makes it possible for our HTTP/2
  implementation to forward responses containing such headers to an HTTP/1
  client when acting as a reverse proxy. If the HTTP/1 client also does
  not behave strictly enough, this can result in response smuggling.

  We now delete malformed framing-related headers when received by our
  HTTP/2 transport, so they will not be forwarded to a potentially
  vulnerable HTTP/1 client.

  Thanks to TJ Barton for reporting this issue.

  This is CVE-2026-78660 and Go issue https://go.dev/issue/81115.

- os: Root.Mkdir(All) can follow junctions out of the root on Windows

  On Windows, when the target of Root.Mkdir or Root.MkdirAll was a junction
  pointing to an empty location, the operation would create a directory at
  the junction target even when that target was located outside the root.
  This only applies to operations where the last path component is a
  junction (path/to/junction, but not path/junction/target).

  Root.Mkdir and Root.MkdirAll now correctly avoid resolving junctions.

  Thanks to Daniele Ballarini for reporting this issue.

  This is CVE-2026-56857 and Go issue https://go.dev/issue/81739.

- net/http: lack of limit on size of parsed Range headers

  When parsing a Range header containing a large number of small ranges,
  FileServer(FS), ServeContent, and ServeFile(FS) could consume an excessive
  amount of CPU.

  These functions now ignore Range headers containing more than 200 ranges.

  The limit is controlled by the new httpservecontentmaxranges=
  GODEBUG setting. Setting GODEBUG=httpservecontentmaxranges=0
  disables the limit.

  Thanks to Jakub Ciolek (https://ciolek.dev) for reporting this issue.

  This is CVE-2026-78667 and Go issue https://go.dev/issue/81858.

- net/http: double flow control refund on HTTP/2 server streams

  The HTTP/2 server could refund connection-level flow control twice for the same data:
  Once when a client resets a stream (refunding data for any sent-but-unread portion
  of the stream), and again when a request handler reads the buffered data.
  A malicious client could exploit this to bypass the configured connection-level
  flow control limit (MaxReceiveBufferPerConnection). Total buffered data is still
  limited by the concurrent stream limit and stream-level flow control.

  The HTTP/2 server now waits to refund connection-level flow control for reset
  streams until after the request handler is complete.

  Thanks to Ali Sherif (https://www.linkedin.com/in/ali-sherif-13812b276/) for reporting this issue.

  This is CVE-2026-78663 and Go issue https://go.dev/issue/81743.

release notes: https://go.dev/doc/devel/release#go1.26.9

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-10-08 20:19:46 +02:00
Sebastiaan van Stijn 63445d6b70 vendor: github.com/docker/go-connections v0.8.2
v0.8.2

- sockets: preserve configured TLS ALPN protocols
- ci: add dependabot to update actions
- ci: update runners to Ubuntu 26.04
- build(deps): bump actions/checkout from 6.0.2 to 7.0.1
- build(deps): bump actions/setup-go from 6.3.0 to 7.0.0
- build(deps): bump golangci/golangci-lint-action from 9.2.0 to 9.3.0

full diff: https://github.com/docker/go-connections/compare/v0.8.1...v0.8.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-08 16:03:13 +02:00
Paweł Gronowski fdb4ee3e75 Merge pull request #7360 from thaJeztah/bump_ansiterm
vendor: github.com/Azure/go-ansiterm 8c912ac31dd4
2026-10-08 14:40:57 +02:00
Sebastiaan van Stijn 4ae247756e vendor: github.com/Azure/go-ansiterm 8c912ac31dd4
- update minimum go version to go1.17
- update minimum golang.org/x/sys to v0.1.0

full diff: https://github.com/Azure/go-ansiterm/compare/e937bb47801a...8c912ac31dd4

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-10-07 23:56:10 +02:00
300 changed files with 10483 additions and 2821 deletions
+59
View File
@@ -0,0 +1,59 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
// https://docs.renovatebot.com/modules/manager/github-actions/
// https://docs.renovatebot.com/presets-helpers/
"helpers:pinGitHubActionDigestsToSemver",
":gitSignOff"
],
"gomod": {
"managerFilePatterns": ["/(^|/)vendor\\.mod$/"]
},
"postUpdateOptions": ["gomodTidy"],
"minimumReleaseAge": "3 days",
"internalChecksFilter": "strict",
"packageRules": [
{
"matchManagers": ["gomod"],
"matchFileNames": ["vendor.mod"],
"semanticCommits": "disabled",
"commitMessagePrefix": "vendor:"
},
{
"matchManagers": ["gomod"],
"matchFileNames": ["cmd/docker-trust/go.mod"],
// The trust module does not vendor dependencies; vendor/ belongs to the root module.
"postUpdateOptions": ["gomodSkipVendor"],
"semanticCommits": "disabled",
"commitMessagePrefix": "cmd/docker-trust:"
},
{
"matchManagers": ["gomod"],
"matchFileNames": ["vendor.mod"],
"groupName": "golang.org/x packages",
"groupSlug": "golang-x",
"matchDepNames": ["/^golang\\.org\\/x\\//"]
},
{
"matchManagers": ["github-actions"],
"minimumReleaseAge": "7 days",
"addLabels": ["area/ci", "status/2-code-review"]
},
{
"matchManagers": ["github-actions"],
"groupName": "docker GitHub Actions",
"groupSlug": "docker-actions",
"matchDepNames": ["/^docker\\//"]
},
{
// Keep all the google.golang.org/genproto modules at the same version.
"matchManagers": ["gomod"],
"matchFileNames": ["vendor.mod"],
"groupName": "google.golang.org/genproto packages",
"groupSlug": "google-genproto",
"matchDepNames": ["/^google\\.golang\\.org\\/genproto(\\/|$)/"],
"schedule": ["every month"]
}
]
}
+6 -6
View File
@@ -65,10 +65,10 @@ jobs:
steps:
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@594f3bf4285d9ea8dc53c9a0c9c4092420091003 # v4.4.0
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
-
name: Build
uses: docker/bake-action@018cb6412ab401ebaa809aa5f85966b74628600f # v7.4.0
uses: docker/bake-action@59cb1203cd42bcefd40a1b6d73b589e48c86040e # v7.5.0
with:
targets: ${{ matrix.target }}
set: |
@@ -91,7 +91,7 @@ jobs:
PLATFORM: ${{ matrix.platform }}
-
name: Upload artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: ${{ env.ARTIFACT_NAME }}
path: /tmp/out/*
@@ -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@58cb9f5b71b1836d6f690c1e95effdeb9b98cb8a # v1.17.0
uses: docker/github-builder/.github/workflows/bake.yml@cbc9d42f8c89a55623392aadd03600965b80e963 # v1.18.1
permissions:
contents: read # same as global permission
id-token: write # for signing attestation(s) and authenticating to Docker Hub with GitHub OIDC Token
@@ -156,10 +156,10 @@ jobs:
steps:
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@594f3bf4285d9ea8dc53c9a0c9c4092420091003 # v4.4.0
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
-
name: Build
uses: docker/bake-action@018cb6412ab401ebaa809aa5f85966b74628600f # v7.4.0
uses: docker/bake-action@59cb1203cd42bcefd40a1b6d73b589e48c86040e # v7.5.0
with:
targets: plugins-cross
set: |
+4 -4
View File
@@ -64,18 +64,18 @@ jobs:
name: Update Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: "1.26.8"
go-version: "1.27.3"
cache: false
-
name: Initialize CodeQL
uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
uses: github/codeql-action/init@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
with:
languages: go
-
name: Autobuild
uses: github/codeql-action/autobuild@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
uses: github/codeql-action/autobuild@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
-
name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
uses: github/codeql-action/analyze@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
with:
category: "/language:go"
+5 -2
View File
@@ -26,6 +26,9 @@ 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
@@ -66,7 +69,7 @@ jobs:
docker info
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@594f3bf4285d9ea8dc53c9a0c9c4092420091003 # v4.4.0
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
-
name: Run ${{ matrix.target }}
run: |
@@ -80,4 +83,4 @@ jobs:
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
with:
files: ./build/coverage/coverage.txt
token: ${{ secrets.CODECOV_TOKEN }}
use_oidc: true
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
fi
- name: Upload context
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: pr-review-context
path: context/
+1 -1
View File
@@ -11,7 +11,7 @@ permissions:
jobs:
review:
uses: docker/docker-agent-action/.github/workflows/review-pr.yml@3654ec391b070e247de2e2e3c1ff2519b6378b3a # v2.0.9
uses: docker/docker-agent-action/.github/workflows/review-pr.yml@aaa657c53cc69ed15683cd8a985d86663a0e1594 # v2.1.0
permissions:
contents: read # Read repository files and PR diffs
pull-requests: write # Post review comments
+13 -7
View File
@@ -26,14 +26,17 @@ 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:
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@594f3bf4285d9ea8dc53c9a0c9c4092420091003 # v4.4.0
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
-
name: Test
uses: docker/bake-action@018cb6412ab401ebaa809aa5f85966b74628600f # v7.4.0
uses: docker/bake-action@59cb1203cd42bcefd40a1b6d73b589e48c86040e # v7.5.0
with:
targets: test-coverage
-
@@ -41,9 +44,12 @@ jobs:
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
with:
files: ./build/coverage/coverage.txt
token: ${{ secrets.CODECOV_TOKEN }}
use_oidc: true
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 }}
@@ -53,9 +59,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:
-
@@ -68,7 +74,7 @@ jobs:
name: Set up Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: "1.26.8"
go-version: "1.27.3"
cache: false
-
name: Test
@@ -86,4 +92,4 @@ jobs:
with:
files: /tmp/coverage.txt
working-directory: ${{ env.GOPATH }}/src/github.com/docker/cli
token: ${{ secrets.CODECOV_TOKEN }}
use_oidc: true
+2 -2
View File
@@ -38,7 +38,7 @@ jobs:
steps:
-
name: Run
uses: docker/bake-action@018cb6412ab401ebaa809aa5f85966b74628600f # v7.4.0
uses: docker/bake-action@59cb1203cd42bcefd40a1b6d73b589e48c86040e # v7.5.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.26.8"
go-version: "1.27.3"
cache: false
-
name: Run gocompat check
+1 -11
View File
@@ -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.26.8"
go: "1.27.3"
timeout: 5m
@@ -201,11 +201,6 @@ 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:
@@ -227,11 +222,6 @@ 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
+9 -7
View File
@@ -5,14 +5,16 @@ 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.23
ARG BASE_DEBIAN_DISTRO=bookworm
ARG ALPINE_VERSION=3.24
ARG GO_VERSION=1.26.8
# BASE_DEBIAN_DISTRO sets the version of the debian base image to use,
ARG BASE_DEBIAN_DISTRO=trixie
ARG GO_VERSION=1.27.3
# 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.
ARG XX_VERSION=1.9.0
ARG XX_VERSION=1.10.0
# GOVERSIONINFO_VERSION is the version of GoVersionInfo to install.
# It must be a valid tag from https://github.com/josephspurrier/goversioninfo
@@ -25,12 +27,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.34.1
ARG BUILDX_VERSION=0.38.1
# 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.1.3
ARG COMPOSE_VERSION=v5.7.0
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
@@ -53,7 +55,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-12-dev pkgconf
RUN xx-apt-get install --no-install-recommends -y libc6-dev libgcc-14-dev pkgconf
FROM build-base-${BASE_VARIANT} AS goversioninfo
ARG GOVERSIONINFO_VERSION
+1 -1
View File
@@ -1 +1 @@
29.9.0
29.10.0
+4
View File
@@ -30,7 +30,11 @@ package hooks
type ResponseType int
const (
// NextSteps renders suggestions under a shared "What's next:" header.
NextSteps ResponseType = 0
// GenericMessage renders before NextSteps, without a header or indentation.
// CLI versions that do not recognize this type ignore the response.
GenericMessage ResponseType = 1
)
// Request is the type representing the information
+35 -10
View File
@@ -7,17 +7,42 @@ const (
indent = " "
)
// PrintNextSteps renders list of [NextSteps] messages and writes them
// to out. It is a no-op if messages is empty.
func PrintNextSteps(out io.Writer, messages []string) {
if len(messages) == 0 {
return
// PrintMessages groups messages by type and writes them to out. Generic messages
// appear first, without a header or indentation, followed by next steps under a
// shared "What's next:" header. Order within each type is preserved.
// Messages with no lines or an unknown type produce no output.
func PrintMessages(out io.Writer, messages []Response, evaluate func(Response) []string) {
grouped := make(map[ResponseType][]string)
for _, message := range messages {
lines := evaluate(message)
grouped[message.Type] = append(grouped[message.Type], lines...)
}
for _, responseType := range []ResponseType{GenericMessage, NextSteps} {
lines := grouped[responseType]
if len(lines) == 0 {
continue
}
_, _ = io.WriteString(out, whatsNext)
for _, msg := range messages {
_, _ = io.WriteString(out, indent)
_, _ = io.WriteString(out, msg)
_, _ = io.WriteString(out, "\n")
header, prefix := "\n", ""
if responseType == NextSteps {
header, prefix = whatsNext, indent
}
_, _ = io.WriteString(out, header)
for _, line := range lines {
_, _ = io.WriteString(out, prefix)
_, _ = io.WriteString(out, line)
_, _ = io.WriteString(out, "\n")
}
}
}
// PrintNextSteps renders list of [NextSteps] messages and writes them
// to out. It is a no-op if messages is empty.
//
// Deprecated: use [PrintMessages] instead.
func PrintNextSteps(out io.Writer, messages []string) {
PrintMessages(out, []Response{{Type: NextSteps}}, func(Response) []string {
return messages
})
}
+84 -1
View File
@@ -8,7 +8,85 @@ import (
"gotest.tools/v3/assert"
)
func TestPrintHookMessages(t *testing.T) {
func TestPrintMessages(t *testing.T) {
const header = "\n\x1b[1mWhat's next:\x1b[0m\n"
for _, tc := range []struct {
doc string
messages []hooks.Response
expected string
}{
{doc: "no messages"},
{
doc: "no lines",
messages: []hooks.Response{
{Type: hooks.GenericMessage},
{Type: hooks.NextSteps},
},
},
{
doc: "generic message",
messages: []hooks.Response{
{Type: hooks.GenericMessage, Template: "Session active"},
},
expected: "\nSession active\n",
},
{
doc: "preserve message formatting",
messages: []hooks.Response{
{Type: hooks.GenericMessage, Template: "Session active\n\n Details"},
},
expected: "\nSession active\n\n Details\n",
},
{
doc: "next steps",
messages: []hooks.Response{
{Type: hooks.NextSteps, Template: "Try another command"},
},
expected: header + " Try another command\n",
},
{
doc: "group interleaved types and preserve order within each type",
messages: []hooks.Response{
{Type: hooks.NextSteps, Template: "First suggestion"},
{Type: hooks.GenericMessage, Template: "Session active"},
{Type: hooks.NextSteps, Template: "Second suggestion\nThird suggestion"},
{Type: hooks.GenericMessage, Template: "Another status"},
},
expected: "\nSession active\nAnother status\n" + header + " First suggestion\n Second suggestion\n Third suggestion\n",
},
{
doc: "unknown type",
messages: []hooks.Response{
{Type: hooks.ResponseType(99), Template: "Ignored"},
},
},
{
doc: "unknown type does not affect known messages",
messages: []hooks.Response{
{Type: hooks.ResponseType(99), Template: "Ignored"},
{Type: hooks.GenericMessage, Template: "Session active"},
{Type: hooks.NextSteps, Template: "Try another command"},
},
expected: "\nSession active\n" + header + " Try another command\n",
},
} {
t.Run(tc.doc, func(t *testing.T) {
var w strings.Builder
hooks.PrintMessages(&w, tc.messages, func(message hooks.Response) []string {
if message.Template == "" {
return nil
}
lines, err := hooks.ParseTemplate(message.Template, nil)
assert.NilError(t, err)
return lines
})
assert.Equal(t, w.String(), tc.expected)
})
}
}
func TestPrintNextSteps(t *testing.T) {
const header = "\n\x1b[1mWhat's next:\x1b[0m\n"
tests := []struct {
@@ -34,6 +112,11 @@ func TestPrintHookMessages(t *testing.T) {
" Foo\n" +
" bar\n",
},
{
doc: "preserve empty and indented lines",
messages: []string{"", " Details", ""},
expectedOutput: header + " \n Details\n \n",
},
}
for _, tc := range tests {
t.Run(tc.doc, func(t *testing.T) {
+11 -1
View File
@@ -7,6 +7,7 @@ import (
"bytes"
"errors"
"fmt"
"slices"
"strings"
"text/template"
@@ -43,7 +44,16 @@ func ParseTemplate(hookTemplate string, cmd *cobra.Command) ([]string, error) {
if n := strings.Count(out, "\n"); n > maxMessages {
return nil, fmt.Errorf("hook template contains too many messages (%d): maximum is %d", n, maxMessages)
}
return strings.SplitN(out, "\n", maxMessages), nil
lines := strings.SplitN(out, "\n", maxMessages)
// Skip messages containing only whitespace, but preserve empty lines
// in messages that have content (e.g., for paragraph spacing).
if !slices.ContainsFunc(lines, func(line string) bool {
return strings.TrimSpace(line) != ""
}) {
return nil, nil
}
return lines, nil
}
var ErrHookTemplateParse = errors.New("failed to parse hook template")
+11 -1
View File
@@ -33,7 +33,17 @@ func TestParseTemplate(t *testing.T) {
{
doc: "empty template",
template: "",
expectedOutput: []string{""},
expectedOutput: nil,
},
{
doc: "only empty lines",
template: "\n\n",
expectedOutput: nil,
},
{
doc: "whitespace-only lines",
template: " \n\t\n ",
expectedOutput: nil,
},
{
doc: "plain message",
+23 -47
View File
@@ -49,11 +49,18 @@ func RunPluginHooks(ctx context.Context, dockerCLI config.Provider, rootCmd, sub
}
func runHooks(ctx context.Context, cfg *configfile.ConfigFile, rootCmd, subCommand *cobra.Command, invokedCommand string, flags map[string]string, cmdErrorMessage string) {
nextSteps := invokeAndCollectHooks(ctx, cfg, rootCmd, subCommand, invokedCommand, flags, cmdErrorMessage)
hooks.PrintNextSteps(subCommand.ErrOrStderr(), nextSteps)
messages := invokeAndCollectHooks(ctx, cfg, rootCmd, invokedCommand, flags, cmdErrorMessage)
hooks.PrintMessages(subCommand.ErrOrStderr(), messages, func(message hooks.Response) []string {
lines, err := hooks.ParseTemplate(message.Template, subCommand)
if err != nil {
logrus.WithError(err).Debug("Failed to evaluate hook template")
return nil
}
return lines
})
}
func invokeAndCollectHooks(ctx context.Context, cfg *configfile.ConfigFile, rootCmd, subCmd *cobra.Command, subCmdStr string, flags map[string]string, cmdErrorMessage string) []string {
func invokeAndCollectHooks(ctx context.Context, cfg *configfile.ConfigFile, rootCmd *cobra.Command, subCmdStr string, flags map[string]string, cmdErrorMessage string) []hooks.Response {
if ctx.Err() != nil {
return nil
}
@@ -64,17 +71,17 @@ func invokeAndCollectHooks(ctx context.Context, cfg *configfile.ConfigFile, root
}
pluginDirs := getPluginDirs(cfg)
nextSteps := make([]string, 0, len(pluginsCfg))
var collected []hooks.Response
tryInvokeHook := func(pluginName string, pluginCfg map[string]string) (messages []string, ok bool, err error) {
tryInvokeHook := func(pluginName string, pluginCfg map[string]string) (hooks.Response, error) {
match, matched := pluginMatch(pluginCfg, subCmdStr, cmdErrorMessage)
if !matched {
return nil, false, nil
return hooks.Response{}, nil
}
p, err := getPlugin(pluginName, pluginDirs, rootCmd)
if err != nil {
return nil, false, err
return hooks.Response{}, err
}
resp, err := p.RunHook(ctx, hooks.Request{
@@ -83,29 +90,23 @@ func invokeAndCollectHooks(ctx context.Context, cfg *configfile.ConfigFile, root
CommandError: cmdErrorMessage,
})
if err != nil {
return nil, false, err
return hooks.Response{}, err
}
var message hooks.Response
if err := json.Unmarshal(resp, &message); err != nil {
return nil, false, fmt.Errorf("failed to unmarshal hook response (%q): %w", string(resp), err)
return hooks.Response{}, fmt.Errorf("failed to unmarshal hook response (%q): %w", string(resp), err)
}
// currently the only hook type
if message.Type != hooks.NextSteps {
return nil, false, errors.New("unexpected hook response type: " + strconv.Itoa(int(message.Type)))
if message.Type != hooks.NextSteps && message.Type != hooks.GenericMessage {
return hooks.Response{}, errors.New("unexpected hook response type: " + strconv.Itoa(int(message.Type)))
}
messages, err = hooks.ParseTemplate(message.Template, subCmd)
if err != nil {
return nil, false, err
}
return messages, true, nil
return message, nil
}
for pluginName, pluginCfg := range pluginsCfg {
messages, ok, err := tryInvokeHook(pluginName, pluginCfg)
message, err := tryInvokeHook(pluginName, pluginCfg)
if err != nil {
// skip misbehaving plugins, but don't halt execution
logrus.WithFields(logrus.Fields{
@@ -114,38 +115,13 @@ func invokeAndCollectHooks(ctx context.Context, cfg *configfile.ConfigFile, root
}).Debug("Plugin hook invocation failed")
continue
}
if !ok {
if message.Template == "" {
continue
}
var appended bool
nextSteps, appended = appendNextSteps(nextSteps, messages)
if !appended {
logrus.WithFields(logrus.Fields{
"plugin": pluginName,
}).Debug("Plugin responded with an empty hook message; ignoring")
}
collected = append(collected, message)
}
return nextSteps
}
// appendNextSteps appends the processed hook output to the nextSteps slice.
// If the processed hook output is empty, it is not appended.
// Empty lines are not stripped if there's at least one non-empty line.
func appendNextSteps(nextSteps []string, processed []string) ([]string, bool) {
empty := true
for _, l := range processed {
if strings.TrimSpace(l) != "" {
empty = false
break
}
}
if empty {
return nextSteps, false
}
return append(nextSteps, processed...), true
return collected
}
// pluginMatch takes a plugin configuration and a string representing the
+108 -35
View File
@@ -2,6 +2,11 @@ package manager
import (
"context"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"github.com/docker/cli/cli/config/configfile"
@@ -258,38 +263,6 @@ func TestMatchHookConfig(t *testing.T) {
}
}
func TestAppendNextSteps(t *testing.T) {
testCases := []struct {
processed []string
expectedOut []string
}{
{
processed: []string{},
expectedOut: []string{},
},
{
processed: []string{"", ""},
expectedOut: []string{},
},
{
processed: []string{"Some hint", "", "Some other hint"},
expectedOut: []string{"Some hint", "", "Some other hint"},
},
{
processed: []string{"Hint 1", "Hint 2"},
expectedOut: []string{"Hint 1", "Hint 2"},
},
}
for _, tc := range testCases {
t.Run("", func(t *testing.T) {
got, appended := appendNextSteps([]string{}, tc.processed)
assert.Check(t, is.DeepEqual(got, tc.expectedOut))
assert.Check(t, is.Equal(appended, len(got) > 0))
})
}
}
func TestRunPluginHooksPassesErrorMessage(t *testing.T) {
cfg := configfile.New("")
cfg.Plugins = map[string]map[string]string{
@@ -336,7 +309,7 @@ func TestInvokeAndCollectHooksErrorHooksSkippedOnSuccess(t *testing.T) {
// On success, error-hooks should not match, so the plugin
// binary is never looked up and no results are returned.
result := invokeAndCollectHooks(
context.Background(), cfg, root, sub,
context.Background(), cfg, root,
"build", map[string]string{}, "",
)
assert.Check(t, is.Len(result, 0))
@@ -349,7 +322,7 @@ func TestInvokeAndCollectHooksNoPlugins(t *testing.T) {
root.AddCommand(sub)
result := invokeAndCollectHooks(
context.Background(), cfg, root, sub,
context.Background(), cfg, root,
"build", map[string]string{}, "some error",
)
assert.Check(t, is.Len(result, 0))
@@ -368,8 +341,108 @@ func TestInvokeAndCollectHooksCancelledContext(t *testing.T) {
cancel() // cancel immediately
result := invokeAndCollectHooks(
ctx, cfg, root, sub,
ctx, cfg, root,
"build", map[string]string{}, "exit status 1",
)
assert.Check(t, is.Nil(result))
}
func TestRunHooksMessages(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("test plugins require a POSIX shell")
}
const header = "\n\x1b[1mWhat's next:\x1b[0m\n"
for _, tc := range []struct {
doc string
responses map[string]string
expected string
}{
{
doc: "generic message preserves formatting and expands templates",
responses: map[string]string{
"status": `{"Type":1,"Template":"Status for {{command}}\n\n Details"}`,
},
expected: "\nStatus for build\n\n Details\n",
},
{
doc: "omitted type defaults to next steps",
responses: map[string]string{
"suggestion": `{"Template":"Try another command"}`,
},
expected: header + " Try another command\n",
},
{
doc: "generic messages precede shared next steps header",
responses: map[string]string{
"statusone": `{"Type":1,"Template":"Session active"}`,
"statustwo": `{"Type":1,"Template":"Session active"}`,
"suggestionone": `{"Type":0,"Template":"Try another command"}`,
"suggestiontwo": `{"Type":0,"Template":"Try another command"}`,
},
expected: "\nSession active\nSession active\n" + header + " Try another command\n Try another command\n",
},
{
doc: "empty responses produce no output",
responses: map[string]string{
"status": `{"Type":1,"Template":" \n\t"}`,
"suggestion": `{"Type":0,"Template":""}`,
},
},
{
doc: "empty generic message does not affect next steps",
responses: map[string]string{
"status": `{"Type":1,"Template":""}`,
"suggestion": `{"Type":0,"Template":"Try another command"}`,
},
expected: header + " Try another command\n",
},
{
doc: "invalid responses do not affect other plugins",
responses: map[string]string{
"unknown": `{"Type":99,"Template":"Ignored"}`,
"invalid": `{"Type":1,"Template":"{{"}`,
"status": `{"Type":1,"Template":"Session active"}`,
"suggestion": `{"Type":0,"Template":"Try another command"}`,
},
expected: "\nSession active\n" + header + " Try another command\n",
},
} {
t.Run(tc.doc, func(t *testing.T) {
pluginDir := t.TempDir()
cfg := configfile.New("")
cfg.CLIPluginsExtraDirs = []string{pluginDir}
cfg.Plugins = make(map[string]map[string]string)
for name, response := range tc.responses {
plugin := fmt.Sprintf(`#!/bin/sh
case "$1" in
docker-cli-plugin-metadata)
printf '%%s\n' '{"SchemaVersion":"0.1.0","Vendor":"test"}'
;;
*)
test "$2" = docker-cli-plugin-hooks || exit 1
printf 'called\n' >> "$0.calls"
printf '%%s\n' '%s'
;;
esac
`, response)
assert.NilError(t, os.WriteFile(filepath.Join(pluginDir, "docker-"+name), []byte(plugin), 0o755))
cfg.Plugins[name] = map[string]string{"hooks": "build"}
}
root := &cobra.Command{Use: "docker"}
sub := &cobra.Command{Use: "build"}
root.AddCommand(sub)
var output strings.Builder
sub.SetErr(&output)
runHooks(context.Background(), cfg, root, sub, "build", nil, "")
assert.Equal(t, output.String(), tc.expected)
for name := range tc.responses {
calls, err := os.ReadFile(filepath.Join(pluginDir, "docker-"+name+".calls"))
assert.NilError(t, err)
assert.Equal(t, string(calls), "called\n", "each plugin hook must run exactly once")
}
})
}
}
+62 -2
View File
@@ -10,6 +10,7 @@ import (
"fmt"
"os"
"sync"
"time"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli-plugins/metadata"
@@ -32,6 +33,11 @@ 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)
@@ -69,6 +75,7 @@ func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta metadat
stopInstrumentation(err)
return err
}
cobra.OnFinalize(func() { finalizeHook(dockerCli) })
})
return retErr
}
@@ -83,6 +90,59 @@ 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
@@ -212,8 +272,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)
+19 -1
View File
@@ -160,7 +160,25 @@ func (tcmd *TopLevelCommand) HandleGlobalFlags() (*cobra.Command, []string, erro
return nil, nil, cmd.FlagErrorFunc()(cmd, err)
}
return cmd, flags.Args(), nil
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
}
// Initialize finalises global option parsing and initializes the docker client.
+42
View File
@@ -108,3 +108,45 @@ 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)
})
}
+15 -12
View File
@@ -146,24 +146,27 @@ 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 {
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 {
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
}
continue
}
// 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 {
if i > 0 {
b.WriteByte(',')
}
b.WriteString(name)
b.WriteString(strings.TrimPrefix(n, "/"))
}
return b.String()
}
+20
View File
@@ -48,6 +48,25 @@ 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,
@@ -257,6 +276,7 @@ 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()
+5 -2
View File
@@ -260,8 +260,11 @@ func runBuild(ctx context.Context, dockerCli command.Cli, options buildOptions)
contextDir = tempDir
case build.ContextTypeRemote:
buildCtx, relDockerfile, err = build.GetContextFromURL(progBuff, options.context, options.dockerfileName)
if err != nil && options.quiet {
_, _ = fmt.Fprintln(dockerCli.Err(), progBuff)
if err != nil {
if options.quiet {
_, _ = fmt.Fprintln(dockerCli.Err(), progBuff)
}
return err
}
default:
return fmt.Errorf("unable to prepare context: path %q not found", options.context)
+31
View File
@@ -6,6 +6,8 @@ import (
"compress/gzip"
"context"
"io"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"slices"
@@ -172,6 +174,35 @@ RUN echo hello world
assert.DeepEqual(t, fakeBuild.filenames(t), []string{"Dockerfile"})
}
// TestRunBuildRemoteContextDownloadError verifies that remote context
// download errors are propagated.
//
// regression test for https://github.com/docker/cli/issues/7372
func TestRunBuildRemoteContextDownloadError(t *testing.T) {
t.Setenv("DOCKER_BUILDKIT", "0")
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "not found", http.StatusNotFound)
}))
defer server.Close()
imageBuildCalled := false
cli := test.NewFakeCli(&fakeClient{
imageBuildFunc: func(ctx context.Context, buildContext io.Reader, options client.ImageBuildOptions) (client.ImageBuildResult, error) {
imageBuildCalled = true
return client.ImageBuildResult{Body: io.NopCloser(bytes.NewReader(nil))}, nil
},
})
options := newBuildOptions()
options.context = server.URL
err := runBuild(context.Background(), cli, options)
assert.ErrorContains(t, err, "unable to download remote context")
assert.Assert(t, !imageBuildCalled, "ImageBuild should not be called when downloading the remote context fails")
}
type fakeBuild struct {
context *tar.Reader
options client.ImageBuildOptions
+30 -2
View File
@@ -10,8 +10,10 @@ 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"
@@ -20,6 +22,23 @@ 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
@@ -97,6 +116,8 @@ 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
}
@@ -139,8 +160,15 @@ func runManifestAnnotate(dockerCLI command.Cli, opts annotateOptions) error {
imageManifest.Descriptor.Platform.OSVersion = opts.osVersion
}
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)
// 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)
}
return manifestStore.Save(targetRef, imgRef, imageManifest)
}
+8 -7
View File
@@ -58,15 +58,16 @@ func TestManifestAnnotate(t *testing.T) {
assert.ErrorContains(t, cmd.Execute(), expectedError)
cmd.SetArgs([]string{"example.com/list:v1", "example.com/alpine:3.0"})
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.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"
assert.ErrorContains(t, cmd.Execute(), expectedError)
cmd.Flags().Set("arch", "arm")
assert.NilError(t, cmd.Flags().Set("arch", "arm"))
assert.NilError(t, cmd.Execute())
cmd = newInspectCommand(cli)
-47
View File
@@ -9,53 +9,6 @@ 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 {
+6 -6
View File
@@ -19,6 +19,7 @@ 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"
)
@@ -226,7 +227,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) (msg string, _ error) {
func loginUser(ctx context.Context, dockerCLI command.Cli, opts loginOptions, defaultUsername, serverAddress string) (message string, _ error) {
// Some links documenting this:
// - https://code.google.com/archive/p/mintty/issues/56
// - https://github.com/docker/docker/issues/15272
@@ -240,13 +241,12 @@ 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 == "" {
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) {
msg, err := loginWithDeviceCodeFlow(ctx, dockerCLI)
if err == nil || !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")
}
+2 -2
View File
@@ -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) {
+2 -2
View File
@@ -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)
+1 -1
View File
@@ -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 {
+1 -1
View File
@@ -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)
-4
View File
@@ -255,7 +255,6 @@ 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())
@@ -263,7 +262,6 @@ 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)
@@ -271,7 +269,6 @@ 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"))
@@ -285,7 +282,6 @@ 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())
+10 -10
View File
@@ -5,13 +5,13 @@ go 1.26.0
require (
github.com/containerd/errdefs v1.0.0
github.com/distribution/reference v0.6.0
github.com/docker/cli v29.7.2+incompatible
github.com/docker/cli v29.8.2+incompatible
github.com/docker/cli-docs-tool v0.11.0
github.com/docker/distribution v2.8.3+incompatible
github.com/docker/go-connections v0.8.1
github.com/docker/go-connections v0.8.2
github.com/fvbommel/sortorder v1.2.0
github.com/moby/moby/api v1.55.0
github.com/moby/moby/client v0.5.1
github.com/moby/moby/api v1.56.1
github.com/moby/moby/client v0.6.2
github.com/opencontainers/go-digest v1.0.0
github.com/sirupsen/logrus v1.10.2
github.com/spf13/cobra v1.10.2
@@ -22,7 +22,7 @@ require (
)
require (
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/Azure/go-ansiterm v0.0.0-20261006220739-8c912ac31dd4 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
@@ -66,11 +66,11 @@ require (
go.opentelemetry.io/otel/sdk/metric v1.46.0 // indirect
go.opentelemetry.io/otel/trace v1.46.0 // indirect
go.opentelemetry.io/proto/otlp v1.11.0 // indirect
golang.org/x/crypto v0.56.0 // indirect
golang.org/x/net v0.58.0 // indirect
golang.org/x/sys v0.47.0 // indirect
golang.org/x/term v0.45.0 // indirect
golang.org/x/text v0.41.0 // indirect
golang.org/x/crypto v0.57.0 // indirect
golang.org/x/net v0.60.0 // indirect
golang.org/x/sys v0.48.0 // indirect
golang.org/x/term v0.46.0 // indirect
golang.org/x/text v0.42.0 // 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
+20 -21
View File
@@ -1,5 +1,5 @@
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
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/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
@@ -42,8 +42,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v29.7.2+incompatible h1:dlkwallR8XqfeVnA2ELEhdwvb4lsSwuB4IgsG8Q9cLY=
github.com/docker/cli v29.7.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli v29.8.2+incompatible h1:2zgdFuoFst2T80oS42vhKGxkd0JRo305eIEKTsxR7pQ=
github.com/docker/cli v29.8.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli-docs-tool v0.11.0 h1:7d8QARFb7QEobizqxmEM7fOteZEHwH/zWgHQtHZEcfE=
github.com/docker/cli-docs-tool v0.11.0/go.mod h1:ma8BKiisUo8D6W05XEYIh3oa1UbgrZhi1nowyKFJa8Q=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
@@ -54,8 +54,8 @@ github.com/docker/docker-credential-helpers v0.9.9/go.mod h1:v1S+hepowrQXITkEfw6
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-connections v0.8.1 h1:JibmG5hULs5qXSr/cp/w3Pw5fZuStt4MOHMUExb29/M=
github.com/docker/go-connections v0.8.1/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q=
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-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
github.com/docker/go-metrics v0.1.0 h1:r76KPNpstz+IvQKSWpYegSkkyzex0V3A1ZGVx6bhGlY=
github.com/docker/go-metrics v0.1.0/go.mod h1:PciI3sONtB051kXALN1JoIlpcu54E1FuPh+4DuqEzyw=
@@ -133,10 +133,10 @@ github.com/mitchellh/mapstructure v1.0.0 h1:vVpGvMXJPqSDh2VYHF7gsfQj8Ncx+Xw5Y1KH
github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/moby/api v1.55.0 h1:2/sexvQyqIWS8pRSCFddBfpW2qE7vR7FCL+vN8pxwMc=
github.com/moby/moby/api v1.55.0/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs=
github.com/moby/moby/client v0.5.1 h1:tYNaJno4c0HXz12y5BiqEDy0rVTYkWzI26lGvnTMiJw=
github.com/moby/moby/client v0.5.1/go.mod h1:odLstlZ6uSnfvAgVxMpvgmb8SUdd+siH2T0GBuxVAlM=
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/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/sequential v0.7.0 h1:ASQNGNROJSuOO6LL6bPHbKvuZu6NU8P4ldPWk31zj/8=
@@ -236,27 +236,26 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.56.0 h1:GUh5Ii4J5jtcseSMiRqr1jXCNHoxjeV9Fmekc2oLy6Y=
golang.org/x/crypto v0.56.0/go.mod h1:OMW5y6CY9l38uPLmxU6l6pwcXp1obtLo3e6gT7gQR2I=
golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M=
golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To=
golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU=
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-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
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.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
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.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
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/xerrors v0.0.0-20190717185122-a985d3407aa7/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=
+6 -3
View File
@@ -27,8 +27,13 @@ func TerminatePrompt(ctx context.Context, t *testing.T, cmd *cobra.Command, cli
}))
cli.SetOut(outStream)
r, _, err := os.Pipe()
r, w, err := os.Pipe()
assert.NilError(t, err)
t.Cleanup(func() {
_ = w.Close()
_ = r.Close()
})
cli.SetIn(streams.NewIn(r))
notifyCtx, notifyCancel := context.WithCancel(ctx)
@@ -58,8 +63,6 @@ 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)
+36 -4
View File
@@ -11,8 +11,9 @@ import (
"github.com/distribution/reference"
"github.com/docker/cli/cli/streams"
"github.com/docker/cli/internal/jsonstream"
"github.com/moby/moby/api/types/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"
@@ -46,7 +47,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.JSONMessage) {
handleTarget := func(msg jsonstream.Message) {
cnt++
if cnt > 1 {
// handleTarget should only be called once. This will be treated as an error.
@@ -78,14 +79,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 := jsonstream.Display(ctx, in, ioStreams.Out()); err != nil {
if err := displayJSONMessages(ctx, in, ioStreams.Out(), nil); err != nil {
return err
}
_, _ = fmt.Fprintln(ioStreams.Err(), "No tag specified, skipping trust metadata push")
return nil
}
if err := jsonstream.Display(ctx, in, ioStreams.Out(), jsonstream.WithAuxCallback(handleTarget)); err != nil {
if err := displayJSONMessages(ctx, in, ioStreams.Out(), handleTarget); err != nil {
return err
}
@@ -147,3 +148,34 @@ 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()
}
-32
View File
@@ -1,32 +0,0 @@
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
}
+2 -2
View File
@@ -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 = lazyregexp.New(`^[a-z0-9][a-z0-9\_\-]*$`).MatchString
var validKeyName = regexp.MustCompile(`^[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
+2 -2
View File
@@ -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 = lazyregexp.New(`^[a-z0-9][a-z0-9\_\-]*$`).MatchString
var validSignerName = regexp.MustCompile(`^[a-z0-9][a-z0-9\_\-]*$`).MatchString
func addSigner(ctx context.Context, dockerCLI command.Cli, options signerAddOptions) error {
signerName := options.signer
+16 -3
View File
@@ -571,11 +571,24 @@ func runDocker(ctx context.Context, dockerCli *command.DockerCli) error {
return nil
}
if !errdefs.IsNotFound(err) {
// For plugin not found we fall through to
// cmd.Execute() which deals with reporting
// "command not found" in a consistent way.
return err
}
if args[0] == "offload" {
// Report this before cmd.ExecuteContext(): plugin-specific flags such as
// --cpus otherwise fail parsing before the root command's RunE.
return errors.New("docker: to use 'docker offload', install the plugin.\nSee https://docs.docker.com/go/cloud-flag/")
}
// 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 = ""
}
}
}
+1
View File
@@ -4156,6 +4156,7 @@ _docker_manifest_annotate() {
amd64
arm
arm64
loong64
mips64
mips64le
ppc64le
+1 -1
View File
@@ -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.23
ARG ALPINE_VERSION=3.24
FROM alpine:${ALPINE_VERSION} AS gen
RUN apk add --no-cache bash git
+3 -3
View File
@@ -1,16 +1,16 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.26.8
ARG GO_VERSION=1.27.3
# 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.23
ARG ALPINE_VERSION=3.24
# 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.34.1
ARG BUILDX_VERSION=0.38.1
FROM docker/buildx-bin:${BUILDX_VERSION} AS buildx
FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS golang
+3 -3
View File
@@ -1,13 +1,13 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.26.8
ARG GO_VERSION=1.27.3
# 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.23
ARG ALPINE_VERSION=3.24
# GOLANGCI_LINT_VERSION sets the version of the golangci/golangci-lint image to use.
ARG GOLANGCI_LINT_VERSION=v2.10.1
ARG GOLANGCI_LINT_VERSION=v2.14.0
FROM golangci/golangci-lint:${GOLANGCI_LINT_VERSION}-alpine AS golangci-lint
+3 -3
View File
@@ -1,12 +1,12 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.26.8
ARG GO_VERSION=1.27.3
# 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.23
ARG MODOUTDATED_VERSION=v0.8.0
ARG ALPINE_VERSION=3.24
ARG MODOUTDATED_VERSION=v0.9.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: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
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
$ 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: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
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
$ 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: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
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
$ 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: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
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
```
+5 -5
View File
@@ -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:24.04 bash 17 seconds ago Up 16 seconds 3300-3310/tcp webapp
ca5534a51dd04bbcebe9b23ba05f389466cf0c190f1f8f182d7eea92a9671d00 ubuntu:26.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 `24.04` image:
Match containers based on the `ubuntu` version `26.04` image:
```console
$ docker ps --filter ancestor=ubuntu:24.04
$ docker ps --filter ancestor=ubuntu:26.04
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
82a598284012 ubuntu:24.04 "top" 3 minutes ago Up 3 minutes sleepy_bose
82a598284012 ubuntu:26.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:24.04 "top" 3 minutes ago Up 3 minutes sleepy_bose
82a598284012 ubuntu:26.04 "top" 3 minutes ago Up 3 minutes sleepy_bose
```
#### Create time
+19 -19
View File
@@ -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:bookworm` image shares
its layer with the `debian:latest`. Pulling the `debian:bookworm` image therefore
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
only pulls its metadata, but not its layers, because the layer is already present
locally:
```console
$ docker image pull debian:bookworm
$ docker image pull debian:trixie
bookworm: Pulling from library/debian
trixie: Pulling from library/debian
Digest: sha256:3f1d6c17773a45c97bd8f158d665c9709d7b29ed7917ac934086ad96f92e4510
Status: Downloaded newer image for debian:bookworm
docker.io/library/debian:bookworm
Status: Downloaded newer image for debian:trixie
docker.io/library/debian:trixie
```
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 bookworm 4eacea30377a 8 days ago 124MB
debian trixie 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:bookworm` and `debian:latest` have the same image ID because they are
`debian:trixie` 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:24.04` pulls the latest version of the Ubuntu
24.04 image.
For example, `docker pull ubuntu:26.04` pulls the latest version of the Ubuntu
26.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:24.04` image from Docker Hub:
`ubuntu:26.04` image from Docker Hub:
```console
$ docker pull ubuntu:24.04
$ docker pull ubuntu:26.04
24.04: Pulling from library/ubuntu
26.04: Pulling from library/ubuntu
125a6e411906: Pull complete
Digest: sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30
Status: Downloaded newer image for ubuntu:24.04
docker.io/library/ubuntu:24.04
Status: Downloaded newer image for ubuntu:26.04
docker.io/library/ubuntu:26.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 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 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 latest 35a88802559d 6 weeks ago 78.1MB
ubuntu noble 35a88802559d 6 weeks ago 78.1MB
ubuntu resolute 35a88802559d 6 weeks ago 78.1MB
```
### Cancel a pull
+3 -4
View File
@@ -180,13 +180,12 @@ 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
Press ENTER to open your browser or submit your device code here: https://login.docker.com/activate
Open this URL to authenticate: https://login.docker.com/activate?user_code=LNFR-PGCJ
Waiting for authentication in the browser…
Press ENTER to open the URL in your browser, or Ctrl+C to cancel.
```
After entering the code in your browser, you are authenticated to Docker Hub
+1 -1
View File
@@ -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-24.04` |
| `engine.labels` | Docker Engine's labels | `engine.labels.operatingsystem==ubuntu-26.04` |
`engine.labels` apply to Docker Engine labels like operating system, drivers,
etc. Swarm administrators add `node.labels` for operational purposes by using
+2 -2
View File
@@ -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:24.04)
2014-05-10T17:42:14.999999999Z07:00 container stop 4386fb97867d (image=ubuntu:24.04)
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-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
View File
@@ -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 `24.04` of the `ubuntu` image: `docker run ubuntu:24.04`.
run version `26.04` of the `ubuntu` image: `docker run ubuntu:26.04`.
#### Image digests
@@ -406,14 +406,14 @@ We have four ways to set user memory usage:
Examples:
```console
$ docker run -it ubuntu:24.04 /bin/bash
$ docker run -it ubuntu:26.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:24.04 /bin/bash
$ docker run -it -m 300M --memory-swap -1 ubuntu:26.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:24.04 /bin/bash
$ docker run -it -m 300M ubuntu:26.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:24.04 /bin/bash
$ docker run -it -m 300M --memory-swap 1G ubuntu:26.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:24.04 /bin/bash
$ docker run -it -m 500M --memory-reservation 200M ubuntu:26.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:24.04 /bin/bash
$ docker run -it --memory-reservation 1G ubuntu:26.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:24.04 /bin/bash
$ docker run -it -m 100M --oom-kill-disable ubuntu:26.04 /bin/bash
```
The following example, illustrates a dangerous way to use the flag:
```console
$ docker run -it --oom-kill-disable ubuntu:24.04 /bin/bash
$ docker run -it --oom-kill-disable ubuntu:26.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:24.04 /bin/bash
$ docker run -it --memory-swappiness=0 ubuntu:26.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:24.04 /bin/bash
$ docker run -it --cpu-period=50000 --cpu-quota=25000 ubuntu:26.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:24.04 /bin/bash
$ docker run -it --cpuset-cpus="1,3" ubuntu:26.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:24.04 /bin/bash
$ docker run -it --cpuset-cpus="0-2" ubuntu:26.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:24.04 /bin/bash
$ docker run -it --cpuset-mems="1,3" ubuntu:26.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:24.04 /bin/bash
$ docker run -it --cpuset-mems="0-2" ubuntu:26.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:24.04 /bin/bash
$ docker run -it --name c2 --blkio-weight 600 ubuntu:24.04 /bin/bash
$ 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
```
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:24.04 ip link add dummy0 type dummy
$ docker run -it --rm ubuntu:26.04 ip link add dummy0 type dummy
RTNETLINK answers: Operation not permitted
$ docker run -it --rm --cap-add=NET_ADMIN ubuntu:24.04 ip link add dummy0 type dummy
$ docker run -it --rm --cap-add=NET_ADMIN ubuntu:26.04 ip link add dummy0 type dummy
```
To mount a FUSE based filesystem, you need to combine both `--cap-add` and
+16
View File
@@ -62,6 +62,22 @@ 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)
+1 -1
View File
@@ -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))
}
+27 -14
View File
@@ -7,6 +7,7 @@ import (
"fmt"
"io"
"os"
"os/exec"
"strings"
"github.com/docker/cli/cli/config/credentials"
@@ -17,8 +18,6 @@ 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"
)
@@ -83,19 +82,18 @@ 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 {
logrus.Debugf("failed to start device code login: %v", err)
return nil, ErrDeviceLoginStartFail
return nil, fmt.Errorf("%w: %w", ErrDeviceLoginStartFail, err)
}
if state.UserCode == "" {
logrus.Debugf("failed to start device code login: missing user code")
return nil, ErrDeviceLoginStartFail
return nil, fmt.Errorf("%w: missing user code", ErrDeviceLoginStartFail)
}
_, _ = fmt.Fprintln(w, aec.Bold.Apply("\nUSING WEB-BASED LOGIN"))
var out tui.Output
switch stream := w.(type) {
case *streams.Out:
@@ -103,9 +101,10 @@ func (m *OAuthManager) LoginDevice(ctx context.Context, w io.Writer) (*types.Aut
default:
out = tui.NewOutput(streams.NewOut(w))
}
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])
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.")
tokenResChan := make(chan api.TokenResponse)
waitForTokenErrChan := make(chan error)
@@ -120,11 +119,25 @@ func (m *OAuthManager) LoginDevice(ctx context.Context, w io.Writer) (*types.Aut
go func() {
reader := bufio.NewReader(os.Stdin)
_, _ = reader.ReadString('\n')
_ = m.openBrowser(state.VerificationURI)
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…")
}()
_, _ = fmt.Fprint(w, "\nWaiting for authentication in the browser…\n")
var tokenRes api.TokenResponse
select {
case <-ctx.Done():
+2 -2
View File
@@ -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,
Dial: (&net.Dialer{
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
}).DialContext,
TLSHandshakeTimeout: 10 * time.Second,
TLSClientConfig: endpoint.TLSConfig,
DisableKeepAlives: true,
+6 -3
View File
@@ -27,8 +27,13 @@ func TerminatePrompt(ctx context.Context, t *testing.T, cmd *cobra.Command, cli
}))
cli.SetOut(outStream)
r, _, err := os.Pipe()
r, w, err := os.Pipe()
assert.NilError(t, err)
t.Cleanup(func() {
_ = w.Close()
_ = r.Close()
})
cli.SetIn(streams.NewIn(r))
notifyCtx, notifyCancel := context.WithCancel(ctx)
@@ -58,8 +63,6 @@ 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)
+14 -6
View File
@@ -83,16 +83,24 @@ 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** *variable*
name and value of a **buildarg**.
**--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.
For example, if you want to pass a value for `http_proxy`, use
`--build-arg=http_proxy="http://some.proxy.url"`
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)
See also https://docs.docker.com/reference/dockerfile/#arg and
https://docs.docker.com/reference/cli/docker/buildx/build/#build-arg.
**--cache-from** ""
Set image that will be used as a build cache source.
+2 -2
View File
@@ -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:24.04 /bin/sh -c #(nop) MA 20 minutes ago Exit 0 desperate_brattain
a87ecb4f327c ubuntu:26.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:24.04 /bin/sh -c #(nop) MA 2 weeks ago Exit 0 drunk_pike
41d50ecd2f57 ubuntu:26.04 /bin/sh -c #(nop) MA 2 weeks ago Exit 0 drunk_pike
## Display only IDs of all containers, including non-running
+1 -1
View File
@@ -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 24.04 or 22.04, etc. to manage different
called ubuntu. It may be tagged with 26.04 or 24.04, etc. to manage different
versions.
## Filters
+19 -19
View File
@@ -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:bookworm` image shares
its layer with the `debian:latest`. Pulling the `debian:bookworm` image therefore
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
only pulls its metadata, but not its layers, because the layer is already present
locally:
$ docker image pull debian:bookworm
$ docker image pull debian:trixie
bookworm: Pulling from library/debian
trixie: Pulling from library/debian
Digest: sha256:3f1d6c17773a45c97bd8f158d665c9709d7b29ed7917ac934086ad96f92e4510
Status: Downloaded newer image for debian:bookworm
docker.io/library/debian:bookworm
Status: Downloaded newer image for debian:trixie
docker.io/library/debian:trixie
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 bookworm 4eacea30377a 8 days ago 124MB
debian trixie 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:bookworm` and `debian:latest` have the same image ID because they are
`debian:trixie` 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:24.04` pulls the latest version of the Ubuntu
24.04 image.
For example, `docker image pull ubuntu:26.04` pulls the latest version of the Ubuntu
26.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:24.04` image from Docker Hub:
`ubuntu:26.04` image from Docker Hub:
$ docker image pull ubuntu:24.04
$ docker image pull ubuntu:26.04
24.04: Pulling from library/ubuntu
26.04: Pulling from library/ubuntu
125a6e411906: Pull complete
Digest: sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30
Status: Downloaded newer image for ubuntu:24.04
docker.io/library/ubuntu:24.04
Status: Downloaded newer image for ubuntu:26.04
docker.io/library/ubuntu:26.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 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 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 latest 35a88802559d 6 weeks ago 78.1MB
ubuntu noble 35a88802559d 6 weeks ago 78.1MB
ubuntu resolute 35a88802559d 6 weeks ago 78.1MB
## Cancel a pull
+9 -9
View File
@@ -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:24.04) die
2015-05-12T15:52:12.999999999Z07:00 4386fb97867d: (from ubuntu:24.04) stop
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-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:24.04)
2014-05-10T17:42:14.999999999Z07:00 container stop 4386fb97867d (image=ubuntu:26.04)
2014-09-03T17:42:14.999999999Z07:00 container stop 7805c1d35632 (image=redis:7.2)
$ 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 '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 '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:24.04)
2014-05-10T17:42:14.999999999Z07:00 container stop 4386fb97867d (image=ubuntu:24.04)
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-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)
+2 -2
View File
@@ -71,8 +71,8 @@ Server:
seccomp
Profile: builtin
cgroupns
Kernel Version: 5.15.0-25-generic
Operating System: Ubuntu 22.04 LTS
Kernel Version: 6.8.0-31-generic
Operating System: Ubuntu 24.04 LTS
OSType: linux
Architecture: x86_64
CPUs: 1
+15 -8
View File
@@ -88,13 +88,20 @@ if [ "$CGO_ENABLED" = "1" ] && [ "$(go env GOOS)" != "windows" ]; then
fi
export GO_BUILDMODE
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
# 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
}
if [ "$CGO_ENABLED" = "1" ] && [ "$GO_LINKMODE" = "static" ] && [ "$(go env GOOS)" = "linux" ]; then
GO_LDFLAGS="$GO_LDFLAGS -linkmode external -extldflags -static"
fi
@@ -128,7 +135,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 -w"
GO_LDFLAGS="$GO_LDFLAGS -s"
fi
export GO_LDFLAGS="$GO_LDFLAGS" # https://github.com/koalaman/shellcheck/issues/2064
+31 -30
View File
@@ -21,24 +21,24 @@ 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.9
github.com/docker/go-connections v0.8.1
github.com/docker/docker-credential-helpers v0.9.12
github.com/docker/go-connections v0.8.2
github.com/docker/go-units v0.5.0
github.com/fvbommel/sortorder v1.2.0
github.com/go-jose/go-jose/v4 v4.1.5
github.com/fvbommel/sortorder v1.2.1
github.com/go-jose/go-jose/v4 v4.1.7
github.com/go-viper/mapstructure/v2 v2.5.0
github.com/gogo/protobuf v1.3.2
github.com/google/go-cmp v0.7.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/google/uuid v1.6.0
github.com/mattn/go-runewidth v0.0.30
github.com/mattn/go-runewidth v0.0.31
github.com/moby/go-archive v0.3.3
github.com/moby/moby/api v1.56.1
github.com/moby/moby/client v0.6.1
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/patternmatcher v0.6.1
github.com/moby/swarmkit/v2 v2.1.2
github.com/moby/swarmkit/v2 v2.1.3
github.com/moby/sys/atomicwriter v0.1.0
github.com/moby/sys/capability v0.4.0
github.com/moby/sys/capability v0.5.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,26 +52,26 @@ 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.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
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
gotest.tools/v3 v3.5.2
tags.cncf.io/container-device-interface v1.1.1
)
require (
github.com/Azure/go-ansiterm v0.0.0-20260917205352-e937bb47801a // indirect
github.com/Microsoft/go-winio v0.6.3-0.20260930231756-f19d9717deb0 // indirect; see https://github.com/microsoft/hcsshim/pull/2545
github.com/Azure/go-ansiterm v0.0.0-20261013165250-51075c6ea6bc // 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
github.com/cespare/xxhash/v2 v2.3.0 // 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.1 // indirect
github.com/klauspost/compress v1.20.2 // 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,13 +99,14 @@ 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.46.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.47.0 // indirect
go.opentelemetry.io/otel/log v1.47.0 // indirect
go.opentelemetry.io/proto/otlp v1.11.0 // indirect
golang.org/x/mod v0.41.0 // indirect
golang.org/x/net v0.59.0 // indirect
golang.org/x/mod v0.42.0 // indirect
golang.org/x/net v0.62.0 // indirect
golang.org/x/time v0.16.0 // 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/genproto/googleapis/api v0.0.0-20260928230214-8a89bd6388cc // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260928230214-8a89bd6388cc // indirect
google.golang.org/grpc v1.83.2 // indirect
google.golang.org/protobuf v1.36.12 // indirect
)
+64 -65
View File
@@ -2,10 +2,10 @@ 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-20260917205352-e937bb47801a h1:4hxax9ktNjSDoFn1tZSeL6gXMTRMpO0FzjdKfT01jgY=
github.com/Azure/go-ansiterm v0.0.0-20260917205352-e937bb47801a/go.mod h1:3EWSSOZ50kb+arhww0qIaEXHToib/3FjBj9Jj5lcP5g=
github.com/Microsoft/go-winio v0.6.3-0.20260930231756-f19d9717deb0 h1:71VU8kW/LCxJkx41+YYys1EgQO+AUnPa1TrxTSyYUCU=
github.com/Microsoft/go-winio v0.6.3-0.20260930231756-f19d9717deb0/go.mod h1:ma0QpxizD4fyyzJ1C7MIblymTD2Nxz5Mho/3CepwIZg=
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/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=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
@@ -35,10 +35,10 @@ 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.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.1 h1:JibmG5hULs5qXSr/cp/w3Pw5fZuStt4MOHMUExb29/M=
github.com/docker/go-connections v0.8.1/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q=
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/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=
github.com/docker/go-events v0.1.0/go.mod h1:jwVwMgySJX4PiukIIRrind1wPGU8QhPa8aTEPkreUj4=
github.com/docker/go-metrics v0.1.0 h1:r76KPNpstz+IvQKSWpYegSkkyzex0V3A1ZGVx6bhGlY=
@@ -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.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/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/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,28 +78,28 @@ 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.1 h1:T7kKElXUMXrUJ2E9QhQhxFtcK5rPyLdsGZvdbLMPdiQ=
github.com/klauspost/compress v1.20.1/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
github.com/klauspost/compress v1.20.2 h1:v5tiZvm1KGLyg5d5oXdXe3lsSPrbEUiKoXGia//I7Qo=
github.com/klauspost/compress v1.20.2/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.30 h1:+KUuiDA4fF0R1p5FeueHefjDm+GIM+kWfFnDjybOPgk=
github.com/mattn/go-runewidth v0.0.30/go.mod h1:3qAiGCV4Koz/yuveO58qUefmUTRm8r0IGEXZ9jeHp/8=
github.com/mattn/go-runewidth v0.0.31 h1:1oCV4ReTlosDBc6rYRw5cL8S/4y8iv5oRl4SJ5IBgwo=
github.com/mattn/go-runewidth v0.0.31/go.mod h1:3qAiGCV4Koz/yuveO58qUefmUTRm8r0IGEXZ9jeHp/8=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
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.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.1 h1:gvfKmdcWw+9MzXYP0vAUKQtBTGu1L8475K2nsmL7O98=
github.com/moby/moby/client v0.6.1/go.mod h1:XHgTFqz9NCgS/VuoxXMmEDVmVgXQ4vFEc15wsCIwb24=
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/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.2 h1:1WDZAI6HVYNKdCG4zlXnTAPyLsLwuhRGWlHoOUf5Z6I=
github.com/moby/swarmkit/v2 v2.1.2/go.mod h1:GQ6T0ij2oBbWX10OHwpvK449xfXkQMZ8J+B+eQ4mgp4=
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/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.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk=
github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I=
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/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,64 +155,65 @@ 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.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/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/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.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
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=
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.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c=
golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o=
golang.org/x/mod v0.42.0 h1:ICeL3t2L30ljSPHHxDnR4fqVcBt/zR2zJAb9juavmQg=
golang.org/x/mod v0.42.0/go.mod h1:u5fzIrRInkL8MaO1cbRkUHT64v303YIT5KEqpNr7jRs=
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.59.0 h1:5zfYln+w5XCxwrnMMJPufRgNoXEaGxl0wo5GqPXyues=
golang.org/x/net v0.59.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg=
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/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.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk=
golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0=
golang.org/x/sync v0.24.0 h1:iqiDrGoDgyuvAKrhLQthUEzU/R378N78gXbBjxed7oA=
golang.org/x/sync v0.24.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.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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/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/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.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI=
golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E=
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/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=
@@ -225,10 +226,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-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/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/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=
@@ -236,7 +237,5 @@ 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=
+7 -5
View File
@@ -1,5 +1,7 @@
package ansiterm
import "slices"
type csiEntryState struct {
baseState
}
@@ -13,11 +15,11 @@ func (csiState csiEntryState) Handle(b byte) (s state, e error) {
}
switch {
case sliceContains(alphabetics, b):
case slices.Contains(alphabetics, b):
return csiState.parser.ground, nil
case sliceContains(csiCollectables, b):
case slices.Contains(csiCollectables, b):
return csiState.parser.csiParam, nil
case sliceContains(executors, b):
case slices.Contains(executors, b):
return csiState, csiState.parser.execute()
}
@@ -33,9 +35,9 @@ func (csiState csiEntryState) Transition(s state) error {
return csiState.parser.csiDispatch()
case csiState.parser.csiParam:
switch {
case sliceContains(csiParams, csiState.parser.context.currentChar):
case slices.Contains(csiParams, csiState.parser.context.currentChar):
_ = csiState.parser.collectParam()
case sliceContains(intermeds, csiState.parser.context.currentChar):
case slices.Contains(intermeds, csiState.parser.context.currentChar):
_ = csiState.parser.collectInter()
}
}
+5 -3
View File
@@ -1,5 +1,7 @@
package ansiterm
import "slices"
type csiParamState struct {
baseState
}
@@ -13,11 +15,11 @@ func (csiState csiParamState) Handle(b byte) (s state, e error) {
}
switch {
case sliceContains(alphabetics, b):
case slices.Contains(alphabetics, b):
return csiState.parser.ground, nil
case sliceContains(csiCollectables, b):
case slices.Contains(csiCollectables, b):
return csiState, csiState.parser.collectParam()
case sliceContains(executors, b):
case slices.Contains(executors, b):
return csiState, csiState.parser.execute()
}
+5 -3
View File
@@ -1,5 +1,7 @@
package ansiterm
import "slices"
type escapeIntermediateState struct {
baseState
}
@@ -12,11 +14,11 @@ func (escState escapeIntermediateState) Handle(b byte) (s state, e error) {
}
switch {
case sliceContains(intermeds, b):
case slices.Contains(intermeds, b):
return escState, escState.parser.collectInter()
case sliceContains(executors, b):
case slices.Contains(executors, b):
return escState, escState.parser.execute()
case sliceContains(escapeIntermediateToGroundBytes, b):
case slices.Contains(escapeIntermediateToGroundBytes, b):
return escState.parser.ground, nil
}
+5 -3
View File
@@ -1,5 +1,7 @@
package ansiterm
import "slices"
type escapeState struct {
baseState
}
@@ -16,11 +18,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 sliceContains(executors, b):
case slices.Contains(executors, b):
return escState, escState.parser.execute()
case sliceContains(escapeToGroundBytes, b):
case slices.Contains(escapeToGroundBytes, b):
return escState.parser.ground, nil
case sliceContains(intermeds, b):
case slices.Contains(intermeds, b):
return escState.parser.escapeIntermediate, nil
}
+4 -2
View File
@@ -1,5 +1,7 @@
package ansiterm
import "slices"
type groundState struct {
baseState
}
@@ -13,10 +15,10 @@ func (gs groundState) Handle(b byte) (s state, e error) {
}
switch {
case sliceContains(printables, b):
case slices.Contains(printables, b):
return gs, gs.parser.print()
case sliceContains(executors, b):
case slices.Contains(executors, b):
return gs, gs.parser.execute()
}
+4 -4
View File
@@ -20,12 +20,12 @@ type AnsiParser struct {
oscString state
stateMap []state
logf func(string, ...interface{})
logf func(string, ...any)
}
type Option func(*AnsiParser)
func WithLogf(f func(string, ...interface{})) Option {
func WithLogf(f func(string, ...any)) 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 ...interface{}) {
ap.logf = func(s string, v ...any) {
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, ...interface{}) {}
ap.logf = func(string, ...any) {}
}
ap.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: ap}}
+1 -1
View File
@@ -49,7 +49,7 @@ func getInts(params []string, minCount int, dflt int) []int {
if len(ints) < minCount {
remaining := minCount - len(ints)
for i := 0; i < remaining; i++ {
for range remaining {
ints = append(ints, dflt)
}
}
+4 -2
View File
@@ -1,5 +1,7 @@
package ansiterm
import "slices"
type state interface {
Enter() error
Exit() error
@@ -32,7 +34,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 sliceContains(toGroundBytes, b):
case slices.Contains(toGroundBytes, b):
return base.parser.ground, nil
}
@@ -52,7 +54,7 @@ func (base baseState) Transition(s state) error {
execBytes = append(execBytes, 0x99)
execBytes = append(execBytes, 0x9A)
if sliceContains(execBytes, base.parser.context.currentChar) {
if slices.Contains(execBytes, base.parser.context.currentChar) {
return base.parser.execute()
}
}
-11
View File
@@ -1,11 +0,0 @@
package ansiterm
func sliceContains(bytes []byte, b byte) bool {
for _, v := range bytes {
if v == b {
return true
}
}
return false
}
+1 -1
View File
@@ -1,4 +1,4 @@
// +build windows
//go:build windows
package winterm
+96 -90
View File
@@ -1,14 +1,17 @@
// +build windows
//go: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.
@@ -26,51 +29,50 @@ import (
// -- The value is not referenced by the method after passing the pointer to Windows
//
// See http://golang.org/doc/go1.3.
//===========================================================================================================
// ===========================================================================================================
var (
kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
kernel32DLL = windows.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")
)
// Windows Console constants
// Console modes
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
const (
// 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_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
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
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
)
// 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.
// 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 (
FOREGROUND_BLUE uint16 = 0x0001
FOREGROUND_GREEN uint16 = 0x0002
FOREGROUND_RED uint16 = 0x0004
@@ -86,23 +88,29 @@ 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.
KEY_EVENT = 0x0001
MOUSE_EVENT = 0x0002
WINDOW_BUFFER_SIZE_EVENT = 0x0004
MENU_EVENT = 0x0008
FOCUS_EVENT = 0x0010
// 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
)
// WaitForSingleObject return codes
WAIT_ABANDONED = 0x00000080
WAIT_FAILED = 0xFFFFFFFF
WAIT_SIGNALED = 0x0000000
WAIT_TIMEOUT = 0x00000102
// 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 wait duration
WAIT_INFINITE = 0xFFFFFFFF
// WaitForSingleObject wait durations.
const (
WAIT_INFINITE = windows.INFINITE
WAIT_ONE_SECOND = 1000
WAIT_HALF_SECOND = 500
WAIT_QUARTER_SECOND = 250
@@ -122,6 +130,8 @@ 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
@@ -130,17 +140,11 @@ type (
MaximumWindowSize COORD
}
COORD struct {
X int16
Y int16
}
// COORD is identical to [windows.Coord] but implements [fmt.Stringer].
COORD windows.Coord
SMALL_RECT struct {
Left int16
Top int16
Right int16
Bottom int16
}
// SMALL_RECT is identical to [windows.SmallRect] but implements [fmt.Stringer].
SMALL_RECT windows.SmallRect
// 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.
@@ -189,43 +193,45 @@ 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 {
r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord))
use(coord)
return checkError(r1, r2, err)
return windows.SetConsoleCursorPosition(windows.Handle(handle), windows.Coord(coord))
}
// GetConsoleMode gets the console mode for given file descriptor
// GetConsoleMode gets the console mode for the given handle.
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx.
func GetConsoleMode(handle uintptr) (mode uint32, err error) {
err = syscall.GetConsoleMode(syscall.Handle(handle), &mode)
err = windows.GetConsoleMode(windows.Handle(handle), &mode)
return mode, err
}
// SetConsoleMode sets the console mode for given file descriptor
// SetConsoleMode sets the console mode for the given handle.
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
func SetConsoleMode(handle uintptr, mode uint32) error {
r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0)
use(mode)
return checkError(r1, r2, err)
return windows.SetConsoleMode(windows.Handle(handle), mode)
}
// 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) {
info := CONSOLE_SCREEN_BUFFER_INFO{}
err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0))
if err != nil {
var info windows.ConsoleScreenBufferInfo
if err := windows.GetConsoleScreenBufferInfo(windows.Handle(handle), &info); err != nil {
return nil, err
}
return &info, nil
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
}
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)))
use(scrollRect)
use(clipRect)
use(destOrigin)
use(char)
runtime.KeepAlive(scrollRect)
runtime.KeepAlive(clipRect)
runtime.KeepAlive(destOrigin)
runtime.KeepAlive(char)
return checkError(r1, r2, err)
}
@@ -233,7 +239,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))
use(coord)
runtime.KeepAlive(coord)
return checkError(r1, r2, err)
}
@@ -242,7 +248,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)
use(attribute)
runtime.KeepAlive(attribute)
return checkError(r1, r2, err)
}
@@ -251,8 +257,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)))
use(isAbsolute)
use(rect)
runtime.KeepAlive(isAbsolute)
runtime.KeepAlive(rect)
return checkError(r1, r2, err)
}
@@ -260,9 +266,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)))
use(buffer)
use(bufferSize)
use(bufferCoord)
runtime.KeepAlive(buffer)
runtime.KeepAlive(bufferSize)
runtime.KeepAlive(bufferCoord)
return checkError(r1, r2, err)
}
@@ -270,7 +276,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)))
use(buffer)
runtime.KeepAlive(buffer)
return checkError(r1, r2, err)
}
@@ -278,15 +284,19 @@ 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) {
r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait)))
switch r1 {
case WAIT_ABANDONED, WAIT_TIMEOUT:
event, err := windows.WaitForSingleObject(windows.Handle(handle), msWait)
if err != nil {
return false, err
}
switch event {
case windows.WAIT_ABANDONED, uint32(windows.WAIT_TIMEOUT):
return false, nil
case WAIT_SIGNALED:
case windows.WAIT_OBJECT_0:
return true, nil
default:
return false, nil
}
use(msWait)
return false, err
}
// String helpers
@@ -321,7 +331,3 @@ 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
View File
@@ -1,4 +1,4 @@
// +build windows
//go:build windows
package winterm
+11 -33
View File
@@ -1,10 +1,12 @@
// +build windows
//go:build windows
package winterm
const (
horizontal = iota
vertical
line
column
)
func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT {
@@ -58,44 +60,20 @@ 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
}
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
return err
}
return nil
return h.setCursorPosition(position, h.getCursorWindow(info))
}
func (h *windowsAnsiEventHandler) moveCursorLine(param int) error {
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
return h.moveCursor(line, param)
}
func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error {
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
return h.moveCursor(column, param)
}
+3 -13
View File
@@ -1,4 +1,4 @@
// +build windows
//go:build windows
package winterm
@@ -50,12 +50,7 @@ func (h *windowsAnsiEventHandler) clearRange(attributes uint16, fromCoord COORD,
coordStart.X, coordStart.Y = xCurrent, yCurrent
coordEnd.X, coordEnd.Y = xEnd, yEnd
err = h.clearRect(attributes, coordStart, coordEnd)
if err != nil {
return err
}
return nil
return h.clearRect(attributes, coordStart, coordEnd)
}
func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD, toCoord COORD) error {
@@ -75,10 +70,5 @@ func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD,
buffer[i] = char
}
err := WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, &region)
if err != nil {
return err
}
return nil
return WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, &region)
}
+4 -11
View File
@@ -1,4 +1,4 @@
// +build windows
//go:build windows
package winterm
@@ -39,9 +39,8 @@ 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 {
@@ -72,10 +71,7 @@ func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSO
Attributes: h.attributes,
}
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
return err
}
return nil
return ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char)
}
func (h *windowsAnsiEventHandler) deleteCharacters(param int) error {
@@ -111,8 +107,5 @@ func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *
Attributes: h.attributes,
}
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
return err
}
return nil
return ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char)
}
+1 -1
View File
@@ -1,4 +1,4 @@
// +build windows
//go:build windows
package winterm
+19 -33
View File
@@ -1,4 +1,4 @@
// +build windows
//go:build windows
package winterm
@@ -169,9 +169,7 @@ func (h *windowsAnsiEventHandler) executeLF() error {
return err
}
h.logf("Resetting cursor position for LF without CR")
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
return err
}
return SetConsoleCursorPosition(h.fd, pos)
}
}
return nil
@@ -373,7 +371,7 @@ func (h *windowsAnsiEventHandler) CUP(row int, col int) error {
}
window := h.getCursorWindow(info)
position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1}
position := COORD{X: window.Left + int16(col) - 1, Y: window.Top + int16(row) - 1}
return h.setCursorPosition(position, window)
}
@@ -423,7 +421,7 @@ func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error {
targetWidth = 132
}
if info.Size.X < targetWidth {
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
if err := SetConsoleScreenBufferSize(h.fd, COORD{X: targetWidth, Y: info.Size.Y}); err != nil {
h.logf("set buffer failed: %v", err)
return err
}
@@ -436,12 +434,12 @@ func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error {
return err
}
if info.Size.X > targetWidth {
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
if err := SetConsoleScreenBufferSize(h.fd, COORD{X: targetWidth, Y: info.Size.Y}); err != nil {
h.logf("set buffer failed: %v", err)
return err
}
}
return SetConsoleCursorPosition(h.fd, COORD{0, 0})
return SetConsoleCursorPosition(h.fd, COORD{X: 0, Y: 0})
}
func (h *windowsAnsiEventHandler) ED(param int) error {
@@ -468,15 +466,15 @@ func (h *windowsAnsiEventHandler) ED(param int) error {
switch param {
case 0:
start = info.CursorPosition
end = COORD{info.Size.X - 1, info.Size.Y - 1}
end = COORD{X: info.Size.X - 1, Y: info.Size.Y - 1}
case 1:
start = COORD{0, 0}
start = COORD{X: 0, Y: 0}
end = info.CursorPosition
case 2:
start = COORD{0, 0}
end = COORD{info.Size.X - 1, info.Size.Y - 1}
start = COORD{X: 0, Y: 0}
end = COORD{X: info.Size.X - 1, Y: info.Size.Y - 1}
}
err = h.clearRange(h.attributes, start, end)
@@ -495,9 +493,7 @@ func (h *windowsAnsiEventHandler) ED(param int) error {
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
return err
}
if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
return err
}
return SetConsoleWindowInfo(h.fd, true, window)
}
return nil
@@ -525,23 +521,18 @@ func (h *windowsAnsiEventHandler) EL(param int) error {
switch param {
case 0:
start = info.CursorPosition
end = COORD{info.Size.X, info.CursorPosition.Y}
end = COORD{X: info.Size.X, Y: info.CursorPosition.Y}
case 1:
start = COORD{0, info.CursorPosition.Y}
start = COORD{X: 0, Y: info.CursorPosition.Y}
end = info.CursorPosition
case 2:
start = COORD{0, info.CursorPosition.Y}
end = COORD{info.Size.X, info.CursorPosition.Y}
start = COORD{X: 0, Y: info.CursorPosition.Y}
end = COORD{X: info.Size.X, Y: info.CursorPosition.Y}
}
err = h.clearRange(h.attributes, start, end)
if err != nil {
return err
}
return nil
return h.clearRange(h.attributes, start, end)
}
func (h *windowsAnsiEventHandler) IL(param int) error {
@@ -611,12 +602,7 @@ func (h *windowsAnsiEventHandler) SGR(params []int) error {
if h.inverted {
attributes = invertAttributes(attributes)
}
err := SetConsoleTextAttribute(h.fd, attributes)
if err != nil {
return err
}
return nil
return SetConsoleTextAttribute(h.fd, attributes)
}
func (h *windowsAnsiEventHandler) SU(param int) error {
@@ -702,8 +688,8 @@ func (h *windowsAnsiEventHandler) Flush() error {
}
charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}}
size := COORD{1, 1}
position := COORD{0, 0}
size := COORD{X: 1, Y: 1}
position := COORD{X: 0, Y: 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, &region); err != nil {
return err
+25 -7
View File
@@ -3,8 +3,9 @@
package winio
import (
"errors"
"context"
"io"
"os"
"runtime"
"sync"
"sync/atomic"
@@ -20,16 +21,33 @@ import (
//sys setFileCompletionNotificationModes(h windows.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
//sys wsaGetOverlappedResult(h windows.Handle, o *windows.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult
var (
ErrFileClosed = errors.New("file has already been closed")
ErrTimeout = &timeoutError{}
)
// ErrFileClosed is returned when an operation is performed on a closed file.
//
// Deprecated: use [os.ErrClosed] instead.
var ErrFileClosed = os.ErrClosed
// ErrTimeout is returned when an I/O operation exceeds its deadline.
//
// It matches both [context.DeadlineExceeded] and [os.ErrDeadlineExceeded]
// with [errors.Is].
var ErrTimeout error = &timeoutError{}
// timeoutError preserves the historical "i/o timeout" error while matching
// both context.DeadlineExceeded and os.ErrDeadlineExceeded through errors.Is.
// This mirrors the behavior of net.errTimeout:
// https://github.com/golang/go/blob/go1.27.1/src/net/net.go
//
// TODO: consider replacing ErrTimeout with os.ErrDeadlineExceeded if os.ErrDeadlineExceeded is changed to match context.DeadlineExceeded.
type timeoutError struct{}
func (*timeoutError) Error() string { return "i/o timeout" }
func (*timeoutError) Timeout() bool { return true }
func (*timeoutError) Temporary() bool { return true }
func (*timeoutError) Unwrap() error { return os.ErrDeadlineExceeded }
func (*timeoutError) Is(err error) bool {
return err == context.DeadlineExceeded
}
type timeoutChan chan struct{}
@@ -143,7 +161,7 @@ func (f *win32File) prepareIO() (*ioOperation, error) {
f.wgLock.RLock()
if f.closing.Load() {
f.wgLock.RUnlock()
return nil, ErrFileClosed
return nil, os.ErrClosed
}
f.wg.Add(1)
f.wgLock.RUnlock()
@@ -192,7 +210,7 @@ func (f *win32File) asyncIO(c *ioOperation, d *deadlineHandler, bytes uint32, er
err = r.err
if err == windows.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
if f.closing.Load() {
err = ErrFileClosed
err = os.ErrClosed
}
} else if err != nil && f.socket {
// err is from Win32. Query the overlapped structure to get the winsock error.
+1 -1
View File
@@ -441,7 +441,7 @@ func canRedial(err error) bool {
func (conn *HvsockConn) opErr(op string, err error) error {
// translate from "file closed" to "socket closed"
if errors.Is(err, ErrFileClosed) {
if errors.Is(err, os.ErrClosed) {
err = socket.ErrSocketClosed
}
return &net.OpError{Op: op, Net: "hvsock", Source: &conn.local, Addr: &conn.remote, Err: err}
+11 -12
View File
@@ -102,12 +102,10 @@ func (status ntStatus) Err() error {
return rtlNtStatusToDosError(status)
}
var (
// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed.
ErrPipeListenerClosed = net.ErrClosed
errPipeWriteClosed = errors.New("pipe has been closed for write")
)
// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed.
//
// Deprecated: use [net.ErrClosed] instead.
var ErrPipeListenerClosed = net.ErrClosed
type win32Pipe struct {
*win32File
@@ -144,9 +142,10 @@ func (f *win32Pipe) Disconnect() error {
}
// CloseWrite closes the write side of a message pipe in byte mode.
// It returns [io.ErrClosedPipe] if the write side is already closed.
func (f *win32MessageBytePipe) CloseWrite() error {
if f.writeClosed {
return errPipeWriteClosed
return io.ErrClosedPipe
}
err := f.win32File.Flush()
if err != nil {
@@ -161,10 +160,10 @@ func (f *win32MessageBytePipe) CloseWrite() error {
}
// Write writes bytes to a message pipe in byte mode. Zero-byte writes are ignored, since
// they are used to implement CloseWrite().
// they are used to implement CloseWrite. It returns [io.ErrClosedPipe] if the write side is closed.
func (f *win32MessageBytePipe) Write(b []byte) (int, error) {
if f.writeClosed {
return 0, errPipeWriteClosed
return 0, io.ErrClosedPipe
}
if len(b) == 0 {
return 0, nil
@@ -454,7 +453,7 @@ func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, error) {
_ = p.Close()
p = nil
<-ch
err = ErrPipeListenerClosed
err = net.ErrClosed
}
return p, err
}
@@ -479,7 +478,7 @@ func (l *win32PipeListener) listenerRoutine() {
}
}
responseCh <- acceptResponse{p, err}
closed = err == ErrPipeListenerClosed //nolint:errorlint // err is Errno
closed = err == net.ErrClosed //nolint:errorlint // err is Errno
}
}
windows.Close(l.firstHandle)
@@ -571,7 +570,7 @@ func (l *win32PipeListener) Accept() (net.Conn, error) {
}
return &win32Pipe{win32File: response.f, path: l.path}, nil
case <-l.doneCh:
return nil, ErrPipeListenerClosed
return nil, net.ErrClosed
}
}
+5 -1
View File
@@ -9,13 +9,17 @@ import (
// NewTCPSocket creates a TCP socket listener with the specified address and
// the specified tls configuration. If TLSConfig is set, will encapsulate the
// TCP listener inside a TLS one.
// If no ALPN protocols are configured, it defaults to HTTP/1.1.
func NewTCPSocket(addr string, tlsConfig *tls.Config) (net.Listener, error) {
l, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
if tlsConfig != nil {
tlsConfig.NextProtos = []string{"http/1.1"}
if len(tlsConfig.NextProtos) == 0 {
tlsConfig = tlsConfig.Clone()
tlsConfig.NextProtos = []string{"http/1.1"}
}
l = tls.NewListener(l, tlsConfig)
}
return l, nil
+33 -3
View File
@@ -408,7 +408,10 @@ func (ctx *genericEncrypter) EncryptWithAuthData(plaintext, aad []byte) (*JSONWe
(*obj.protected)[k] = makeRawMessage(b)
}
authData := obj.computeAuthData()
authData, err := obj.computeAuthData()
if err != nil {
return nil, err
}
parts, err := ctx.cipher.encrypt(cek, authData, plaintext)
if err != nil {
return nil, err
@@ -428,6 +431,13 @@ 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.
@@ -485,7 +495,10 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error)
tag: obj.tag,
}
authData := obj.computeAuthData()
authData, err := obj.computeAuthData()
if err != nil {
return nil, err
}
var plaintext []byte
recipient := obj.recipients[0]
@@ -495,6 +508,10 @@ 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)
@@ -520,6 +537,12 @@ 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)
@@ -553,7 +576,10 @@ func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Heade
tag: obj.tag,
}
authData := obj.computeAuthData()
authData, err := obj.computeAuthData()
if err != nil {
return -1, Header{}, nil, err
}
index := -1
var plaintext []byte
@@ -572,6 +598,10 @@ 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)
+6 -32
View File
@@ -30,30 +30,6 @@ 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{}
@@ -122,6 +98,8 @@ 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
}
@@ -169,13 +147,13 @@ func (b *byteBuffer) UnmarshalJSON(data []byte) error {
return err
}
*b = *newBuffer(decoded)
b.data = decoded
return nil
}
func (b *byteBuffer) base64() string {
return base64.RawURLEncoding.EncodeToString(b.data)
return base64.RawURLEncoding.EncodeToString(b.bytes())
}
func (b *byteBuffer) bytes() []byte {
@@ -186,12 +164,8 @@ func (b *byteBuffer) bytes() []byte {
return b.data
}
func (b byteBuffer) bigInt() *big.Int {
return new(big.Int).SetBytes(b.data)
}
func (b byteBuffer) toInt() int {
return int(b.bigInt().Int64())
func (b *byteBuffer) bigInt() *big.Int {
return new(big.Int).SetBytes(b.bytes())
}
func base64EncodeLen(sl []byte) int {
+13
View File
@@ -671,6 +671,19 @@ 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()
+13 -1
View File
@@ -1025,7 +1025,19 @@ 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.PkgPath != "" && !sf.Anonymous { // unexported
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.
continue
}
tag := sf.Tag.Get("json")
+59 -25
View File
@@ -25,6 +25,12 @@ 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"`
@@ -84,14 +90,18 @@ func (obj JSONWebEncryption) mergedHeaders(recipient *recipientInfo) rawHeader {
}
// Get the additional authenticated data from a JWE object.
func (obj JSONWebEncryption) computeAuthData() []byte {
func (obj JSONWebEncryption) computeAuthData() ([]byte, error) {
var protected string
switch {
case obj.original != nil && obj.original.Protected != nil:
protected = obj.original.Protected.base64()
case obj.protected != nil:
protected = base64.RawURLEncoding.EncodeToString(mustSerializeJSON((obj.protected)))
serializedProtected, err := json.Marshal(obj.protected)
if err != nil {
return nil, err
}
protected = base64.RawURLEncoding.EncodeToString(serializedProtected)
default:
protected = ""
}
@@ -102,7 +112,7 @@ func (obj JSONWebEncryption) computeAuthData() []byte {
output = append(output, []byte(base64.RawURLEncoding.EncodeToString(obj.aad))...)
}
return output
return output, nil
}
func containsKeyAlgorithm(haystack []KeyAlgorithm, needle KeyAlgorithm) bool {
@@ -128,11 +138,10 @@ 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 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.
// 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.
func ParseEncrypted(input string,
keyEncryptionAlgorithms []KeyAlgorithm,
contentEncryption []ContentEncryption,
@@ -145,9 +154,13 @@ func ParseEncrypted(input string,
return ParseEncryptedCompact(input, keyEncryptionAlgorithms, contentEncryption)
}
// ParseEncryptedJSON parses a message in JWE JSON Serialization.
// ParseEncryptedJSON parses a message in JWE JSON Serialization. Messages with
// more than [MaxRecipients] recipients are rejected.
//
// 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,
@@ -177,6 +190,9 @@ 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,
@@ -195,21 +211,11 @@ func (parsed *rawJSONWebEncryption) sanitized(
}
}
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()
protected, err := parseProtectedHeader(parsed.Protected)
if err != nil {
return nil, fmt.Errorf("go-jose/go-jose: cannot sanitize merged headers: %v (%v)", err, mergedHeaders)
return nil, err
}
obj.protected = protected
if len(parsed.Recipients) == 0 {
obj.recipients = []recipientInfo{
@@ -264,6 +270,14 @@ 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()
@@ -287,6 +301,9 @@ 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,
@@ -354,7 +371,10 @@ func (obj JSONWebEncryption) CompactSerialize() (string, error) {
return "", ErrNotSupported
}
serializedProtected := mustSerializeJSON(obj.protected)
serializedProtected, err := json.Marshal(obj.protected)
if err != nil {
return "", err
}
return base64JoinWithDots(
serializedProtected,
@@ -366,7 +386,13 @@ 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),
@@ -392,8 +418,16 @@ func (obj JSONWebEncryption) FullSerialize() string {
}
if obj.protected != nil {
raw.Protected = newBuffer(mustSerializeJSON(obj.protected))
serializedProtected, err := json.Marshal(obj.protected)
if err != nil {
return ""
}
raw.Protected = newBuffer(serializedProtected)
}
return string(mustSerializeJSON(raw))
out, err := json.Marshal(raw)
if err != nil {
return ""
}
return string(out)
}
+74 -24
View File
@@ -30,6 +30,7 @@ import (
"encoding/hex"
"errors"
"fmt"
"math"
"math/big"
"net/url"
"reflect"
@@ -177,13 +178,29 @@ func (k JSONWebKey) MarshalJSON() ([]byte, error) {
// UnmarshalJSON reads a key from its JSON representation.
//
// Returns ErrUnsupportedKeyType for unrecognized or unsupported "kty" header values.
func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
//
// 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) {
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)
@@ -233,7 +250,7 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
keyPub = key
}
case "oct":
if certPub != nil {
if len(certs) > 0 {
return errors.New("go-jose/go-jose: invalid JWK, found 'oct' (symmetric) key with cert chain")
}
key, err = raw.symmetricKey()
@@ -272,10 +289,8 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
return ErrUnsupportedKeyType
}
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")
}
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")
}
*k = JSONWebKey{Key: key, KeyID: raw.Kid, Algorithm: raw.Alg, Use: raw.Use, Certificates: certs}
@@ -392,6 +407,9 @@ 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
@@ -505,14 +523,41 @@ 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) {
if key.N == nil || key.E == nil {
return rsaPublicKey(key.N, key.E)
}
func rsaPublicKey(N, E *byteBuffer) (*rsa.PublicKey, error) {
if N == nil || 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: key.N.bigInt(),
E: key.E.toInt(),
N: n,
E: int(eInt64),
}, nil
}
@@ -556,11 +601,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.data) {
if curveSize(curve) != len(key.X.bytes()) {
return nil, fmt.Errorf("go-jose/go-jose: invalid EC public key, wrong length for x")
}
if curveSize(curve) != len(key.Y.data) {
if curveSize(curve) != len(key.Y.bytes()) {
return nil, fmt.Errorf("go-jose/go-jose: invalid EC public key, wrong length for y")
}
@@ -673,16 +718,21 @@ 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: rsa.PublicKey{
N: key.N.bigInt(),
E: key.E.toInt(),
},
D: key.D.bigInt(),
Primes: []*big.Int{
key.P.bigInt(),
key.Q.bigInt(),
},
PublicKey: *pubKey,
D: key.D.bigInt(),
Primes: []*big.Int{p, q},
}
if key.Dp != nil {
@@ -695,7 +745,7 @@ func (key rawJSONWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) {
rv.Precomputed.Qinv = key.Qi.bigInt()
}
err := rv.Validate()
err = rv.Validate()
return rv, err
}
@@ -769,16 +819,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.data) {
if curveSize(curve) != len(key.X.bytes()) {
return nil, fmt.Errorf("go-jose/go-jose: invalid EC private key, wrong length for x")
}
if curveSize(curve) != len(key.Y.data) {
if curveSize(curve) != len(key.Y.bytes()) {
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.data) {
if dSize(curve) != len(key.D.bytes()) {
return nil, fmt.Errorf("go-jose/go-jose: invalid EC private key, wrong length for d")
}
+79 -32
View File
@@ -27,6 +27,12 @@ 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"`
@@ -86,6 +92,11 @@ 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,
@@ -108,6 +119,9 @@ 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,
@@ -125,6 +139,9 @@ 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,
@@ -157,7 +174,11 @@ func (obj JSONWebSignature) computeAuthData(payload []byte, signature *Signature
authData.WriteString(signature.original.Protected.base64())
} else if signature.protected != nil {
protectedHeader = signature.protected
authData.WriteString(base64.RawURLEncoding.EncodeToString(mustSerializeJSON(protectedHeader)))
serializedProtected, err := json.Marshal(protectedHeader)
if err != nil {
return nil, err
}
authData.WriteString(base64.RawURLEncoding.EncodeToString(serializedProtected))
}
needsBase64 := true
@@ -180,9 +201,13 @@ func (obj JSONWebSignature) computeAuthData(payload []byte, signature *Signature
return authData.Bytes(), nil
}
// ParseSignedJSON parses a message in JWS JSON Serialization.
// ParseSignedJSON parses a message in JWS JSON Serialization. Messages with
// more than [MaxSignatures] signatures are rejected.
//
// 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,
@@ -236,6 +261,9 @@ 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(),
@@ -245,14 +273,13 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
if len(parsed.Signatures) == 0 {
// No signatures array, must be flattened serialization
signature := Signature{}
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
}
prot, err := parseProtectedHeader(parsed.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
@@ -275,17 +302,17 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
Signature: parsed.Signature,
}
var err error
signature.Header, err = signature.mergedHeaders().sanitized()
if err != nil {
return nil, err
}
alg := SignatureAlgorithm(signature.Header.Algorithm)
mergedHeaders := signature.mergedHeaders()
alg := mergedHeaders.getSignatureAlgorithm()
if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms)
}
signature.Header, err = mergedHeaders.sanitized()
if err != nil {
return nil, err
}
if signature.header != nil {
signature.Unprotected, err = signature.header.sanitized()
if err != nil {
@@ -310,30 +337,31 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
}
for i, sig := range parsed.Signatures {
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
}
prot, err := parseProtectedHeader(sig.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
}
var err error
obj.Signatures[i].Header, err = obj.Signatures[i].mergedHeaders().sanitized()
if err != nil {
return nil, err
}
obj.Signatures[i].header = sig.Header
alg := SignatureAlgorithm(obj.Signatures[i].Header.Algorithm)
mergedHeaders := obj.Signatures[i].mergedHeaders()
alg := mergedHeaders.getSignatureAlgorithm()
if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms)
}
obj.Signatures[i].Header, err = mergedHeaders.sanitized()
if err != nil {
return nil, err
}
if obj.Signatures[i].header != nil {
obj.Signatures[i].Unprotected, err = obj.Signatures[i].header.sanitized()
if err != nil {
@@ -359,7 +387,6 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
// Copy value of sig
original := sig
obj.Signatures[i].header = sig.Header
obj.Signatures[i].original = &original
}
@@ -424,7 +451,10 @@ func (obj JSONWebSignature) compactSerialize(detached bool) (string, error) {
return "", ErrNotSupported
}
serializedProtected := mustSerializeJSON(obj.Signatures[0].protected)
serializedProtected, err := json.Marshal(obj.Signatures[0].protected)
if err != nil {
return "", err
}
var payload []byte
if !detached {
@@ -449,14 +479,23 @@ 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 := mustSerializeJSON(obj.Signatures[0].protected)
serializedProtected, err := json.Marshal(obj.Signatures[0].protected)
if err != nil {
return ""
}
raw.Protected = newBuffer(serializedProtected)
}
raw.Header = obj.Signatures[0].header
@@ -470,10 +509,18 @@ func (obj JSONWebSignature) FullSerialize() string {
}
if signature.protected != nil {
raw.Signatures[i].Protected = newBuffer(mustSerializeJSON(signature.protected))
serializedProtected, err := json.Marshal(signature.protected)
if err != nil {
return ""
}
raw.Signatures[i].Protected = newBuffer(serializedProtected)
}
}
}
return string(mustSerializeJSON(raw))
out, err := json.Marshal(raw)
if err != nil {
return ""
}
return string(out)
}
+1 -1
View File
@@ -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 field, token issued in the future (iat)")
var ErrIssuedInTheFuture = errors.New("go-jose/go-jose/jwt: validation failed, 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)")
+12 -17
View File
@@ -85,7 +85,12 @@ func (t *NestedJSONWebToken) Decrypt(decryptionKey interface{}) (*JSONWebToken,
return sig, nil
}
// ParseSigned parses token from JWS form.
// 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.
func ParseSigned(s string, signatureAlgorithms []jose.SignatureAlgorithm) (*JSONWebToken, error) {
sig, err := jose.ParseSignedCompact(s, signatureAlgorithms)
if err != nil {
@@ -142,13 +147,10 @@ func parseEncryptedCompact(
return enc, nil
}
// ParseEncrypted parses token from JWE form.
// ParseEncrypted parses a JWT in the JWE Compact Serialization.
//
// 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.
// 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.
func ParseEncrypted(s string,
keyAlgorithms []jose.KeyAlgorithm,
contentEncryption []jose.ContentEncryption,
@@ -164,17 +166,10 @@ func ParseEncrypted(s string,
}, nil
}
// ParseSignedAndEncrypted parses signed-then-encrypted token from JWE form.
// ParseSignedAndEncrypted parses a signed-then-encrypted token in the JWE Compact Serialization.
//
// 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.
// The encryptionKeyAlgorithms, contentEncryption, and signatureAlgorithms parameters contain the allowable
// algorithms. They must be non-empty. Non-matching algorithms cause a parse error.
func ParseSignedAndEncrypted(s string,
encryptionKeyAlgorithms []jose.KeyAlgorithm,
contentEncryption []jose.ContentEncryption,
+43 -37
View File
@@ -18,6 +18,7 @@ package jose
import (
"crypto/elliptic"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"errors"
@@ -210,13 +211,20 @@ 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 or the chain could
// 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
// 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()
@@ -297,9 +305,10 @@ func (parsed rawHeader) getEPK() (*JSONWebKey, error) {
if v == nil {
return nil, nil
}
var epk *JSONWebKey
err := json.Unmarshal(*v, &epk)
if err != 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 {
return nil, err
}
return epk, nil
@@ -325,20 +334,6 @@ 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) {
@@ -424,10 +419,14 @@ func (parsed rawHeader) sanitized() (h Header, err error) {
}
switch k {
case headerJWK:
var jwk *JSONWebKey
err = json.Unmarshal(*v, &jwk)
// 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)
if err != nil {
err = fmt.Errorf("failed to unmarshal JWK: %v: %#v", err, string(*v))
err = fmt.Errorf("failed to unmarshal JWK: %w", err)
return
}
h.JSONWebKey = jwk
@@ -499,22 +498,8 @@ func parseCertificateChain(chain []string) ([]*x509.Certificate, error) {
}
func (parsed rawHeader) isSet(k HeaderKey) bool {
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
_, ok := parsed[k]
return ok
}
// Merge headers from src into dst, giving precedence to headers from l.
@@ -564,3 +549,24 @@ 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
}
+4 -1
View File
@@ -321,7 +321,10 @@ func (ctx *genericSigner) Sign(payload []byte) (*JSONWebSignature, error) {
protected[k] = v
}
serializedProtected := mustSerializeJSON(protected)
serializedProtected, err := json.Marshal(protected)
if err != nil {
return nil, fmt.Errorf("go-jose/go-jose: Error marshaling JSON: %s", err)
}
needsBase64 := true
if b64, ok := protected[headerB64]; ok {

Some files were not shown because too many files have changed in this diff Show More