Compare commits

...

12 Commits

Author SHA1 Message Date
Miloslav Trmač
267465e170 [release-1.22] Bump Skopeo to 1.22.2
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2026-04-14 18:21:34 +02:00
Miloslav Trmač
fefb99717f Merge pull request #2847 from wking/proxy-validate-manifest-too
OCPBUGS-81187: proxy: Verify *either* toplevel or target
2026-04-14 18:16:49 +02:00
Colin Walters
f195baca1c proxy: Verify *either* toplevel or target
(Only compile tested locally)

An issue was raised in that a current Red Hat internal build system
was performing a signature just on the per-architecture manifest,
but the current proxy code is expecting a signature on the manifest
list.

To quote Miloslav from that bug:

> Podman signs both the per-platform items and the top level,
> and enforces signatures only on per-platform items. cosign,
> by default, signs only the top level (and has an option to
> sign everything), I’m not sure which one it enforces.
> I don’t immediately recall other platforms.

We believe the current proxy code is secure since
we always require signatures (if configured) on the manifest
list, and the manifest list covers the individual manifests
via sha256 digest.

However, we want to support signatures only being present
on the per-arch manifest too in order to be flexible.

Yet, we can't hard switch to requiring signatures on the
per-arch manifests as that would immediately break anyone
relying on the current behavior of validating the toplevel.

Change the logic here to:

- Verify signature on the manifest list, and cache the error (if any)
- Fetch the manifest
- Verify signature on the manifest
- Allow if *either* signature was accepted; conversely, only error
  if signature validation failed on *both* the manifest list and
  manifest

This also switches things to cache the manifest upfront instead
of doing it lazily on `GetManifest/GetConfig`; in practice
callers were always immediately requesting those anyways.
The use case of just fetching blobs exists (e.g. to resume
an interrupted fetch), but is relatively obscure and
in general I think it's good to re-verify signatures on
each operation.

Signed-off-by: Colin Walters <walters@verbum.org>
Signed-off-by: W. Trevor King <wking@tremily.us>
2026-04-13 09:46:04 -07:00
Colin Walters
81e67ab5cb proxy: Move policycontext into global state
I am not aware of a reason not to just cache this for the life
of the proxy, like we do other global state.

Prep for further changes.

Signed-off-by: Colin Walters <walters@verbum.org>
Signed-off-by: W. Trevor King <wking@tremily.us>
2026-04-13 09:46:04 -07:00
Lokesh Mandvekar
8fd0e2e6ca Merge pull request #2845 from lsm5/backport-packit-post-modifications
[release-1.22] Packit: fix downstream post-modifications action
2026-04-10 14:00:38 -04:00
Lokesh Mandvekar
3bb7f313fe Packit: fix downstream post-modifications action
The downstream TMT plan can use a ref value without double quotes[0], so
the `post-modifications` action in packit config can be simplified as in
this patch. Also, switch the single and double quote usage to be
consistent with the usage in `get-current-version` packit action.

This should help to avoid variable substitution issues noticed in the
previous release [1].

Refs:
[0]: https://src.fedoraproject.org/rpms/skopeo/pull-request/98
[1]: fd38aa8a5e/f/plans/main.fmf

Signed-off-by: Lokesh Mandvekar <lsm5@redhat.com>
(cherry picked from commit 1ea0fb4baf)
2026-04-09 16:02:30 -04:00
Miloslav Trmač
e7d174ba44 Merge pull request #2842 from TomSweeneyRedHat/dev/tsweeney/skopeo-1.22.1
Bump Skopeo to v1.22.1, CVE-2026-34986, c/common v067.1, c/image v5.39.2
2026-04-09 16:13:40 +02:00
Tom Sweeney
ecdbb551ec [release-1.22] Bump Skopeo to v1.22.1
Bump Skopeo to v1.22.1 to go out with Podman v5.8.2

Signed-off-by: Tom Sweeney <tsweeney@redhat.com>
2026-04-08 18:02:32 -04:00
Tom Sweeney
b0b024aa09 [release-1.20] CVE-2026-34986 gojose v4.1.4
Bump github.com/go-jose/go-jose/v4 v4.1.4 to cure CVE-24986
Fixes: https://redhat.atlassian.net/browse/RHEL-165013, https://redhat.atlassian.net/browse/RHEL-165013

Signed-off-by: Tom Sweeney <tsweeney@redhat.com>
2026-04-08 17:57:14 -04:00
Tom Sweeney
0bf3b382a3 [release-1.22] Bump google.golang.org/grpc to v1.79.3
Just to be ultra safe, lets bump grpc to v1.79.3 to
address CVE-2026-33186 which does not appear to be an
issue for Skopeo.

Signed-off-by: Tom Sweeney <tsweeney@redhat.com>
2026-04-08 17:10:43 -04:00
Tom Sweeney
e5890ebb4f [release-1.22] Bump c/common to v0.67.1, c/image v5.39.2
Signed-off-by: Tom Sweeney <tsweeney@redhat.com>
2026-04-08 16:51:55 -04:00
Miloslav Trmač
fd3ba47e00 Merge pull request #2800 from TomSweeneyRedHat/dev/tsweeney/skopeo-v1.22.0-1
[release-1.22] Skopeo v1.22.0
2026-02-11 18:33:16 +01:00
214 changed files with 23162 additions and 9202 deletions

View File

@@ -121,7 +121,7 @@ jobs:
- fedora-all
actions:
post-modifications: >-
bash -c "sed -i 's/^\(\s*\)ref: .*/\1ref: \"v${PACKIT_PROJECT_VERSION}\"/' ${PACKIT_DOWNSTREAM_REPO}/plans/main.fmf"
bash -c 'sed -i "s/^\(\s*\)ref: .*/\1ref: v${PACKIT_PROJECT_VERSION}/" ${PACKIT_DOWNSTREAM_REPO}/plans/main.fmf'
# Sync to CentOS Stream
# FIXME: Switch trigger whenever we're ready to update CentOS Stream via

View File

@@ -28,6 +28,7 @@ import (
"go.podman.io/image/v5/image"
"go.podman.io/image/v5/manifest"
"go.podman.io/image/v5/pkg/blobinfocache"
"go.podman.io/image/v5/signature"
"go.podman.io/image/v5/transports"
"go.podman.io/image/v5/transports/alltransports"
"go.podman.io/image/v5/types"
@@ -119,9 +120,9 @@ type activePipe struct {
// openImage is an opened image reference
type openImage struct {
// id is an opaque integer handle
id uint64
src types.ImageSource
cachedimg types.Image
id uint64
src types.ImageSource
img types.Image
}
// proxyHandler is the state associated with our socket.
@@ -129,9 +130,10 @@ type proxyHandler struct {
// lock protects everything else in this structure.
lock sync.Mutex
// opts is CLI options
opts *proxyOptions
sysctx *types.SystemContext
cache types.BlobInfoCache
opts *proxyOptions
sysctx *types.SystemContext
policyctx *signature.PolicyContext
cache types.BlobInfoCache
// imageSerial is a counter for open images
imageSerial uint64
@@ -188,6 +190,11 @@ func (h *proxyHandler) Initialize(args []any) (replyBuf, error) {
return ret, fmt.Errorf("already initialized")
}
policyContext, err := h.opts.global.getPolicyContext()
if err != nil {
return ret, err
}
sysctx, err := h.opts.imageOpts.newSystemContext()
if err != nil {
return ret, err
@@ -195,6 +202,8 @@ func (h *proxyHandler) Initialize(args []any) (replyBuf, error) {
h.sysctx = sysctx
h.cache = blobinfocache.DefaultCache(sysctx)
h.policyctx = policyContext
r := replyBuf{
value: protocolVersion,
}
@@ -208,6 +217,7 @@ func (h *proxyHandler) OpenImage(args []any) (replyBuf, error) {
}
func (h *proxyHandler) openImageImpl(args []any, allowNotFound bool) (retReplyBuf replyBuf, retErr error) {
ctx := context.Background()
h.lock.Lock()
defer h.lock.Unlock()
var ret replyBuf
@@ -236,23 +246,54 @@ func (h *proxyHandler) openImageImpl(args []any, allowNotFound bool) (retReplyBu
return ret, err
}
policyContext, err := h.opts.global.getPolicyContext()
if err != nil {
return ret, err
}
defer func() {
if err := policyContext.Destroy(); err != nil {
retErr = noteCloseFailure(retErr, "tearing down policy context", err)
}
}()
unparsedTopLevel := image.UnparsedInstance(imgsrc, nil)
allowed, err := policyContext.IsRunningImageAllowed(context.Background(), unparsedTopLevel)
// Check the signature on the toplevel (possibly multi-arch) manifest, but we don't
// yet propagate the error here.
allowed, toplevelVerificationErr := h.policyctx.IsRunningImageAllowed(context.Background(), unparsedTopLevel)
if toplevelVerificationErr == nil && !allowed {
return ret, fmt.Errorf("internal inconsistency: policy verification failed without returning an error")
}
mfest, manifestType, err := unparsedTopLevel.Manifest(ctx)
if err != nil {
return ret, err
}
if !allowed {
return ret, fmt.Errorf("internal inconsistency: policy verification failed without returning an error")
var target *image.UnparsedImage
if manifest.MIMETypeIsMultiImage(manifestType) {
manifestList, err := manifest.ListFromBlob(mfest, manifestType)
if err != nil {
return ret, err
}
instanceDigest, err := manifestList.ChooseInstance(h.sysctx)
if err != nil {
return ret, err
}
target = image.UnparsedInstance(imgsrc, &instanceDigest)
allowed, targetVerificationErr := h.policyctx.IsRunningImageAllowed(context.Background(), target)
if targetVerificationErr == nil && !allowed {
return ret, fmt.Errorf("internal inconsistency: policy verification failed without returning an error")
}
// Now, we only error if *both* the toplevel and target verification failed.
// If either succeeded, that's OK. We want to support a case where the manifest
// list is signed, but the target is not (because we previously supported that behavior),
// and we want to support the case where only the target is signed (consistent with what c/image enforces).
if targetVerificationErr != nil && toplevelVerificationErr != nil {
return ret, targetVerificationErr
}
} else {
target = unparsedTopLevel
// We're not using a manifest list, so require verification of the single arch manifest.
if toplevelVerificationErr != nil {
return ret, toplevelVerificationErr
}
}
img, err := image.FromUnparsedImage(ctx, h.sysctx, target)
if err != nil {
return ret, err
}
// Note that we never return zero as an imageid; this code doesn't yet
@@ -261,6 +302,7 @@ func (h *proxyHandler) openImageImpl(args []any, allowNotFound bool) (retReplyBu
openimg := &openImage{
id: h.imageSerial,
src: imgsrc,
img: img,
}
h.images[openimg.id] = openimg
ret.value = openimg.id
@@ -360,44 +402,6 @@ func (h *proxyHandler) returnBytes(retval any, buf []byte) (replyBuf, error) {
return ret, nil
}
// cacheTargetManifest is invoked when GetManifest or GetConfig is invoked
// the first time for a given image. If the requested image is a manifest
// list, this function resolves it to the image matching the calling process'
// operating system and architecture.
//
// TODO: Add GetRawManifest or so that exposes manifest lists
func (h *proxyHandler) cacheTargetManifest(img *openImage) error {
ctx := context.Background()
if img.cachedimg != nil {
return nil
}
unparsedToplevel := image.UnparsedInstance(img.src, nil)
mfest, manifestType, err := unparsedToplevel.Manifest(ctx)
if err != nil {
return err
}
var target *image.UnparsedImage
if manifest.MIMETypeIsMultiImage(manifestType) {
manifestList, err := manifest.ListFromBlob(mfest, manifestType)
if err != nil {
return err
}
instanceDigest, err := manifestList.ChooseInstance(h.sysctx)
if err != nil {
return err
}
target = image.UnparsedInstance(img.src, &instanceDigest)
} else {
target = unparsedToplevel
}
cachedimg, err := image.FromUnparsedImage(ctx, h.sysctx, target)
if err != nil {
return err
}
img.cachedimg = cachedimg
return nil
}
// GetManifest returns a copy of the manifest, converted to OCI format, along with the original digest.
// Manifest lists are resolved to the current operating system and architecture.
func (h *proxyHandler) GetManifest(args []any) (replyBuf, error) {
@@ -417,14 +421,8 @@ func (h *proxyHandler) GetManifest(args []any) (replyBuf, error) {
return ret, err
}
err = h.cacheTargetManifest(imgref)
if err != nil {
return ret, err
}
img := imgref.cachedimg
ctx := context.Background()
rawManifest, manifestType, err := img.Manifest(ctx)
rawManifest, manifestType, err := imgref.img.Manifest(ctx)
if err != nil {
return ret, err
}
@@ -453,7 +451,7 @@ func (h *proxyHandler) GetManifest(args []any) (replyBuf, error) {
// docker schema and MIME types.
if manifestType != imgspecv1.MediaTypeImageManifest {
manifestUpdates := types.ManifestUpdateOptions{ManifestMIMEType: imgspecv1.MediaTypeImageManifest}
ociImage, err := img.UpdatedImage(ctx, manifestUpdates)
ociImage, err := imgref.img.UpdatedImage(ctx, manifestUpdates)
if err != nil {
return ret, err
}
@@ -487,14 +485,9 @@ func (h *proxyHandler) GetFullConfig(args []any) (replyBuf, error) {
if err != nil {
return ret, err
}
err = h.cacheTargetManifest(imgref)
if err != nil {
return ret, err
}
img := imgref.cachedimg
ctx := context.TODO()
config, err := img.OCIConfig(ctx)
config, err := imgref.img.OCIConfig(ctx)
if err != nil {
return ret, err
}
@@ -524,14 +517,9 @@ func (h *proxyHandler) GetConfig(args []any) (replyBuf, error) {
if err != nil {
return ret, err
}
err = h.cacheTargetManifest(imgref)
if err != nil {
return ret, err
}
img := imgref.cachedimg
ctx := context.TODO()
config, err := img.OCIConfig(ctx)
config, err := imgref.img.OCIConfig(ctx)
if err != nil {
return ret, err
}
@@ -720,19 +708,13 @@ func (h *proxyHandler) GetLayerInfo(args []any) (replyBuf, error) {
ctx := context.TODO()
err = h.cacheTargetManifest(imgref)
if err != nil {
return ret, err
}
img := imgref.cachedimg
layerInfos, err := img.LayerInfosForCopy(ctx)
layerInfos, err := imgref.img.LayerInfosForCopy(ctx)
if err != nil {
return ret, err
}
if layerInfos == nil {
layerInfos = img.LayerInfos()
layerInfos = imgref.img.LayerInfos()
}
layers := make([]convertedLayerInfo, 0, len(layerInfos))
@@ -769,20 +751,13 @@ func (h *proxyHandler) GetLayerInfoPiped(args []any) (replyBuf, error) {
}
ctx := context.TODO()
err = h.cacheTargetManifest(imgref)
if err != nil {
return ret, err
}
img := imgref.cachedimg
layerInfos, err := img.LayerInfosForCopy(ctx)
layerInfos, err := imgref.img.LayerInfosForCopy(ctx)
if err != nil {
return ret, err
}
if layerInfos == nil {
layerInfos = img.LayerInfos()
layerInfos = imgref.img.LayerInfos()
}
layers := make([]convertedLayerInfo, 0, len(layerInfos))
@@ -832,7 +807,13 @@ func (h *proxyHandler) close() {
err := image.src.Close()
if err != nil {
// This shouldn't be fatal
logrus.Warnf("Failed to close image %s: %v", transports.ImageName(image.cachedimg.Reference()), err)
logrus.Warnf("Failed to close image %s: %v", transports.ImageName(image.img.Reference()), err)
}
}
if h.policyctx != nil {
if err := h.policyctx.Destroy(); err != nil {
logrus.Warnf("tearing down policy context: %v", err)
}
}
}

37
go.mod
View File

@@ -17,10 +17,10 @@ require (
github.com/spf13/cobra v1.10.1
github.com/spf13/pflag v1.0.10
github.com/stretchr/testify v1.11.1
go.podman.io/common v0.67.0
go.podman.io/image/v5 v5.39.1
go.podman.io/common v0.67.1
go.podman.io/image/v5 v5.39.2
go.podman.io/storage v1.62.0
golang.org/x/term v0.36.0
golang.org/x/term v0.38.0
gopkg.in/yaml.v3 v3.0.1
)
@@ -30,6 +30,7 @@ require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/VividCortex/ewma v1.2.0 // indirect
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.17.0 // indirect
@@ -45,7 +46,7 @@ require (
github.com/docker/go-units v0.5.0 // indirect
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/go-jose/go-jose/v4 v4.1.4 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
@@ -92,19 +93,19 @@ require (
github.com/ulikunitz/xz v0.5.15 // indirect
github.com/vbatts/tar-split v0.12.1 // indirect
github.com/vbauerster/mpb/v8 v8.10.2 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.36.0 // indirect
go.opentelemetry.io/otel/metric v1.36.0 // indirect
go.opentelemetry.io/otel/trace v1.36.0 // indirect
golang.org/x/crypto v0.43.0 // indirect
golang.org/x/net v0.45.0 // indirect
golang.org/x/oauth2 v0.32.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.37.0 // indirect
golang.org/x/text v0.30.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e // indirect
google.golang.org/grpc v1.72.2 // indirect
google.golang.org/protobuf v1.36.9 // indirect
go.opentelemetry.io/otel v1.39.0 // indirect
go.opentelemetry.io/otel/metric v1.39.0 // indirect
go.opentelemetry.io/otel/trace v1.39.0 // indirect
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/oauth2 v0.34.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.32.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/grpc v1.79.3 // indirect
google.golang.org/protobuf v1.36.10 // indirect
)

94
go.sum
View File

@@ -66,8 +66,8 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA=
github.com/go-jose/go-jose/v4 v4.1.4/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.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -194,8 +194,8 @@ github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoG
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
@@ -256,30 +256,30 @@ github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3R
github.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU=
github.com/ysmood/leakless v0.9.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
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.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.podman.io/common v0.67.0 h1:6Ci5oU1ek08OAxBLkHEqSyWmjNh5zf03PRqZ04cPdwU=
go.podman.io/common v0.67.0/go.mod h1:sB9L8LMtmf5Hpek2qkEyRrcSzpb+gYpG3vq5Khima3U=
go.podman.io/image/v5 v5.39.1 h1:loIw4qHzZzBlUguYZau40u8HbR5MrTPQhwT4Hy6sCm0=
go.podman.io/image/v5 v5.39.1/go.mod h1:SlaR6Pra1ATIx4BcuZ16oafb3QcCHISaKcJbtlN/G/0=
go.podman.io/common v0.67.1 h1:HddYLJfkfFUmFJ0V3PVoewguFM9eHkqk0g+fOc2B9R4=
go.podman.io/common v0.67.1/go.mod h1:XVmSLtnhJwGb+ImYn6BXiozxVE3mYZJgiiBuDOiOquk=
go.podman.io/image/v5 v5.39.2 h1:EJua/pRtvgLV/a5y8/RvA+ekKukZh0UuKMvLdTmEWFk=
go.podman.io/image/v5 v5.39.2/go.mod h1:SlaR6Pra1ATIx4BcuZ16oafb3QcCHISaKcJbtlN/G/0=
go.podman.io/storage v1.62.0 h1:0QjX1XlzVmbiaulb+aR/CG6p9+pzaqwIeZPe3tEjHbY=
go.podman.io/storage v1.62.0/go.mod h1:A3UBK0XypjNZ6pghRhuxg62+2NIm5lcUGv/7XyMhMUI=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
@@ -292,15 +292,15 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -309,10 +309,10 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -320,8 +320,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -334,8 +334,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -345,8 +345,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
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.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
@@ -356,8 +356,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -366,18 +366,20 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e h1:UdXH7Kzbj+Vzastr5nVfccbmFsmYNygVLSPk1pEfDoY=
google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e/go.mod h1:085qFyf2+XaZlRdCgKNCIZ3afY2p4HHZdoIRpId8F4A=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e h1:ztQaXfzEXTmCBvbtWYRhJxW+0iJcz2qXfd38/e9l7bA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8=
google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls=
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View File

@@ -22,8 +22,9 @@ import (
"go.podman.io/image/v5/manifest"
)
// This image is known to be x86_64 only right now
const knownNotManifestListedImageX8664 = "docker://quay.io/coreos/11bot"
// This image is known to be x86_64 only right now; TODO push
// a non-manifest-listed fixture to quay.io/libpod
const knownNotManifestListedImageX8664 = "docker://quay.io/cgwalters/ostest"
// knownNotExtantImage would be very surprising if it did exist
const knownNotExtantImage = "docker://quay.io/centos/centos:opensusewindowsubuntu"
@@ -266,7 +267,12 @@ func (p *proxy) callGetRawBlob(args []any) (rval any, buf []byte, err error) {
return
}
func newProxy() (*proxy, error) {
type proxyConfig struct {
// policyFilePath is equivalent to skopeo --policy, an empty value is treated as unset
policyFilePath string
}
func newProxy(config proxyConfig) (*proxy, error) {
fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_SEQPACKET, 0)
if err != nil {
return nil, err
@@ -282,7 +288,12 @@ func newProxy() (*proxy, error) {
}
// Note ExtraFiles starts at 3
proc := exec.Command(skopeoBinary, "experimental-image-proxy", "--sockfd", "3")
args := []string{}
if config.policyFilePath != "" {
args = append(args, "--policy", config.policyFilePath)
}
args = append(args, "experimental-image-proxy", "--sockfd", "3")
proc := exec.Command(skopeoBinary, args...)
proc.Stderr = os.Stderr
cmdLifecycleToParentIfPossible(proc)
proc.ExtraFiles = append(proc.ExtraFiles, theirfd)
@@ -480,7 +491,10 @@ func runTestGetBlob(p *proxy, img string) error {
func (s *proxySuite) TestProxyMetadata() {
t := s.T()
p, err := newProxy()
config := proxyConfig{
policyFilePath: "",
}
p, err := newProxy(config)
require.NoError(t, err)
err = runTestMetadataAPIs(p, knownNotManifestListedImageX8664)
@@ -504,7 +518,7 @@ func (s *proxySuite) TestProxyMetadata() {
func (s *proxySuite) TestProxyGetBlob() {
t := s.T()
p, err := newProxy()
p, err := newProxy(proxyConfig{})
require.NoError(t, err)
err = runTestGetBlob(p, knownListImage)
@@ -513,3 +527,30 @@ func (s *proxySuite) TestProxyGetBlob() {
}
assert.NoError(t, err)
}
// Verify that a policy that denies all images is correctly rejected
// for both manifest listed and direct per-arch images.
func (s *proxySuite) TestProxyPolicyRejectAll() {
t := s.T()
tempd := t.TempDir()
config := proxyConfig{
policyFilePath: tempd + "/policy.json",
}
err := os.WriteFile(config.policyFilePath, []byte("{ \"default\": [ { \"type\":\"reject\"} ] }"), 0o644)
require.NoError(t, err)
p, err := newProxy(config)
require.NoError(t, err)
err = runTestMetadataAPIs(p, knownNotManifestListedImageX8664)
assert.ErrorContains(t, err, "is rejected by policy")
err = runTestMetadataAPIs(p, knownListImage)
assert.ErrorContains(t, err, "is rejected by policy")
// This one should continue to be fine.
err = runTestOpenImageOptionalNotFound(p, knownNotExtantImage)
if err != nil {
err = fmt.Errorf("Testing optional image %s: %v", knownNotExtantImage, err)
}
assert.NoError(t, err)
}

22
vendor/github.com/cespare/xxhash/v2/LICENSE.txt generated vendored Normal file
View File

@@ -0,0 +1,22 @@
Copyright (c) 2016 Caleb Spare
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

74
vendor/github.com/cespare/xxhash/v2/README.md generated vendored Normal file
View File

@@ -0,0 +1,74 @@
# xxhash
[![Go Reference](https://pkg.go.dev/badge/github.com/cespare/xxhash/v2.svg)](https://pkg.go.dev/github.com/cespare/xxhash/v2)
[![Test](https://github.com/cespare/xxhash/actions/workflows/test.yml/badge.svg)](https://github.com/cespare/xxhash/actions/workflows/test.yml)
xxhash is a Go implementation of the 64-bit [xxHash] algorithm, XXH64. This is a
high-quality hashing algorithm that is much faster than anything in the Go
standard library.
This package provides a straightforward API:
```
func Sum64(b []byte) uint64
func Sum64String(s string) uint64
type Digest struct{ ... }
func New() *Digest
```
The `Digest` type implements hash.Hash64. Its key methods are:
```
func (*Digest) Write([]byte) (int, error)
func (*Digest) WriteString(string) (int, error)
func (*Digest) Sum64() uint64
```
The package is written with optimized pure Go and also contains even faster
assembly implementations for amd64 and arm64. If desired, the `purego` build tag
opts into using the Go code even on those architectures.
[xxHash]: http://cyan4973.github.io/xxHash/
## Compatibility
This package is in a module and the latest code is in version 2 of the module.
You need a version of Go with at least "minimal module compatibility" to use
github.com/cespare/xxhash/v2:
* 1.9.7+ for Go 1.9
* 1.10.3+ for Go 1.10
* Go 1.11 or later
I recommend using the latest release of Go.
## Benchmarks
Here are some quick benchmarks comparing the pure-Go and assembly
implementations of Sum64.
| input size | purego | asm |
| ---------- | --------- | --------- |
| 4 B | 1.3 GB/s | 1.2 GB/s |
| 16 B | 2.9 GB/s | 3.5 GB/s |
| 100 B | 6.9 GB/s | 8.1 GB/s |
| 4 KB | 11.7 GB/s | 16.7 GB/s |
| 10 MB | 12.0 GB/s | 17.3 GB/s |
These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C
CPU using the following commands under Go 1.19.2:
```
benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$')
benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')
```
## Projects using this package
- [InfluxDB](https://github.com/influxdata/influxdb)
- [Prometheus](https://github.com/prometheus/prometheus)
- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
- [FreeCache](https://github.com/coocood/freecache)
- [FastCache](https://github.com/VictoriaMetrics/fastcache)
- [Ristretto](https://github.com/dgraph-io/ristretto)
- [Badger](https://github.com/dgraph-io/badger)

10
vendor/github.com/cespare/xxhash/v2/testall.sh generated vendored Normal file
View File

@@ -0,0 +1,10 @@
#!/bin/bash
set -eu -o pipefail
# Small convenience script for running the tests with various combinations of
# arch/tags. This assumes we're running on amd64 and have qemu available.
go test ./...
go test -tags purego ./...
GOARCH=arm64 go test
GOARCH=arm64 go test -tags purego

243
vendor/github.com/cespare/xxhash/v2/xxhash.go generated vendored Normal file
View File

@@ -0,0 +1,243 @@
// Package xxhash implements the 64-bit variant of xxHash (XXH64) as described
// at http://cyan4973.github.io/xxHash/.
package xxhash
import (
"encoding/binary"
"errors"
"math/bits"
)
const (
prime1 uint64 = 11400714785074694791
prime2 uint64 = 14029467366897019727
prime3 uint64 = 1609587929392839161
prime4 uint64 = 9650029242287828579
prime5 uint64 = 2870177450012600261
)
// Store the primes in an array as well.
//
// The consts are used when possible in Go code to avoid MOVs but we need a
// contiguous array for the assembly code.
var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5}
// Digest implements hash.Hash64.
//
// Note that a zero-valued Digest is not ready to receive writes.
// Call Reset or create a Digest using New before calling other methods.
type Digest struct {
v1 uint64
v2 uint64
v3 uint64
v4 uint64
total uint64
mem [32]byte
n int // how much of mem is used
}
// New creates a new Digest with a zero seed.
func New() *Digest {
return NewWithSeed(0)
}
// NewWithSeed creates a new Digest with the given seed.
func NewWithSeed(seed uint64) *Digest {
var d Digest
d.ResetWithSeed(seed)
return &d
}
// Reset clears the Digest's state so that it can be reused.
// It uses a seed value of zero.
func (d *Digest) Reset() {
d.ResetWithSeed(0)
}
// ResetWithSeed clears the Digest's state so that it can be reused.
// It uses the given seed to initialize the state.
func (d *Digest) ResetWithSeed(seed uint64) {
d.v1 = seed + prime1 + prime2
d.v2 = seed + prime2
d.v3 = seed
d.v4 = seed - prime1
d.total = 0
d.n = 0
}
// Size always returns 8 bytes.
func (d *Digest) Size() int { return 8 }
// BlockSize always returns 32 bytes.
func (d *Digest) BlockSize() int { return 32 }
// Write adds more data to d. It always returns len(b), nil.
func (d *Digest) Write(b []byte) (n int, err error) {
n = len(b)
d.total += uint64(n)
memleft := d.mem[d.n&(len(d.mem)-1):]
if d.n+n < 32 {
// This new data doesn't even fill the current block.
copy(memleft, b)
d.n += n
return
}
if d.n > 0 {
// Finish off the partial block.
c := copy(memleft, b)
d.v1 = round(d.v1, u64(d.mem[0:8]))
d.v2 = round(d.v2, u64(d.mem[8:16]))
d.v3 = round(d.v3, u64(d.mem[16:24]))
d.v4 = round(d.v4, u64(d.mem[24:32]))
b = b[c:]
d.n = 0
}
if len(b) >= 32 {
// One or more full blocks left.
nw := writeBlocks(d, b)
b = b[nw:]
}
// Store any remaining partial block.
copy(d.mem[:], b)
d.n = len(b)
return
}
// Sum appends the current hash to b and returns the resulting slice.
func (d *Digest) Sum(b []byte) []byte {
s := d.Sum64()
return append(
b,
byte(s>>56),
byte(s>>48),
byte(s>>40),
byte(s>>32),
byte(s>>24),
byte(s>>16),
byte(s>>8),
byte(s),
)
}
// Sum64 returns the current hash.
func (d *Digest) Sum64() uint64 {
var h uint64
if d.total >= 32 {
v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4
h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)
h = mergeRound(h, v1)
h = mergeRound(h, v2)
h = mergeRound(h, v3)
h = mergeRound(h, v4)
} else {
h = d.v3 + prime5
}
h += d.total
b := d.mem[:d.n&(len(d.mem)-1)]
for ; len(b) >= 8; b = b[8:] {
k1 := round(0, u64(b[:8]))
h ^= k1
h = rol27(h)*prime1 + prime4
}
if len(b) >= 4 {
h ^= uint64(u32(b[:4])) * prime1
h = rol23(h)*prime2 + prime3
b = b[4:]
}
for ; len(b) > 0; b = b[1:] {
h ^= uint64(b[0]) * prime5
h = rol11(h) * prime1
}
h ^= h >> 33
h *= prime2
h ^= h >> 29
h *= prime3
h ^= h >> 32
return h
}
const (
magic = "xxh\x06"
marshaledSize = len(magic) + 8*5 + 32
)
// MarshalBinary implements the encoding.BinaryMarshaler interface.
func (d *Digest) MarshalBinary() ([]byte, error) {
b := make([]byte, 0, marshaledSize)
b = append(b, magic...)
b = appendUint64(b, d.v1)
b = appendUint64(b, d.v2)
b = appendUint64(b, d.v3)
b = appendUint64(b, d.v4)
b = appendUint64(b, d.total)
b = append(b, d.mem[:d.n]...)
b = b[:len(b)+len(d.mem)-d.n]
return b, nil
}
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
func (d *Digest) UnmarshalBinary(b []byte) error {
if len(b) < len(magic) || string(b[:len(magic)]) != magic {
return errors.New("xxhash: invalid hash state identifier")
}
if len(b) != marshaledSize {
return errors.New("xxhash: invalid hash state size")
}
b = b[len(magic):]
b, d.v1 = consumeUint64(b)
b, d.v2 = consumeUint64(b)
b, d.v3 = consumeUint64(b)
b, d.v4 = consumeUint64(b)
b, d.total = consumeUint64(b)
copy(d.mem[:], b)
d.n = int(d.total % uint64(len(d.mem)))
return nil
}
func appendUint64(b []byte, x uint64) []byte {
var a [8]byte
binary.LittleEndian.PutUint64(a[:], x)
return append(b, a[:]...)
}
func consumeUint64(b []byte) ([]byte, uint64) {
x := u64(b)
return b[8:], x
}
func u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) }
func u32(b []byte) uint32 { return binary.LittleEndian.Uint32(b) }
func round(acc, input uint64) uint64 {
acc += input * prime2
acc = rol31(acc)
acc *= prime1
return acc
}
func mergeRound(acc, val uint64) uint64 {
val = round(0, val)
acc ^= val
acc = acc*prime1 + prime4
return acc
}
func rol1(x uint64) uint64 { return bits.RotateLeft64(x, 1) }
func rol7(x uint64) uint64 { return bits.RotateLeft64(x, 7) }
func rol11(x uint64) uint64 { return bits.RotateLeft64(x, 11) }
func rol12(x uint64) uint64 { return bits.RotateLeft64(x, 12) }
func rol18(x uint64) uint64 { return bits.RotateLeft64(x, 18) }
func rol23(x uint64) uint64 { return bits.RotateLeft64(x, 23) }
func rol27(x uint64) uint64 { return bits.RotateLeft64(x, 27) }
func rol31(x uint64) uint64 { return bits.RotateLeft64(x, 31) }

209
vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s generated vendored Normal file
View File

@@ -0,0 +1,209 @@
//go:build !appengine && gc && !purego
// +build !appengine
// +build gc
// +build !purego
#include "textflag.h"
// Registers:
#define h AX
#define d AX
#define p SI // pointer to advance through b
#define n DX
#define end BX // loop end
#define v1 R8
#define v2 R9
#define v3 R10
#define v4 R11
#define x R12
#define prime1 R13
#define prime2 R14
#define prime4 DI
#define round(acc, x) \
IMULQ prime2, x \
ADDQ x, acc \
ROLQ $31, acc \
IMULQ prime1, acc
// round0 performs the operation x = round(0, x).
#define round0(x) \
IMULQ prime2, x \
ROLQ $31, x \
IMULQ prime1, x
// mergeRound applies a merge round on the two registers acc and x.
// It assumes that prime1, prime2, and prime4 have been loaded.
#define mergeRound(acc, x) \
round0(x) \
XORQ x, acc \
IMULQ prime1, acc \
ADDQ prime4, acc
// blockLoop processes as many 32-byte blocks as possible,
// updating v1, v2, v3, and v4. It assumes that there is at least one block
// to process.
#define blockLoop() \
loop: \
MOVQ +0(p), x \
round(v1, x) \
MOVQ +8(p), x \
round(v2, x) \
MOVQ +16(p), x \
round(v3, x) \
MOVQ +24(p), x \
round(v4, x) \
ADDQ $32, p \
CMPQ p, end \
JLE loop
// func Sum64(b []byte) uint64
TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
// Load fixed primes.
MOVQ ·primes+0(SB), prime1
MOVQ ·primes+8(SB), prime2
MOVQ ·primes+24(SB), prime4
// Load slice.
MOVQ b_base+0(FP), p
MOVQ b_len+8(FP), n
LEAQ (p)(n*1), end
// The first loop limit will be len(b)-32.
SUBQ $32, end
// Check whether we have at least one block.
CMPQ n, $32
JLT noBlocks
// Set up initial state (v1, v2, v3, v4).
MOVQ prime1, v1
ADDQ prime2, v1
MOVQ prime2, v2
XORQ v3, v3
XORQ v4, v4
SUBQ prime1, v4
blockLoop()
MOVQ v1, h
ROLQ $1, h
MOVQ v2, x
ROLQ $7, x
ADDQ x, h
MOVQ v3, x
ROLQ $12, x
ADDQ x, h
MOVQ v4, x
ROLQ $18, x
ADDQ x, h
mergeRound(h, v1)
mergeRound(h, v2)
mergeRound(h, v3)
mergeRound(h, v4)
JMP afterBlocks
noBlocks:
MOVQ ·primes+32(SB), h
afterBlocks:
ADDQ n, h
ADDQ $24, end
CMPQ p, end
JG try4
loop8:
MOVQ (p), x
ADDQ $8, p
round0(x)
XORQ x, h
ROLQ $27, h
IMULQ prime1, h
ADDQ prime4, h
CMPQ p, end
JLE loop8
try4:
ADDQ $4, end
CMPQ p, end
JG try1
MOVL (p), x
ADDQ $4, p
IMULQ prime1, x
XORQ x, h
ROLQ $23, h
IMULQ prime2, h
ADDQ ·primes+16(SB), h
try1:
ADDQ $4, end
CMPQ p, end
JGE finalize
loop1:
MOVBQZX (p), x
ADDQ $1, p
IMULQ ·primes+32(SB), x
XORQ x, h
ROLQ $11, h
IMULQ prime1, h
CMPQ p, end
JL loop1
finalize:
MOVQ h, x
SHRQ $33, x
XORQ x, h
IMULQ prime2, h
MOVQ h, x
SHRQ $29, x
XORQ x, h
IMULQ ·primes+16(SB), h
MOVQ h, x
SHRQ $32, x
XORQ x, h
MOVQ h, ret+24(FP)
RET
// func writeBlocks(d *Digest, b []byte) int
TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
// Load fixed primes needed for round.
MOVQ ·primes+0(SB), prime1
MOVQ ·primes+8(SB), prime2
// Load slice.
MOVQ b_base+8(FP), p
MOVQ b_len+16(FP), n
LEAQ (p)(n*1), end
SUBQ $32, end
// Load vN from d.
MOVQ s+0(FP), d
MOVQ 0(d), v1
MOVQ 8(d), v2
MOVQ 16(d), v3
MOVQ 24(d), v4
// We don't need to check the loop condition here; this function is
// always called with at least one block of data to process.
blockLoop()
// Copy vN back to d.
MOVQ v1, 0(d)
MOVQ v2, 8(d)
MOVQ v3, 16(d)
MOVQ v4, 24(d)
// The number of bytes written is p minus the old base pointer.
SUBQ b_base+8(FP), p
MOVQ p, ret+32(FP)
RET

183
vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s generated vendored Normal file
View File

@@ -0,0 +1,183 @@
//go:build !appengine && gc && !purego
// +build !appengine
// +build gc
// +build !purego
#include "textflag.h"
// Registers:
#define digest R1
#define h R2 // return value
#define p R3 // input pointer
#define n R4 // input length
#define nblocks R5 // n / 32
#define prime1 R7
#define prime2 R8
#define prime3 R9
#define prime4 R10
#define prime5 R11
#define v1 R12
#define v2 R13
#define v3 R14
#define v4 R15
#define x1 R20
#define x2 R21
#define x3 R22
#define x4 R23
#define round(acc, x) \
MADD prime2, acc, x, acc \
ROR $64-31, acc \
MUL prime1, acc
// round0 performs the operation x = round(0, x).
#define round0(x) \
MUL prime2, x \
ROR $64-31, x \
MUL prime1, x
#define mergeRound(acc, x) \
round0(x) \
EOR x, acc \
MADD acc, prime4, prime1, acc
// blockLoop processes as many 32-byte blocks as possible,
// updating v1, v2, v3, and v4. It assumes that n >= 32.
#define blockLoop() \
LSR $5, n, nblocks \
PCALIGN $16 \
loop: \
LDP.P 16(p), (x1, x2) \
LDP.P 16(p), (x3, x4) \
round(v1, x1) \
round(v2, x2) \
round(v3, x3) \
round(v4, x4) \
SUB $1, nblocks \
CBNZ nblocks, loop
// func Sum64(b []byte) uint64
TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
LDP b_base+0(FP), (p, n)
LDP ·primes+0(SB), (prime1, prime2)
LDP ·primes+16(SB), (prime3, prime4)
MOVD ·primes+32(SB), prime5
CMP $32, n
CSEL LT, prime5, ZR, h // if n < 32 { h = prime5 } else { h = 0 }
BLT afterLoop
ADD prime1, prime2, v1
MOVD prime2, v2
MOVD $0, v3
NEG prime1, v4
blockLoop()
ROR $64-1, v1, x1
ROR $64-7, v2, x2
ADD x1, x2
ROR $64-12, v3, x3
ROR $64-18, v4, x4
ADD x3, x4
ADD x2, x4, h
mergeRound(h, v1)
mergeRound(h, v2)
mergeRound(h, v3)
mergeRound(h, v4)
afterLoop:
ADD n, h
TBZ $4, n, try8
LDP.P 16(p), (x1, x2)
round0(x1)
// NOTE: here and below, sequencing the EOR after the ROR (using a
// rotated register) is worth a small but measurable speedup for small
// inputs.
ROR $64-27, h
EOR x1 @> 64-27, h, h
MADD h, prime4, prime1, h
round0(x2)
ROR $64-27, h
EOR x2 @> 64-27, h, h
MADD h, prime4, prime1, h
try8:
TBZ $3, n, try4
MOVD.P 8(p), x1
round0(x1)
ROR $64-27, h
EOR x1 @> 64-27, h, h
MADD h, prime4, prime1, h
try4:
TBZ $2, n, try2
MOVWU.P 4(p), x2
MUL prime1, x2
ROR $64-23, h
EOR x2 @> 64-23, h, h
MADD h, prime3, prime2, h
try2:
TBZ $1, n, try1
MOVHU.P 2(p), x3
AND $255, x3, x1
LSR $8, x3, x2
MUL prime5, x1
ROR $64-11, h
EOR x1 @> 64-11, h, h
MUL prime1, h
MUL prime5, x2
ROR $64-11, h
EOR x2 @> 64-11, h, h
MUL prime1, h
try1:
TBZ $0, n, finalize
MOVBU (p), x4
MUL prime5, x4
ROR $64-11, h
EOR x4 @> 64-11, h, h
MUL prime1, h
finalize:
EOR h >> 33, h
MUL prime2, h
EOR h >> 29, h
MUL prime3, h
EOR h >> 32, h
MOVD h, ret+24(FP)
RET
// func writeBlocks(d *Digest, b []byte) int
TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
LDP ·primes+0(SB), (prime1, prime2)
// Load state. Assume v[1-4] are stored contiguously.
MOVD d+0(FP), digest
LDP 0(digest), (v1, v2)
LDP 16(digest), (v3, v4)
LDP b_base+8(FP), (p, n)
blockLoop()
// Store updated state.
STP (v1, v2), 0(digest)
STP (v3, v4), 16(digest)
BIC $31, n
MOVD n, ret+32(FP)
RET

15
vendor/github.com/cespare/xxhash/v2/xxhash_asm.go generated vendored Normal file
View File

@@ -0,0 +1,15 @@
//go:build (amd64 || arm64) && !appengine && gc && !purego
// +build amd64 arm64
// +build !appengine
// +build gc
// +build !purego
package xxhash
// Sum64 computes the 64-bit xxHash digest of b with a zero seed.
//
//go:noescape
func Sum64(b []byte) uint64
//go:noescape
func writeBlocks(d *Digest, b []byte) int

76
vendor/github.com/cespare/xxhash/v2/xxhash_other.go generated vendored Normal file
View File

@@ -0,0 +1,76 @@
//go:build (!amd64 && !arm64) || appengine || !gc || purego
// +build !amd64,!arm64 appengine !gc purego
package xxhash
// Sum64 computes the 64-bit xxHash digest of b with a zero seed.
func Sum64(b []byte) uint64 {
// A simpler version would be
// d := New()
// d.Write(b)
// return d.Sum64()
// but this is faster, particularly for small inputs.
n := len(b)
var h uint64
if n >= 32 {
v1 := primes[0] + prime2
v2 := prime2
v3 := uint64(0)
v4 := -primes[0]
for len(b) >= 32 {
v1 = round(v1, u64(b[0:8:len(b)]))
v2 = round(v2, u64(b[8:16:len(b)]))
v3 = round(v3, u64(b[16:24:len(b)]))
v4 = round(v4, u64(b[24:32:len(b)]))
b = b[32:len(b):len(b)]
}
h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)
h = mergeRound(h, v1)
h = mergeRound(h, v2)
h = mergeRound(h, v3)
h = mergeRound(h, v4)
} else {
h = prime5
}
h += uint64(n)
for ; len(b) >= 8; b = b[8:] {
k1 := round(0, u64(b[:8]))
h ^= k1
h = rol27(h)*prime1 + prime4
}
if len(b) >= 4 {
h ^= uint64(u32(b[:4])) * prime1
h = rol23(h)*prime2 + prime3
b = b[4:]
}
for ; len(b) > 0; b = b[1:] {
h ^= uint64(b[0]) * prime5
h = rol11(h) * prime1
}
h ^= h >> 33
h *= prime2
h ^= h >> 29
h *= prime3
h ^= h >> 32
return h
}
func writeBlocks(d *Digest, b []byte) int {
v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4
n := len(b)
for len(b) >= 32 {
v1 = round(v1, u64(b[0:8:len(b)]))
v2 = round(v2, u64(b[8:16:len(b)]))
v3 = round(v3, u64(b[16:24:len(b)]))
v4 = round(v4, u64(b[24:32:len(b)]))
b = b[32:len(b):len(b)]
}
d.v1, d.v2, d.v3, d.v4 = v1, v2, v3, v4
return n - len(b)
}

16
vendor/github.com/cespare/xxhash/v2/xxhash_safe.go generated vendored Normal file
View File

@@ -0,0 +1,16 @@
//go:build appengine
// +build appengine
// This file contains the safe implementations of otherwise unsafe-using code.
package xxhash
// Sum64String computes the 64-bit xxHash digest of s with a zero seed.
func Sum64String(s string) uint64 {
return Sum64([]byte(s))
}
// WriteString adds more data to d. It always returns len(s), nil.
func (d *Digest) WriteString(s string) (n int, err error) {
return d.Write([]byte(s))
}

58
vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go generated vendored Normal file
View File

@@ -0,0 +1,58 @@
//go:build !appengine
// +build !appengine
// This file encapsulates usage of unsafe.
// xxhash_safe.go contains the safe implementations.
package xxhash
import (
"unsafe"
)
// In the future it's possible that compiler optimizations will make these
// XxxString functions unnecessary by realizing that calls such as
// Sum64([]byte(s)) don't need to copy s. See https://go.dev/issue/2205.
// If that happens, even if we keep these functions they can be replaced with
// the trivial safe code.
// NOTE: The usual way of doing an unsafe string-to-[]byte conversion is:
//
// var b []byte
// bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
// bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
// bh.Len = len(s)
// bh.Cap = len(s)
//
// Unfortunately, as of Go 1.15.3 the inliner's cost model assigns a high enough
// weight to this sequence of expressions that any function that uses it will
// not be inlined. Instead, the functions below use a different unsafe
// conversion designed to minimize the inliner weight and allow both to be
// inlined. There is also a test (TestInlining) which verifies that these are
// inlined.
//
// See https://github.com/golang/go/issues/42739 for discussion.
// Sum64String computes the 64-bit xxHash digest of s with a zero seed.
// It may be faster than Sum64([]byte(s)) by avoiding a copy.
func Sum64String(s string) uint64 {
b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))
return Sum64(b)
}
// WriteString adds more data to d. It always returns len(s), nil.
// It may be faster than Write([]byte(s)) by avoiding a copy.
func (d *Digest) WriteString(s string) (n int, err error) {
d.Write(*(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})))
// d.Write always returns len(s), nil.
// Ignoring the return output and returning these fixed values buys a
// savings of 6 in the inliner's cost model.
return len(s), nil
}
// sliceHeader is similar to reflect.SliceHeader, but it assumes that the layout
// of the first two words is the same as the layout of a string.
type sliceHeader struct {
s string
cap int
}

View File

@@ -1,96 +0,0 @@
# v4.0.4
## Fixed
- Reverted "Allow unmarshalling JSONWebKeySets with unsupported key types" as a
breaking change. See #136 / #137.
# v4.0.3
## Changed
- Allow unmarshalling JSONWebKeySets with unsupported key types (#130)
- Document that OpaqueKeyEncrypter can't be implemented (for now) (#129)
- Dependency updates
# v4.0.2
## Changed
- Improved documentation of Verify() to note that JSONWebKeySet is a supported
argument type (#104)
- Defined exported error values for missing x5c header and unsupported elliptic
curves error cases (#117)
# v4.0.1
## Fixed
- An attacker could send a JWE containing compressed data that used large
amounts of memory and CPU when decompressed by `Decrypt` or `DecryptMulti`.
Those functions now return an error if the decompressed data would exceed
250kB or 10x the compressed size (whichever is larger). Thanks to
Enze Wang@Alioth and Jianjun Chen@Zhongguancun Lab (@zer0yu and @chenjj)
for reporting.
# v4.0.0
This release makes some breaking changes in order to more thoroughly
address the vulnerabilities discussed in [Three New Attacks Against JSON Web
Tokens][1], "Sign/encrypt confusion", "Billion hash attack", and "Polyglot
token".
## Changed
- Limit JWT encryption types (exclude password or public key types) (#78)
- Enforce minimum length for HMAC keys (#85)
- jwt: match any audience in a list, rather than requiring all audiences (#81)
- jwt: accept only Compact Serialization (#75)
- jws: Add expected algorithms for signatures (#74)
- Require specifying expected algorithms for ParseEncrypted,
ParseSigned, ParseDetached, jwt.ParseEncrypted, jwt.ParseSigned,
jwt.ParseSignedAndEncrypted (#69, #74)
- Usually there is a small, known set of appropriate algorithms for a program
to use and it's a mistake to allow unexpected algorithms. For instance the
"billion hash attack" relies in part on programs accepting the PBES2
encryption algorithm and doing the necessary work even if they weren't
specifically configured to allow PBES2.
- Revert "Strip padding off base64 strings" (#82)
- The specs require base64url encoding without padding.
- Minimum supported Go version is now 1.21
## Added
- ParseSignedCompact, ParseSignedJSON, ParseEncryptedCompact, ParseEncryptedJSON.
- These allow parsing a specific serialization, as opposed to ParseSigned and
ParseEncrypted, which try to automatically detect which serialization was
provided. It's common to require a specific serialization for a specific
protocol - for instance JWT requires Compact serialization.
[1]: https://i.blackhat.com/BH-US-23/Presentations/US-23-Tervoort-Three-New-Attacks-Against-JSON-Web-Tokens.pdf
# v3.0.2
## Fixed
- DecryptMulti: handle decompression error (#19)
## Changed
- jwe/CompactSerialize: improve performance (#67)
- Increase the default number of PBKDF2 iterations to 600k (#48)
- Return the proper algorithm for ECDSA keys (#45)
## Added
- Add Thumbprint support for opaque signers (#38)
# v3.0.1
## Fixed
- Security issue: an attacker specifying a large "p2c" value can cause
JSONWebEncryption.Decrypt and JSONWebEncryption.DecryptMulti to consume large
amounts of CPU, causing a DoS. Thanks to Matt Schwager (@mschwager) for the
disclosure and to Tom Tervoort for originally publishing the category of attack.
https://i.blackhat.com/BH-US-23/Presentations/US-23-Tervoort-Three-New-Attacks-Against-JSON-Web-Tokens.pdf

View File

@@ -3,7 +3,6 @@
[![godoc](https://pkg.go.dev/badge/github.com/go-jose/go-jose/v4.svg)](https://pkg.go.dev/github.com/go-jose/go-jose/v4)
[![godoc](https://pkg.go.dev/badge/github.com/go-jose/go-jose/v4/jwt.svg)](https://pkg.go.dev/github.com/go-jose/go-jose/v4/jwt)
[![license](https://img.shields.io/badge/license-apache_2.0-blue.svg?style=flat)](https://raw.githubusercontent.com/go-jose/go-jose/master/LICENSE)
[![test](https://img.shields.io/github/checks-status/go-jose/go-jose/v4)](https://github.com/go-jose/go-jose/actions)
Package jose aims to provide an implementation of the Javascript Object Signing
and Encryption set of standards. This includes support for JSON Web Encryption,
@@ -29,17 +28,20 @@ libraries in other languages.
### Versions
[Version 4](https://github.com/go-jose/go-jose)
([branch](https://github.com/go-jose/go-jose/tree/main),
[doc](https://pkg.go.dev/github.com/go-jose/go-jose/v4), [releases](https://github.com/go-jose/go-jose/releases)) is the current stable version:
The forthcoming Version 5 will be released with several breaking API changes,
and will require Golang's `encoding/json/v2`, which is currently requires
Go 1.25 built with GOEXPERIMENT=jsonv2.
Version 4 is the current stable version:
import "github.com/go-jose/go-jose/v4"
The old [square/go-jose](https://github.com/square/go-jose) repo contains the prior v1 and v2 versions, which
are still useable but not actively developed anymore.
It supports at least the current and previous Golang release. Currently it
requires Golang 1.24.
Version 3, in this repo, is still receiving security fixes but not functionality
updates.
Version 3 is only receiving critical security updates. Migration to Version 4 is recommended.
Versions 1 and 2 are obsolete, but can be found in the old repository, [square/go-jose](https://github.com/square/go-jose).
### Supported algorithms
@@ -47,36 +49,36 @@ See below for a table of supported algorithms. Algorithm identifiers match
the names in the [JSON Web Algorithms](https://dx.doi.org/10.17487/RFC7518)
standard where possible. The Godoc reference has a list of constants.
Key encryption | Algorithm identifier(s)
:------------------------- | :------------------------------
RSA-PKCS#1v1.5 | RSA1_5
RSA-OAEP | RSA-OAEP, RSA-OAEP-256
AES key wrap | A128KW, A192KW, A256KW
AES-GCM key wrap | A128GCMKW, A192GCMKW, A256GCMKW
ECDH-ES + AES key wrap | ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW
ECDH-ES (direct) | ECDH-ES<sup>1</sup>
Direct encryption | dir<sup>1</sup>
| Key encryption | Algorithm identifier(s) |
|:-----------------------|:-----------------------------------------------|
| RSA-PKCS#1v1.5 | RSA1_5 |
| RSA-OAEP | RSA-OAEP, RSA-OAEP-256 |
| AES key wrap | A128KW, A192KW, A256KW |
| AES-GCM key wrap | A128GCMKW, A192GCMKW, A256GCMKW |
| ECDH-ES + AES key wrap | ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW |
| ECDH-ES (direct) | ECDH-ES<sup>1</sup> |
| Direct encryption | dir<sup>1</sup> |
<sup>1. Not supported in multi-recipient mode</sup>
Signing / MAC | Algorithm identifier(s)
:------------------------- | :------------------------------
RSASSA-PKCS#1v1.5 | RS256, RS384, RS512
RSASSA-PSS | PS256, PS384, PS512
HMAC | HS256, HS384, HS512
ECDSA | ES256, ES384, ES512
Ed25519 | EdDSA<sup>2</sup>
| Signing / MAC | Algorithm identifier(s) |
|:------------------|:------------------------|
| RSASSA-PKCS#1v1.5 | RS256, RS384, RS512 |
| RSASSA-PSS | PS256, PS384, PS512 |
| HMAC | HS256, HS384, HS512 |
| ECDSA | ES256, ES384, ES512 |
| Ed25519 | EdDSA<sup>2</sup> |
<sup>2. Only available in version 2 of the package</sup>
Content encryption | Algorithm identifier(s)
:------------------------- | :------------------------------
AES-CBC+HMAC | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512
AES-GCM | A128GCM, A192GCM, A256GCM
| Content encryption | Algorithm identifier(s) |
|:-------------------|:--------------------------------------------|
| AES-CBC+HMAC | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 |
| AES-GCM | A128GCM, A192GCM, A256GCM |
Compression | Algorithm identifiers(s)
:------------------------- | -------------------------------
DEFLATE (RFC 1951) | DEF
| Compression | Algorithm identifiers(s) |
|:-------------------|--------------------------|
| DEFLATE (RFC 1951) | DEF |
### Supported key types
@@ -85,12 +87,12 @@ library, and can be passed to corresponding functions such as `NewEncrypter` or
`NewSigner`. Each of these keys can also be wrapped in a JWK if desired, which
allows attaching a key id.
Algorithm(s) | Corresponding types
:------------------------- | -------------------------------
RSA | *[rsa.PublicKey](https://pkg.go.dev/crypto/rsa/#PublicKey), *[rsa.PrivateKey](https://pkg.go.dev/crypto/rsa/#PrivateKey)
ECDH, ECDSA | *[ecdsa.PublicKey](https://pkg.go.dev/crypto/ecdsa/#PublicKey), *[ecdsa.PrivateKey](https://pkg.go.dev/crypto/ecdsa/#PrivateKey)
EdDSA<sup>1</sup> | [ed25519.PublicKey](https://pkg.go.dev/crypto/ed25519#PublicKey), [ed25519.PrivateKey](https://pkg.go.dev/crypto/ed25519#PrivateKey)
AES, HMAC | []byte
| Algorithm(s) | Corresponding types |
|:------------------|--------------------------------------------------------------------------------------------------------------------------------------|
| RSA | *[rsa.PublicKey](https://pkg.go.dev/crypto/rsa/#PublicKey), *[rsa.PrivateKey](https://pkg.go.dev/crypto/rsa/#PrivateKey) |
| ECDH, ECDSA | *[ecdsa.PublicKey](https://pkg.go.dev/crypto/ecdsa/#PublicKey), *[ecdsa.PrivateKey](https://pkg.go.dev/crypto/ecdsa/#PrivateKey) |
| EdDSA<sup>1</sup> | [ed25519.PublicKey](https://pkg.go.dev/crypto/ed25519#PublicKey), [ed25519.PrivateKey](https://pkg.go.dev/crypto/ed25519#PrivateKey) |
| AES, HMAC | []byte |
<sup>1. Only available in version 2 or later of the package</sup>

View File

@@ -414,6 +414,9 @@ func (ctx ecKeyGenerator) genKey() ([]byte, rawHeader, error) {
// Decrypt the given payload and return the content encryption key.
func (ctx ecDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
if recipient == nil {
return nil, errors.New("go-jose/go-jose: missing recipient")
}
epk, err := headers.getEPK()
if err != nil {
return nil, errors.New("go-jose/go-jose: invalid epk header")
@@ -461,13 +464,18 @@ func (ctx ecDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientI
return nil, ErrUnsupportedAlgorithm
}
encryptedKey := recipient.encryptedKey
if len(encryptedKey) == 0 {
return nil, errors.New("go-jose/go-jose: missing JWE Encrypted Key")
}
key := deriveKey(string(algorithm), keySize)
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
return josecipher.KeyUnwrap(block, recipient.encryptedKey)
return josecipher.KeyUnwrap(block, encryptedKey)
}
func (ctx edDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) {

View File

@@ -66,12 +66,20 @@ func KeyWrap(block cipher.Block, cek []byte) ([]byte, error) {
}
// KeyUnwrap implements NIST key unwrapping; it unwraps a content encryption key (cek) with the given block cipher.
//
// https://datatracker.ietf.org/doc/html/rfc7518#section-4.4
// https://datatracker.ietf.org/doc/html/rfc7518#section-4.6
// https://datatracker.ietf.org/doc/html/rfc7518#section-4.8
func KeyUnwrap(block cipher.Block, ciphertext []byte) ([]byte, error) {
n := (len(ciphertext) / 8) - 1
if n <= 0 {
return nil, errors.New("go-jose/go-jose: JWE Encrypted Key too short")
}
if len(ciphertext)%8 != 0 {
return nil, errors.New("go-jose/go-jose: key wrap input must be 8 byte blocks")
}
n := (len(ciphertext) / 8) - 1
r := make([][]byte, n)
for i := range r {

View File

@@ -286,6 +286,10 @@ func makeJWERecipient(alg KeyAlgorithm, encryptionKey interface{}) (recipientKey
return newSymmetricRecipient(alg, encryptionKey)
case string:
return newSymmetricRecipient(alg, []byte(encryptionKey))
case JSONWebKey:
recipient, err := makeJWERecipient(alg, encryptionKey.Key)
recipient.keyID = encryptionKey.KeyID
return recipient, err
case *JSONWebKey:
recipient, err := makeJWERecipient(alg, encryptionKey.Key)
recipient.keyID = encryptionKey.KeyID
@@ -450,13 +454,9 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error)
return nil, errors.New("go-jose/go-jose: too many recipients in payload; expecting only one")
}
critical, err := headers.getCritical()
err := headers.checkNoCritical()
if err != nil {
return nil, fmt.Errorf("go-jose/go-jose: invalid crit header")
}
if len(critical) > 0 {
return nil, fmt.Errorf("go-jose/go-jose: unsupported crit header")
return nil, err
}
key, err := tryJWKS(decryptionKey, obj.Header)
@@ -523,13 +523,9 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error)
func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Header, []byte, error) {
globalHeaders := obj.mergedHeaders(nil)
critical, err := globalHeaders.getCritical()
err := globalHeaders.checkNoCritical()
if err != nil {
return -1, Header{}, nil, fmt.Errorf("go-jose/go-jose: invalid crit header")
}
if len(critical) > 0 {
return -1, Header{}, nil, fmt.Errorf("go-jose/go-jose: unsupported crit header")
return -1, Header{}, nil, err
}
key, err := tryJWKS(decryptionKey, obj.Header)

View File

@@ -274,7 +274,7 @@ func validateAlgEnc(headers rawHeader, keyAlgorithms []KeyAlgorithm, contentEncr
if alg != "" && !containsKeyAlgorithm(keyAlgorithms, alg) {
return fmt.Errorf("unexpected key algorithm %q; expected %q", alg, keyAlgorithms)
}
if alg != "" && !containsContentEncryption(contentEncryption, enc) {
if enc != "" && !containsContentEncryption(contentEncryption, enc) {
return fmt.Errorf("unexpected content encryption algorithm %q; expected %q", enc, contentEncryption)
}
return nil
@@ -288,11 +288,20 @@ func ParseEncryptedCompact(
keyAlgorithms []KeyAlgorithm,
contentEncryption []ContentEncryption,
) (*JSONWebEncryption, error) {
// Five parts is four separators
if strings.Count(input, ".") != 4 {
return nil, fmt.Errorf("go-jose/go-jose: compact JWE format must have five parts")
var parts [5]string
var ok bool
for i := range 4 {
parts[i], input, ok = strings.Cut(input, ".")
if !ok {
return nil, errors.New("go-jose/go-jose: compact JWE format must have five parts")
}
}
parts := strings.SplitN(input, ".", 5)
// Validate that the last part does not contain more dots
if strings.ContainsRune(input, '.') {
return nil, errors.New("go-jose/go-jose: compact JWE format must have five parts")
}
parts[4] = input
rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0])
if err != nil {

View File

@@ -175,6 +175,8 @@ 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) {
var raw rawJSONWebKey
err = json.Unmarshal(data, &raw)
@@ -228,7 +230,7 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
}
key, err = raw.symmetricKey()
case "OKP":
if raw.Crv == "Ed25519" && raw.X != nil {
if raw.Crv == "Ed25519" {
if raw.D != nil {
key, err = raw.edPrivateKey()
if err == nil {
@@ -238,17 +240,27 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
key, err = raw.edPublicKey()
keyPub = key
}
} else {
return fmt.Errorf("go-jose/go-jose: unknown curve %s'", raw.Crv)
}
default:
return fmt.Errorf("go-jose/go-jose: unknown json web key type '%s'", raw.Kty)
case "":
// kty MUST be present
err = fmt.Errorf("go-jose/go-jose: missing json web key type")
}
if err != nil {
return
}
if key == nil {
// RFC 7517:
// 5. JWK Set Format
// ...
// Implementations SHOULD ignore JWKs within a JWK Set that use "kty"
// (key type) values that are not understood by them, that are missing
// required members, or for which values are out of the supported
// ranges.
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")
@@ -581,10 +593,10 @@ func fromEcPublicKey(pub *ecdsa.PublicKey) (*rawJSONWebKey, error) {
func (key rawJSONWebKey) edPrivateKey() (ed25519.PrivateKey, error) {
var missing []string
switch {
case key.D == nil:
if key.D == nil {
missing = append(missing, "D")
case key.X == nil:
}
if key.X == nil {
missing = append(missing, "X")
}
@@ -611,19 +623,21 @@ func (key rawJSONWebKey) edPublicKey() (ed25519.PublicKey, error) {
func (key rawJSONWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) {
var missing []string
switch {
case key.N == nil:
if key.N == nil {
missing = append(missing, "N")
case key.E == nil:
}
if key.E == nil {
missing = append(missing, "E")
case key.D == nil:
}
if key.D == nil {
missing = append(missing, "D")
case key.P == nil:
}
if key.P == nil {
missing = append(missing, "P")
case key.Q == nil:
}
if key.Q == nil {
missing = append(missing, "Q")
}
if len(missing) > 0 {
return nil, fmt.Errorf("go-jose/go-jose: invalid RSA private key, missing %s value(s)", strings.Join(missing, ", "))
}
@@ -698,8 +712,19 @@ func (key rawJSONWebKey) ecPrivateKey() (*ecdsa.PrivateKey, error) {
return nil, fmt.Errorf("go-jose/go-jose: unsupported elliptic curve '%s'", key.Crv)
}
if key.X == nil || key.Y == nil || key.D == nil {
return nil, fmt.Errorf("go-jose/go-jose: invalid EC private key, missing x/y/d values")
var missing []string
if key.X == nil {
missing = append(missing, "X")
}
if key.Y == nil {
missing = append(missing, "Y")
}
if key.D == nil {
missing = append(missing, "D")
}
if len(missing) > 0 {
return nil, fmt.Errorf("go-jose/go-jose: invalid EC private key, missing %s value(s)", strings.Join(missing, ", "))
}
// The length of this octet string MUST be the full size of a coordinate for

View File

@@ -75,7 +75,14 @@ type Signature struct {
original *rawSignatureInfo
}
// ParseSigned parses a signed message in JWS Compact or JWS JSON Serialization.
// ParseSigned parses a signed message in JWS Compact or JWS JSON Serialization. Validation fails if
// the JWS is signed with an algorithm that isn't in the provided list of signature algorithms.
// Applications should decide for themselves which signature algorithms are acceptable. If you're
// not sure which signature algorithms your application might receive, consult the documentation of
// the program which provides them or the protocol that you are implementing. You can also try
// getting an example JWS and decoding it with a tool like https://jwt.io to see what its "alg"
// header parameter indicates. The signature on the JWS does not get validated during parsing. Call
// Verify() after parsing to validate the signature and obtain the payload.
//
// https://datatracker.ietf.org/doc/html/rfc7515#section-7
func ParseSigned(
@@ -90,7 +97,14 @@ func ParseSigned(
return parseSignedCompact(signature, nil, signatureAlgorithms)
}
// ParseSignedCompact parses a message in JWS Compact Serialization.
// ParseSignedCompact parses a message in JWS Compact Serialization. Validation fails if the JWS is
// signed with an algorithm that isn't in the provided list of signature algorithms. Applications
// should decide for themselves which signature algorithms are acceptable.If you're not sure which
// signature algorithms your application might receive, consult the documentation of the program
// which provides them or the protocol that you are implementing. You can also try getting an
// example JWS and decoding it with a tool like https://jwt.io to see what its "alg" header
// parameter indicates. The signature on the JWS does not get validated during parsing. Call
// Verify() after parsing to validate the signature and obtain the payload.
//
// https://datatracker.ietf.org/doc/html/rfc7515#section-7.1
func ParseSignedCompact(
@@ -101,6 +115,15 @@ func ParseSignedCompact(
}
// ParseDetached parses a signed message in compact serialization format with detached payload.
// Validation fails if the JWS is signed with an algorithm that isn't in the provided list of
// signature algorithms. Applications should decide for themselves which signature algorithms are
// acceptable. If you're not sure which signature algorithms your application might receive, consult
// the documentation of the program which provides them or the protocol that you are implementing.
// You can also try getting an example JWS and decoding it with a tool like https://jwt.io to see
// what its "alg" header parameter indicates. The signature on the JWS does not get validated during
// parsing. Call Verify() after parsing to validate the signature and obtain the payload.
//
// https://datatracker.ietf.org/doc/html/rfc7515#appendix-F
func ParseDetached(
signature string,
payload []byte,
@@ -181,6 +204,25 @@ func containsSignatureAlgorithm(haystack []SignatureAlgorithm, needle SignatureA
return false
}
// ErrUnexpectedSignatureAlgorithm is returned when the signature algorithm in
// the JWS header does not match one of the expected algorithms.
type ErrUnexpectedSignatureAlgorithm struct {
// Got is the signature algorithm found in the JWS header.
Got SignatureAlgorithm
expected []SignatureAlgorithm
}
func (e *ErrUnexpectedSignatureAlgorithm) Error() string {
return fmt.Sprintf("unexpected signature algorithm %q; expected %q", e.Got, e.expected)
}
func newErrUnexpectedSignatureAlgorithm(got SignatureAlgorithm, expected []SignatureAlgorithm) error {
return &ErrUnexpectedSignatureAlgorithm{
Got: got,
expected: expected,
}
}
// sanitized produces a cleaned-up JWS object from the raw JSON.
func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgorithm) (*JSONWebSignature, error) {
if len(signatureAlgorithms) == 0 {
@@ -236,8 +278,7 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
alg := SignatureAlgorithm(signature.Header.Algorithm)
if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
return nil, fmt.Errorf("go-jose/go-jose: unexpected signature algorithm %q; expected %q",
alg, signatureAlgorithms)
return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms)
}
if signature.header != nil {
@@ -285,8 +326,7 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
alg := SignatureAlgorithm(obj.Signatures[i].Header.Algorithm)
if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
return nil, fmt.Errorf("go-jose/go-jose: unexpected signature algorithm %q; expected %q",
alg, signatureAlgorithms)
return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms)
}
if obj.Signatures[i].header != nil {
@@ -321,35 +361,43 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
return obj, nil
}
const tokenDelim = "."
// parseSignedCompact parses a message in compact format.
func parseSignedCompact(
input string,
payload []byte,
signatureAlgorithms []SignatureAlgorithm,
) (*JSONWebSignature, error) {
// Three parts is two separators
if strings.Count(input, ".") != 2 {
protected, s, ok := strings.Cut(input, tokenDelim)
if !ok { // no period found
return nil, fmt.Errorf("go-jose/go-jose: compact JWS format must have three parts")
}
claims, sig, ok := strings.Cut(s, tokenDelim)
if !ok { // only one period found
return nil, fmt.Errorf("go-jose/go-jose: compact JWS format must have three parts")
}
if strings.ContainsRune(sig, '.') { // too many periods found
return nil, fmt.Errorf("go-jose/go-jose: compact JWS format must have three parts")
}
parts := strings.SplitN(input, ".", 3)
if parts[1] != "" && payload != nil {
if claims != "" && payload != nil {
return nil, fmt.Errorf("go-jose/go-jose: payload is not detached")
}
rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0])
rawProtected, err := base64.RawURLEncoding.DecodeString(protected)
if err != nil {
return nil, err
}
if payload == nil {
payload, err = base64.RawURLEncoding.DecodeString(parts[1])
payload, err = base64.RawURLEncoding.DecodeString(claims)
if err != nil {
return nil, err
}
}
signature, err := base64.RawURLEncoding.DecodeString(parts[2])
signature, err := base64.RawURLEncoding.DecodeString(sig)
if err != nil {
return nil, err
}

View File

@@ -77,6 +77,9 @@ var (
// ErrUnsupportedEllipticCurve indicates unsupported or unknown elliptic curve has been found.
ErrUnsupportedEllipticCurve = errors.New("go-jose/go-jose: unsupported/unknown elliptic curve")
// ErrUnsupportedCriticalHeader is returned when a header is marked critical but not supported by go-jose.
ErrUnsupportedCriticalHeader = errors.New("go-jose/go-jose: unsupported critical header")
)
// Key management algorithms
@@ -167,8 +170,8 @@ const (
)
// supportedCritical is the set of supported extensions that are understood and processed.
var supportedCritical = map[string]bool{
headerB64: true,
var supportedCritical = map[string]struct{}{
headerB64: {},
}
// rawHeader represents the JOSE header for JWE/JWS objects (used for parsing).
@@ -346,6 +349,32 @@ func (parsed rawHeader) getCritical() ([]string, error) {
return q, nil
}
// checkNoCritical verifies there are no critical headers present.
func (parsed rawHeader) checkNoCritical() error {
if _, ok := parsed[headerCritical]; ok {
return ErrUnsupportedCriticalHeader
}
return nil
}
// checkSupportedCritical verifies there are no unsupported critical headers.
// Supported headers are passed in as a set: map of names to empty structs
func (parsed rawHeader) checkSupportedCritical(supported map[string]struct{}) error {
crit, err := parsed.getCritical()
if err != nil {
return err
}
for _, name := range crit {
if _, ok := supported[name]; !ok {
return ErrUnsupportedCriticalHeader
}
}
return nil
}
// getS2C extracts parsed "p2c" from the raw JSON.
func (parsed rawHeader) getP2C() (int, error) {
v := parsed[headerP2C]

View File

@@ -404,15 +404,23 @@ func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey inter
}
signature := obj.Signatures[0]
headers := signature.mergedHeaders()
critical, err := headers.getCritical()
if err != nil {
return err
if signature.header != nil {
// Per https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.11,
// 4.1.11. "crit" (Critical) Header Parameter
// "When used, this Header Parameter MUST be integrity
// protected; therefore, it MUST occur only within the JWS
// Protected Header."
err = signature.header.checkNoCritical()
if err != nil {
return err
}
}
for _, name := range critical {
if !supportedCritical[name] {
return ErrCryptoFailure
if signature.protected != nil {
err = signature.protected.checkSupportedCritical(supportedCritical)
if err != nil {
return err
}
}
@@ -421,6 +429,7 @@ func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey inter
return ErrCryptoFailure
}
headers := signature.mergedHeaders()
alg := headers.getSignatureAlgorithm()
err = verifier.verifyPayload(input, signature.Signature, alg)
if err == nil {
@@ -469,14 +478,22 @@ func (obj JSONWebSignature) DetachedVerifyMulti(payload []byte, verificationKey
outer:
for i, signature := range obj.Signatures {
headers := signature.mergedHeaders()
critical, err := headers.getCritical()
if err != nil {
continue
if signature.header != nil {
// Per https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.11,
// 4.1.11. "crit" (Critical) Header Parameter
// "When used, this Header Parameter MUST be integrity
// protected; therefore, it MUST occur only within the JWS
// Protected Header."
err = signature.header.checkNoCritical()
if err != nil {
continue outer
}
}
for _, name := range critical {
if !supportedCritical[name] {
if signature.protected != nil {
// Check for only supported critical headers
err = signature.protected.checkSupportedCritical(supportedCritical)
if err != nil {
continue outer
}
}
@@ -486,6 +503,7 @@ outer:
continue
}
headers := signature.mergedHeaders()
alg := headers.getSignatureAlgorithm()
err = verifier.verifyPayload(input, signature.Signature, alg)
if err == nil {

View File

@@ -21,6 +21,7 @@ import (
"crypto/aes"
"crypto/cipher"
"crypto/hmac"
"crypto/pbkdf2"
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
@@ -30,8 +31,6 @@ import (
"hash"
"io"
"golang.org/x/crypto/pbkdf2"
josecipher "github.com/go-jose/go-jose/v4/cipher"
)
@@ -330,7 +329,10 @@ func (ctx *symmetricKeyCipher) encryptKey(cek []byte, alg KeyAlgorithm) (recipie
// derive key
keyLen, h := getPbkdf2Params(alg)
key := pbkdf2.Key(ctx.key, salt, ctx.p2c, keyLen, h)
key, err := pbkdf2.Key(h, string(ctx.key), salt, ctx.p2c, keyLen)
if err != nil {
return recipientInfo{}, nil
}
// use AES cipher with derived key
block, err := aes.NewCipher(key)
@@ -364,11 +366,21 @@ func (ctx *symmetricKeyCipher) encryptKey(cek []byte, alg KeyAlgorithm) (recipie
// Decrypt the content encryption key.
func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
switch headers.getAlgorithm() {
case DIRECT:
cek := make([]byte, len(ctx.key))
copy(cek, ctx.key)
return cek, nil
if recipient == nil {
return nil, fmt.Errorf("go-jose/go-jose: missing recipient")
}
alg := headers.getAlgorithm()
if alg == DIRECT {
return bytes.Clone(ctx.key), nil
}
encryptedKey := recipient.encryptedKey
if len(encryptedKey) == 0 {
return nil, fmt.Errorf("go-jose/go-jose: missing JWE Encrypted Key")
}
switch alg {
case A128GCMKW, A192GCMKW, A256GCMKW:
aead := newAESGCM(len(ctx.key))
@@ -383,7 +395,7 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien
parts := &aeadParts{
iv: iv.bytes(),
ciphertext: recipient.encryptedKey,
ciphertext: encryptedKey,
tag: tag.bytes(),
}
@@ -399,7 +411,7 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien
return nil, err
}
cek, err := josecipher.KeyUnwrap(block, recipient.encryptedKey)
cek, err := josecipher.KeyUnwrap(block, encryptedKey)
if err != nil {
return nil, err
}
@@ -432,7 +444,10 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien
// derive key
keyLen, h := getPbkdf2Params(alg)
key := pbkdf2.Key(ctx.key, salt, p2c, keyLen, h)
key, err := pbkdf2.Key(h, string(ctx.key), salt, p2c, keyLen)
if err != nil {
return nil, err
}
// use AES cipher with derived key
block, err := aes.NewCipher(key)
@@ -440,7 +455,7 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien
return nil, err
}
cek, err := josecipher.KeyUnwrap(block, recipient.encryptedKey)
cek, err := josecipher.KeyUnwrap(block, encryptedKey)
if err != nil {
return nil, err
}

View File

@@ -82,7 +82,7 @@ func marshalJSON(id []byte) ([]byte, error) {
}
// unmarshalJSON inflates trace id from hex string, possibly enclosed in quotes.
func unmarshalJSON(dst []byte, src []byte) error {
func unmarshalJSON(dst, src []byte) error {
if l := len(src); l >= 2 && src[0] == '"' && src[l-1] == '"' {
src = src[1 : l-1]
}

View File

@@ -41,7 +41,7 @@ func (i *protoInt64) UnmarshalJSON(data []byte) error {
// strings or integers.
type protoUint64 uint64
// Int64 returns the protoUint64 as a uint64.
// Uint64 returns the protoUint64 as a uint64.
func (i *protoUint64) Uint64() uint64 { return uint64(*i) }
// UnmarshalJSON decodes both strings and integers.

View File

@@ -10,6 +10,7 @@ import (
"errors"
"fmt"
"io"
"math"
"time"
)
@@ -151,8 +152,8 @@ func (s Span) MarshalJSON() ([]byte, error) {
}{
Alias: Alias(s),
ParentSpanID: parentSpanId,
StartTime: uint64(startT),
EndTime: uint64(endT),
StartTime: uint64(startT), // nolint:gosec // >0 checked above.
EndTime: uint64(endT), // nolint:gosec // >0 checked above.
})
}
@@ -201,11 +202,13 @@ func (s *Span) UnmarshalJSON(data []byte) error {
case "startTimeUnixNano", "start_time_unix_nano":
var val protoUint64
err = decoder.Decode(&val)
s.StartTime = time.Unix(0, int64(val.Uint64()))
v := int64(min(val.Uint64(), math.MaxInt64)) //nolint:gosec // Overflow checked.
s.StartTime = time.Unix(0, v)
case "endTimeUnixNano", "end_time_unix_nano":
var val protoUint64
err = decoder.Decode(&val)
s.EndTime = time.Unix(0, int64(val.Uint64()))
v := int64(min(val.Uint64(), math.MaxInt64)) //nolint:gosec // Overflow checked.
s.EndTime = time.Unix(0, v)
case "attributes":
err = decoder.Decode(&s.Attrs)
case "droppedAttributesCount", "dropped_attributes_count":
@@ -248,13 +251,20 @@ func (s *Span) UnmarshalJSON(data []byte) error {
type SpanFlags int32
const (
// SpanFlagsTraceFlagsMask is a mask for trace-flags.
//
// Bits 0-7 are used for trace flags.
SpanFlagsTraceFlagsMask SpanFlags = 255
// Bits 8 and 9 are used to indicate that the parent span or link span is remote.
// Bit 8 (`HAS_IS_REMOTE`) indicates whether the value is known.
// Bit 9 (`IS_REMOTE`) indicates whether the span or link is remote.
// SpanFlagsContextHasIsRemoteMask is a mask for HAS_IS_REMOTE status.
//
// Bits 8 and 9 are used to indicate that the parent span or link span is
// remote. Bit 8 (`HAS_IS_REMOTE`) indicates whether the value is known.
SpanFlagsContextHasIsRemoteMask SpanFlags = 256
// SpanFlagsContextHasIsRemoteMask indicates the Span is remote.
// SpanFlagsContextIsRemoteMask is a mask for IS_REMOTE status.
//
// Bits 8 and 9 are used to indicate that the parent span or link span is
// remote. Bit 9 (`IS_REMOTE`) indicates whether the span or link is
// remote.
SpanFlagsContextIsRemoteMask SpanFlags = 512
)
@@ -263,26 +273,30 @@ const (
type SpanKind int32
const (
// Indicates that the span represents an internal operation within an application,
// as opposed to an operation happening at the boundaries. Default value.
// SpanKindInternal indicates that the span represents an internal
// operation within an application, as opposed to an operation happening at
// the boundaries.
SpanKindInternal SpanKind = 1
// Indicates that the span covers server-side handling of an RPC or other
// remote network request.
// SpanKindServer indicates that the span covers server-side handling of an
// RPC or other remote network request.
SpanKindServer SpanKind = 2
// Indicates that the span describes a request to some remote service.
// SpanKindClient indicates that the span describes a request to some
// remote service.
SpanKindClient SpanKind = 3
// Indicates that the span describes a producer sending a message to a broker.
// Unlike CLIENT and SERVER, there is often no direct critical path latency relationship
// between producer and consumer spans. A PRODUCER span ends when the message was accepted
// by the broker while the logical processing of the message might span a much longer time.
// SpanKindProducer indicates that the span describes a producer sending a
// message to a broker. Unlike SpanKindClient and SpanKindServer, there is
// often no direct critical path latency relationship between producer and
// consumer spans. A SpanKindProducer span ends when the message was
// accepted by the broker while the logical processing of the message might
// span a much longer time.
SpanKindProducer SpanKind = 4
// Indicates that the span describes consumer receiving a message from a broker.
// Like the PRODUCER kind, there is often no direct critical path latency relationship
// between producer and consumer spans.
// SpanKindConsumer indicates that the span describes a consumer receiving
// a message from a broker. Like SpanKindProducer, there is often no direct
// critical path latency relationship between producer and consumer spans.
SpanKindConsumer SpanKind = 5
)
// Event is a time-stamped annotation of the span, consisting of user-supplied
// SpanEvent is a time-stamped annotation of the span, consisting of user-supplied
// text description and key-value pairs.
type SpanEvent struct {
// time_unix_nano is the time the event occurred.
@@ -312,7 +326,7 @@ func (e SpanEvent) MarshalJSON() ([]byte, error) {
Time uint64 `json:"timeUnixNano,omitempty"`
}{
Alias: Alias(e),
Time: uint64(t),
Time: uint64(t), //nolint:gosec // >0 checked above
})
}
@@ -347,7 +361,8 @@ func (se *SpanEvent) UnmarshalJSON(data []byte) error {
case "timeUnixNano", "time_unix_nano":
var val protoUint64
err = decoder.Decode(&val)
se.Time = time.Unix(0, int64(val.Uint64()))
v := int64(min(val.Uint64(), math.MaxInt64)) //nolint:gosec // Overflow checked.
se.Time = time.Unix(0, v)
case "name":
err = decoder.Decode(&se.Name)
case "attributes":
@@ -365,10 +380,11 @@ func (se *SpanEvent) UnmarshalJSON(data []byte) error {
return nil
}
// A pointer from the current span to another span in the same trace or in a
// different trace. For example, this can be used in batching operations,
// where a single batch handler processes multiple requests from different
// traces or when the handler receives a request from a different project.
// SpanLink is a reference from the current span to another span in the same
// trace or in a different trace. For example, this can be used in batching
// operations, where a single batch handler processes multiple requests from
// different traces or when the handler receives a request from a different
// project.
type SpanLink struct {
// A unique identifier of a trace that this linked span is part of. The ID is a
// 16-byte array.

View File

@@ -3,17 +3,19 @@
package telemetry
// StatusCode is the status of a Span.
//
// For the semantics of status codes see
// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#set-status
type StatusCode int32
const (
// The default status.
// StatusCodeUnset is the default status.
StatusCodeUnset StatusCode = 0
// The Span has been validated by an Application developer or Operator to
// have completed successfully.
// StatusCodeOK is used when the Span has been validated by an Application
// developer or Operator to have completed successfully.
StatusCodeOK StatusCode = 1
// The Span contains an error.
// StatusCodeError is used when the Span contains an error.
StatusCodeError StatusCode = 2
)

View File

@@ -71,7 +71,7 @@ func (td *Traces) UnmarshalJSON(data []byte) error {
return nil
}
// A collection of ScopeSpans from a Resource.
// ResourceSpans is a collection of ScopeSpans from a Resource.
type ResourceSpans struct {
// The resource for the spans in this message.
// If this field is not set then no resource info is known.
@@ -128,7 +128,7 @@ func (rs *ResourceSpans) UnmarshalJSON(data []byte) error {
return nil
}
// A collection of Spans produced by an InstrumentationScope.
// ScopeSpans is a collection of Spans produced by an InstrumentationScope.
type ScopeSpans struct {
// The instrumentation scope information for the spans in this message.
// Semantically when InstrumentationScope isn't set, it is equivalent with

View File

@@ -1,8 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
//go:generate stringer -type=ValueKind -trimprefix=ValueKind
package telemetry
import (
@@ -23,7 +21,7 @@ import (
// A zero value is valid and represents an empty value.
type Value struct {
// Ensure forward compatibility by explicitly making this not comparable.
noCmp [0]func() //nolint: unused // This is indeed used.
noCmp [0]func() //nolint:unused // This is indeed used.
// num holds the value for Int64, Float64, and Bool. It holds the length
// for String, Bytes, Slice, Map.
@@ -92,7 +90,7 @@ func IntValue(v int) Value { return Int64Value(int64(v)) }
// Int64Value returns a [Value] for an int64.
func Int64Value(v int64) Value {
return Value{num: uint64(v), any: ValueKindInt64}
return Value{num: uint64(v), any: ValueKindInt64} //nolint:gosec // Raw value conv.
}
// Float64Value returns a [Value] for a float64.
@@ -164,7 +162,7 @@ func (v Value) AsInt64() int64 {
// this will return garbage.
func (v Value) asInt64() int64 {
// Assumes v.num was a valid int64 (overflow not checked).
return int64(v.num) // nolint: gosec
return int64(v.num) //nolint:gosec // Bounded.
}
// AsBool returns the value held by v as a bool.
@@ -309,13 +307,13 @@ func (v Value) String() string {
return v.asString()
case ValueKindInt64:
// Assumes v.num was a valid int64 (overflow not checked).
return strconv.FormatInt(int64(v.num), 10) // nolint: gosec
return strconv.FormatInt(int64(v.num), 10) //nolint:gosec // Bounded.
case ValueKindFloat64:
return strconv.FormatFloat(v.asFloat64(), 'g', -1, 64)
case ValueKindBool:
return strconv.FormatBool(v.asBool())
case ValueKindBytes:
return fmt.Sprint(v.asBytes())
return string(v.asBytes())
case ValueKindMap:
return fmt.Sprint(v.asMap())
case ValueKindSlice:
@@ -343,7 +341,7 @@ func (v *Value) MarshalJSON() ([]byte, error) {
case ValueKindInt64:
return json.Marshal(struct {
Value string `json:"intValue"`
}{strconv.FormatInt(int64(v.num), 10)})
}{strconv.FormatInt(int64(v.num), 10)}) //nolint:gosec // Raw value conv.
case ValueKindFloat64:
return json.Marshal(struct {
Value float64 `json:"doubleValue"`

View File

@@ -6,6 +6,7 @@ package sdk
import (
"encoding/json"
"fmt"
"math"
"reflect"
"runtime"
"strings"
@@ -16,7 +17,7 @@ import (
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
"go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/noop"
@@ -85,7 +86,12 @@ func (s *span) SetAttributes(attrs ...attribute.KeyValue) {
limit := maxSpan.Attrs
if limit == 0 {
// No attributes allowed.
s.span.DroppedAttrs += uint32(len(attrs))
n := int64(len(attrs))
if n > 0 {
s.span.DroppedAttrs += uint32( //nolint:gosec // Bounds checked.
min(n, math.MaxUint32),
)
}
return
}
@@ -121,8 +127,13 @@ func (s *span) SetAttributes(attrs ...attribute.KeyValue) {
// convCappedAttrs converts up to limit attrs into a []telemetry.Attr. The
// number of dropped attributes is also returned.
func convCappedAttrs(limit int, attrs []attribute.KeyValue) ([]telemetry.Attr, uint32) {
n := len(attrs)
if limit == 0 {
return nil, uint32(len(attrs))
var out uint32
if n > 0 {
out = uint32(min(int64(n), math.MaxUint32)) //nolint:gosec // Bounds checked.
}
return nil, out
}
if limit < 0 {
@@ -130,8 +141,12 @@ func convCappedAttrs(limit int, attrs []attribute.KeyValue) ([]telemetry.Attr, u
return convAttrs(attrs), 0
}
limit = min(len(attrs), limit)
return convAttrs(attrs[:limit]), uint32(len(attrs) - limit)
if n < 0 {
n = 0
}
limit = min(n, limit)
return convAttrs(attrs[:limit]), uint32(n - limit) //nolint:gosec // Bounds checked.
}
func convAttrs(attrs []attribute.KeyValue) []telemetry.Attr {

View File

@@ -5,6 +5,7 @@ package sdk
import (
"context"
"math"
"time"
"go.opentelemetry.io/otel/trace"
@@ -21,15 +22,20 @@ type tracer struct {
var _ trace.Tracer = tracer{}
func (t tracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
var psc trace.SpanContext
func (t tracer) Start(
ctx context.Context,
name string,
opts ...trace.SpanStartOption,
) (context.Context, trace.Span) {
var psc, sc trace.SpanContext
sampled := true
span := new(span)
// Ask eBPF for sampling decision and span context info.
t.start(ctx, span, &psc, &sampled, &span.spanContext)
t.start(ctx, span, &psc, &sampled, &sc)
span.sampled.Store(sampled)
span.spanContext = sc
ctx = trace.ContextWithSpan(ctx, span)
@@ -58,7 +64,13 @@ func (t *tracer) start(
// start is used for testing.
var start = func(context.Context, *span, *trace.SpanContext, *bool, *trace.SpanContext) {}
func (t tracer) traces(name string, cfg trace.SpanConfig, sc, psc trace.SpanContext) (*telemetry.Traces, *telemetry.Span) {
var intToUint32Bound = min(math.MaxInt, math.MaxUint32)
func (t tracer) traces(
name string,
cfg trace.SpanConfig,
sc, psc trace.SpanContext,
) (*telemetry.Traces, *telemetry.Span) {
span := &telemetry.Span{
TraceID: telemetry.TraceID(sc.TraceID()),
SpanID: telemetry.SpanID(sc.SpanID()),
@@ -73,11 +85,16 @@ func (t tracer) traces(name string, cfg trace.SpanConfig, sc, psc trace.SpanCont
links := cfg.Links()
if limit := maxSpan.Links; limit == 0 {
span.DroppedLinks = uint32(len(links))
n := len(links)
if n > 0 {
bounded := max(min(n, intToUint32Bound), 0)
span.DroppedLinks = uint32(bounded) //nolint:gosec // Bounds checked.
}
} else {
if limit > 0 {
n := max(len(links)-limit, 0)
span.DroppedLinks = uint32(n)
bounded := min(n, intToUint32Bound)
span.DroppedLinks = uint32(bounded) //nolint:gosec // Bounds checked.
links = links[n:]
}
span.Links = convLinks(links)

3
vendor/go.opentelemetry.io/otel/.clomonitor.yml generated vendored Normal file
View File

@@ -0,0 +1,3 @@
exemptions:
- check: artifacthub_badge
reason: "Artifact Hub doesn't support Go packages"

View File

@@ -7,3 +7,5 @@ ans
nam
valu
thirdparty
addOpt
observ

View File

@@ -10,6 +10,7 @@ linters:
- depguard
- errcheck
- errorlint
- gocritic
- godot
- gosec
- govet
@@ -66,8 +67,6 @@ linters:
desc: Do not use cross-module internal packages.
- pkg: go.opentelemetry.io/otel/internal/internaltest
desc: Do not use cross-module internal packages.
- pkg: go.opentelemetry.io/otel/internal/matchers
desc: Do not use cross-module internal packages.
otlp-internal:
files:
- '!**/exporters/otlp/internal/**/*.go'
@@ -88,6 +87,18 @@ linters:
deny:
- pkg: go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal
desc: Do not use cross-module internal packages.
gocritic:
disabled-checks:
- appendAssign
- commentedOutCode
- dupArg
- hugeParam
- importShadow
- preferDecodeRune
- rangeValCopy
- unnamedResult
- whyNoLint
enable-all: true
godot:
exclude:
# Exclude links.
@@ -169,7 +180,10 @@ linters:
- fmt.Print
- fmt.Printf
- fmt.Println
- name: unused-parameter
- name: unused-receiver
- name: unnecessary-stmt
- name: use-any
- name: useless-break
- name: var-declaration
- name: var-naming
@@ -183,6 +197,9 @@ linters:
- float-compare
- go-require
- require-error
usetesting:
context-background: true
context-todo: true
exclusions:
generated: lax
presets:
@@ -190,6 +207,10 @@ linters:
- legacy
- std-error-handling
rules:
- linters:
- revive
path: schema/v.*/types/.*
text: avoid meaningless package names
# TODO: Having appropriate comments for exported objects helps development,
# even for objects in internal packages. Appropriate comments for all
# exported objects should be added and this exclusion removed.
@@ -222,10 +243,6 @@ linters:
- linters:
- gosec
text: 'G402: TLS MinVersion too low.'
paths:
- third_party$
- builtin$
- examples$
issues:
max-issues-per-linter: 0
max-same-issues: 0
@@ -235,14 +252,12 @@ formatters:
- goimports
- golines
settings:
gofumpt:
extra-rules: true
goimports:
local-prefixes:
- go.opentelemetry.io
- go.opentelemetry.io/otel
golines:
max-len: 120
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$

View File

@@ -1,6 +1,13 @@
http://localhost
https://localhost
http://jaeger-collector
https://github.com/open-telemetry/opentelemetry-go/milestone/
https://github.com/open-telemetry/opentelemetry-go/projects
# Weaver model URL for semantic-conventions repository.
https?:\/\/github\.com\/open-telemetry\/semantic-conventions\/archive\/refs\/tags\/[^.]+\.zip\[[^]]+]
file:///home/runner/work/opentelemetry-go/opentelemetry-go/libraries
file:///home/runner/work/opentelemetry-go/opentelemetry-go/manual
http://4.3.2.1:78/user/123
file:///home/runner/work/opentelemetry-go/opentelemetry-go/exporters/otlp/otlptrace/otlptracegrpc/internal/observ/dns:/:4317
# URL works, but it has blocked link checkers.
https://dl.acm.org/doi/10.1145/198429.198435

View File

@@ -11,6 +11,216 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
<!-- Released section -->
<!-- Don't change this section unless doing release -->
## [1.39.0/0.61.0/0.15.0/0.0.14] 2025-12-05
### Added
- Greatly reduce the cost of recording metrics in `go.opentelemetry.io/otel/sdk/metric` using hashing for map keys. (#7175)
- Add `WithInstrumentationAttributeSet` option to `go.opentelemetry.io/otel/log`, `go.opentelemetry.io/otel/metric`, and `go.opentelemetry.io/otel/trace` packages.
This provides a concurrent-safe and performant alternative to `WithInstrumentationAttributes` by accepting a pre-constructed `attribute.Set`. (#7287)
- Add experimental observability for the Prometheus exporter in `go.opentelemetry.io/otel/exporters/prometheus`.
Check the `go.opentelemetry.io/otel/exporters/prometheus/internal/x` package documentation for more information. (#7345)
- Add experimental observability metrics in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc`. (#7353)
- Add temporality selector functions `DeltaTemporalitySelector`, `CumulativeTemporalitySelector`, `LowMemoryTemporalitySelector` to `go.opentelemetry.io/otel/sdk/metric`. (#7434)
- Add experimental observability metrics for simple log processor in `go.opentelemetry.io/otel/sdk/log`. (#7548)
- Add experimental observability metrics in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc`. (#7459)
- Add experimental observability metrics in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#7486)
- Add experimental observability metrics for simple span processor in `go.opentelemetry.io/otel/sdk/trace`. (#7374)
- Add experimental observability metrics in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. (#7512)
- Add experimental observability metrics for manual reader in `go.opentelemetry.io/otel/sdk/metric`. (#7524)
- Add experimental observability metrics for periodic reader in `go.opentelemetry.io/otel/sdk/metric`. (#7571)
- Support `OTEL_EXPORTER_OTLP_LOGS_INSECURE` and `OTEL_EXPORTER_OTLP_INSECURE` environmental variables in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. (#7608)
- Add `Enabled` method to the `Processor` interface in `go.opentelemetry.io/otel/sdk/log`.
All `Processor` implementations now include an `Enabled` method. (#7639)
- The `go.opentelemetry.io/otel/semconv/v1.38.0` package.
The package contains semantic conventions from the `v1.38.0` version of the OpenTelemetry Semantic Conventions.
See the [migration documentation](./semconv/v1.38.0/MIGRATION.md) for information on how to upgrade from `go.opentelemetry.io/otel/semconv/v1.37.0.`(#7648)
### Changed
- `Distinct` in `go.opentelemetry.io/otel/attribute` is no longer guaranteed to uniquely identify an attribute set.
Collisions between `Distinct` values for different Sets are possible with extremely high cardinality (billions of series per instrument), but are highly unlikely. (#7175)
- `WithInstrumentationAttributes` in `go.opentelemetry.io/otel/trace` synchronously de-duplicates the passed attributes instead of delegating it to the returned `TracerOption`. (#7266)
- `WithInstrumentationAttributes` in `go.opentelemetry.io/otel/meter` synchronously de-duplicates the passed attributes instead of delegating it to the returned `MeterOption`. (#7266)
- `WithInstrumentationAttributes` in `go.opentelemetry.io/otel/log` synchronously de-duplicates the passed attributes instead of delegating it to the returned `LoggerOption`. (#7266)
- Rename the `OTEL_GO_X_SELF_OBSERVABILITY` environment variable to `OTEL_GO_X_OBSERVABILITY` in `go.opentelemetry.io/otel/sdk/trace`, `go.opentelemetry.io/otel/sdk/log`, and `go.opentelemetry.io/otel/exporters/stdout/stdouttrace`. (#7302)
- Improve performance of histogram `Record` in `go.opentelemetry.io/otel/sdk/metric` when min and max are disabled using `NoMinMax`. (#7306)
- Improve error handling for dropped data during translation by using `prometheus.NewInvalidMetric` in `go.opentelemetry.io/otel/exporters/prometheus`.
⚠️ **Breaking Change:** Previously, these cases were only logged and scrapes succeeded.
Now, when translation would drop data (e.g., invalid label/value), the exporter emits a `NewInvalidMetric`, and Prometheus scrapes **fail with HTTP 500** by default.
To preserve the prior behavior (scrapes succeed while errors are logged), configure your Prometheus HTTP handler with: `promhttp.HandlerOpts{ ErrorHandling: promhttp.ContinueOnError }`. (#7363)
- Replace fnv hash with xxhash in `go.opentelemetry.io/otel/attribute` for better performance. (#7371)
- The default `TranslationStrategy` in `go.opentelemetry.io/exporters/prometheus` is changed from `otlptranslator.NoUTF8EscapingWithSuffixes` to `otlptranslator.UnderscoreEscapingWithSuffixes`. (#7421)
- Improve performance of concurrent measurements in `go.opentelemetry.io/otel/sdk/metric`. (#7427)
- Include W3C TraceFlags (bits 07) in the OTLP `Span.Flags` field in `go.opentelemetry.io/exporters/otlp/otlptrace/otlptracehttp` and `go.opentelemetry.io/exporters/otlp/otlptrace/otlptracegrpc`. (#7438)
- The `ErrorType` function in `go.opentelemetry.io/otel/semconv/v1.37.0` now handles custom error types.
If an error implements an `ErrorType() string` method, the return value of that method will be used as the error type. (#7442)
### Fixed
- Fix `WithInstrumentationAttributes` options in `go.opentelemetry.io/otel/trace`, `go.opentelemetry.io/otel/metric`, and `go.opentelemetry.io/otel/log` to properly merge attributes when passed multiple times instead of replacing them.
Attributes with duplicate keys will use the last value passed. (#7300)
- The equality of `attribute.Set` when using the `Equal` method is not affected by the user overriding the empty set pointed to by `attribute.EmptySet` in `go.opentelemetry.io/otel/attribute`. (#7357)
- Return partial OTLP export errors to the caller in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc`. (#7372)
- Return partial OTLP export errors to the caller in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. (#7372)
- Return partial OTLP export errors to the caller in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`. (#7372)
- Return partial OTLP export errors to the caller in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#7372)
- Return partial OTLP export errors to the caller in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc`. (#7372)
- Return partial OTLP export errors to the caller in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#7372)
- Fix `AddAttributes`, `SetAttributes`, `SetBody` on `Record` in `go.opentelemetry.io/otel/sdk/log` to not mutate input. (#7403)
- Do not double record measurements of `RecordSet` methods in `go.opentelemetry.io/otel/semconv/v1.37.0`. (#7655)
- Do not double record measurements of `RecordSet` methods in `go.opentelemetry.io/otel/semconv/v1.36.0`. (#7656)
### Removed
- Drop support for [Go 1.23]. (#7274)
- Remove the `FilterProcessor` interface in `go.opentelemetry.io/otel/sdk/log`.
The `Enabled` method has been added to the `Processor` interface instead.
All `Processor` implementations must now implement the `Enabled` method.
Custom processors that do not filter records can implement `Enabled` to return `true`. (#7639)
## [1.38.0/0.60.0/0.14.0/0.0.13] 2025-08-29
This release is the last to support [Go 1.23].
The next release will require at least [Go 1.24].
### Added
- Add native histogram exemplar support in `go.opentelemetry.io/otel/exporters/prometheus`. (#6772)
- Add template attribute functions to the `go.opentelmetry.io/otel/semconv/v1.34.0` package. (#6939)
- `ContainerLabel`
- `DBOperationParameter`
- `DBSystemParameter`
- `HTTPRequestHeader`
- `HTTPResponseHeader`
- `K8SCronJobAnnotation`
- `K8SCronJobLabel`
- `K8SDaemonSetAnnotation`
- `K8SDaemonSetLabel`
- `K8SDeploymentAnnotation`
- `K8SDeploymentLabel`
- `K8SJobAnnotation`
- `K8SJobLabel`
- `K8SNamespaceAnnotation`
- `K8SNamespaceLabel`
- `K8SNodeAnnotation`
- `K8SNodeLabel`
- `K8SPodAnnotation`
- `K8SPodLabel`
- `K8SReplicaSetAnnotation`
- `K8SReplicaSetLabel`
- `K8SStatefulSetAnnotation`
- `K8SStatefulSetLabel`
- `ProcessEnvironmentVariable`
- `RPCConnectRPCRequestMetadata`
- `RPCConnectRPCResponseMetadata`
- `RPCGRPCRequestMetadata`
- `RPCGRPCResponseMetadata`
- Add `ErrorType` attribute helper function to the `go.opentelmetry.io/otel/semconv/v1.34.0` package. (#6962)
- Add `WithAllowKeyDuplication` in `go.opentelemetry.io/otel/sdk/log` which can be used to disable deduplication for log records. (#6968)
- Add `WithCardinalityLimit` option to configure the cardinality limit in `go.opentelemetry.io/otel/sdk/metric`. (#6996, #7065, #7081, #7164, #7165, #7179)
- Add `Clone` method to `Record` in `go.opentelemetry.io/otel/log` that returns a copy of the record with no shared state. (#7001)
- Add experimental self-observability span and batch span processor metrics in `go.opentelemetry.io/otel/sdk/trace`.
Check the `go.opentelemetry.io/otel/sdk/trace/internal/x` package documentation for more information. (#7027, #6393, #7209)
- The `go.opentelemetry.io/otel/semconv/v1.36.0` package.
The package contains semantic conventions from the `v1.36.0` version of the OpenTelemetry Semantic Conventions.
See the [migration documentation](./semconv/v1.36.0/MIGRATION.md) for information on how to upgrade from `go.opentelemetry.io/otel/semconv/v1.34.0.`(#7032, #7041)
- Add support for configuring Prometheus name translation using `WithTranslationStrategy` option in `go.opentelemetry.io/otel/exporters/prometheus`. The current default translation strategy when UTF-8 mode is enabled is `NoUTF8EscapingWithSuffixes`, but a future release will change the default strategy to `UnderscoreEscapingWithSuffixes` for compliance with the specification. (#7111)
- Add experimental self-observability log metrics in `go.opentelemetry.io/otel/sdk/log`.
Check the `go.opentelemetry.io/otel/sdk/log/internal/x` package documentation for more information. (#7121)
- Add experimental self-observability trace exporter metrics in `go.opentelemetry.io/otel/exporters/stdout/stdouttrace`.
Check the `go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/x` package documentation for more information. (#7133)
- Support testing of [Go 1.25]. (#7187)
- The `go.opentelemetry.io/otel/semconv/v1.37.0` package.
The package contains semantic conventions from the `v1.37.0` version of the OpenTelemetry Semantic Conventions.
See the [migration documentation](./semconv/v1.37.0/MIGRATION.md) for information on how to upgrade from `go.opentelemetry.io/otel/semconv/v1.36.0.`(#7254)
### Changed
- Optimize `TraceIDFromHex` and `SpanIDFromHex` in `go.opentelemetry.io/otel/sdk/trace`. (#6791)
- Change `AssertEqual` in `go.opentelemetry.io/otel/log/logtest` to accept `TestingT` in order to support benchmarks and fuzz tests. (#6908)
- Change `DefaultExemplarReservoirProviderSelector` in `go.opentelemetry.io/otel/sdk/metric` to use `runtime.GOMAXPROCS(0)` instead of `runtime.NumCPU()` for the `FixedSizeReservoirProvider` default size. (#7094)
### Fixed
- `SetBody` method of `Record` in `go.opentelemetry.io/otel/sdk/log` now deduplicates key-value collections (`log.Value` of `log.KindMap` from `go.opentelemetry.io/otel/log`). (#7002)
- Fix `go.opentelemetry.io/otel/exporters/prometheus` to not append a suffix if it's already present in metric name. (#7088)
- Fix the `go.opentelemetry.io/otel/exporters/stdout/stdouttrace` self-observability component type and name. (#7195)
- Fix partial export count metric in `go.opentelemetry.io/otel/exporters/stdout/stdouttrace`. (#7199)
### Deprecated
- Deprecate `WithoutUnits` and `WithoutCounterSuffixes` options, preferring `WithTranslationStrategy` instead. (#7111)
- Deprecate support for `OTEL_GO_X_CARDINALITY_LIMIT` environment variable in `go.opentelemetry.io/otel/sdk/metric`. Use `WithCardinalityLimit` option instead. (#7166)
## [0.59.1] 2025-07-21
### Changed
- Retract `v0.59.0` release of `go.opentelemetry.io/otel/exporters/prometheus` module which appends incorrect unit suffixes. (#7046)
- Change `go.opentelemetry.io/otel/exporters/prometheus` to no longer deduplicate suffixes when UTF8 is enabled.
It is recommended to disable unit and counter suffixes in the exporter, and manually add suffixes if you rely on the existing behavior. (#7044)
### Fixed
- Fix `go.opentelemetry.io/otel/exporters/prometheus` to properly handle unit suffixes when the unit is in brackets.
E.g. `{spans}`. (#7044)
## [1.37.0/0.59.0/0.13.0] 2025-06-25
### Added
- The `go.opentelemetry.io/otel/semconv/v1.33.0` package.
The package contains semantic conventions from the `v1.33.0` version of the OpenTelemetry Semantic Conventions.
See the [migration documentation](./semconv/v1.33.0/MIGRATION.md) for information on how to upgrade from `go.opentelemetry.io/otel/semconv/v1.32.0.`(#6799)
- The `go.opentelemetry.io/otel/semconv/v1.34.0` package.
The package contains semantic conventions from the `v1.34.0` version of the OpenTelemetry Semantic Conventions. (#6812)
- Add metric's schema URL as `otel_scope_schema_url` label in `go.opentelemetry.io/otel/exporters/prometheus`. (#5947)
- Add metric's scope attributes as `otel_scope_[attribute]` labels in `go.opentelemetry.io/otel/exporters/prometheus`. (#5947)
- Add `EventName` to `EnabledParameters` in `go.opentelemetry.io/otel/log`. (#6825)
- Add `EventName` to `EnabledParameters` in `go.opentelemetry.io/otel/sdk/log`. (#6825)
- Changed handling of `go.opentelemetry.io/otel/exporters/prometheus` metric renaming to add unit suffixes when it doesn't match one of the pre-defined values in the unit suffix map. (#6839)
### Changed
- The semantic conventions have been upgraded from `v1.26.0` to `v1.34.0` in `go.opentelemetry.io/otel/bridge/opentracing`. (#6827)
- The semantic conventions have been upgraded from `v1.26.0` to `v1.34.0` in `go.opentelemetry.io/otel/exporters/zipkin`. (#6829)
- The semantic conventions have been upgraded from `v1.26.0` to `v1.34.0` in `go.opentelemetry.io/otel/metric`. (#6832)
- The semantic conventions have been upgraded from `v1.26.0` to `v1.34.0` in `go.opentelemetry.io/otel/sdk/resource`. (#6834)
- The semantic conventions have been upgraded from `v1.26.0` to `v1.34.0` in `go.opentelemetry.io/otel/sdk/trace`. (#6835)
- The semantic conventions have been upgraded from `v1.26.0` to `v1.34.0` in `go.opentelemetry.io/otel/trace`. (#6836)
- `Record.Resource` now returns `*resource.Resource` instead of `resource.Resource` in `go.opentelemetry.io/otel/sdk/log`. (#6864)
- Retry now shows error cause for context timeout in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc`, `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`, `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc`, `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`, `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`, `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. (#6898)
### Fixed
- Stop stripping trailing slashes from configured endpoint URL in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc`. (#6710)
- Stop stripping trailing slashes from configured endpoint URL in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#6710)
- Stop stripping trailing slashes from configured endpoint URL in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`. (#6710)
- Stop stripping trailing slashes from configured endpoint URL in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#6710)
- Validate exponential histogram scale range for Prometheus compatibility in `go.opentelemetry.io/otel/exporters/prometheus`. (#6822)
- Context cancellation during metric pipeline produce does not corrupt data in `go.opentelemetry.io/otel/sdk/metric`. (#6914)
### Removed
- `go.opentelemetry.io/otel/exporters/prometheus` no longer exports `otel_scope_info` metric. (#6770)
## [0.12.2] 2025-05-22
### Fixed
- Retract `v0.12.0` release of `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc` module that contains invalid dependencies. (#6804)
- Retract `v0.12.0` release of `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp` module that contains invalid dependencies. (#6804)
- Retract `v0.12.0` release of `go.opentelemetry.io/otel/exporters/stdout/stdoutlog` module that contains invalid dependencies. (#6804)
## [0.12.1] 2025-05-21
### Fixes
- Use the proper dependency version of `go.opentelemetry.io/otel/sdk/log/logtest` in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc`. (#6800)
- Use the proper dependency version of `go.opentelemetry.io/otel/sdk/log/logtest` in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. (#6800)
- Use the proper dependency version of `go.opentelemetry.io/otel/sdk/log/logtest` in `go.opentelemetry.io/otel/exporters/stdout/stdoutlog`. (#6800)
## [1.36.0/0.58.0/0.12.0] 2025-05-20
### Added
@@ -3288,7 +3498,13 @@ It contains api and sdk for trace and meter.
- CircleCI build CI manifest files.
- CODEOWNERS file to track owners of this project.
[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.36.0...HEAD
[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.39.0...HEAD
[1.39.0/0.61.0/0.15.0/0.0.14]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.39.0
[1.38.0/0.60.0/0.14.0/0.0.13]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.38.0
[0.59.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/exporters/prometheus/v0.59.1
[1.37.0/0.59.0/0.13.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.37.0
[0.12.2]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/log/v0.12.2
[0.12.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/log/v0.12.1
[1.36.0/0.58.0/0.12.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.36.0
[1.35.0/0.57.0/0.11.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.35.0
[1.34.0/0.56.0/0.10.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.34.0
@@ -3381,6 +3597,7 @@ It contains api and sdk for trace and meter.
<!-- Released section ended -->
[Go 1.25]: https://go.dev/doc/go1.25
[Go 1.24]: https://go.dev/doc/go1.24
[Go 1.23]: https://go.dev/doc/go1.23
[Go 1.22]: https://go.dev/doc/go1.22

View File

@@ -12,6 +12,6 @@
# https://help.github.com/en/articles/about-code-owners
#
* @MrAlias @XSAM @dashpole @pellared @dmathieu
* @MrAlias @XSAM @dashpole @pellared @dmathieu @flc1125
CODEOWNERS @MrAlias @pellared @dashpole @XSAM @dmathieu

View File

@@ -54,8 +54,8 @@ go get -d go.opentelemetry.io/otel
(This may print some warning about "build constraints exclude all Go
files", just ignore it.)
This will put the project in `${GOPATH}/src/go.opentelemetry.io/otel`. You
can alternatively use `git` directly with:
This will put the project in `${GOPATH}/src/go.opentelemetry.io/otel`.
Alternatively, you can use `git` directly with:
```sh
git clone https://github.com/open-telemetry/opentelemetry-go
@@ -65,8 +65,7 @@ git clone https://github.com/open-telemetry/opentelemetry-go
that name is a kind of a redirector to GitHub that `go get` can
understand, but `git` does not.)
This would put the project in the `opentelemetry-go` directory in
current working directory.
This will add the project as `opentelemetry-go` within the current directory.
Enter the newly created directory and add your fork as a new remote:
@@ -109,10 +108,9 @@ A PR is considered **ready to merge** when:
This is not enforced through automation, but needs to be validated by the
maintainer merging.
* The qualified approvals need to be from [Approver]s/[Maintainer]s
affiliated with different companies. Two qualified approvals from
[Approver]s or [Maintainer]s affiliated with the same company counts as a
single qualified approval.
* At least one of the qualified approvals needs to be from an
[Approver]/[Maintainer] affiliated with a different company than the author
of the PR.
* PRs introducing changes that have already been discussed and consensus
reached only need one qualified approval. The discussion and resolution
needs to be linked to the PR.
@@ -167,11 +165,11 @@ guidelines](https://opentelemetry.io/docs/specs/otel/library-guidelines).
### Focus on Capabilities, Not Structure Compliance
OpenTelemetry is an evolving specification, one where the desires and
use cases are clear, but the method to satisfy those uses cases are
use cases are clear, but the methods to satisfy those use cases are
not.
As such, Contributions should provide functionality and behavior that
conforms to the specification, but the interface and structure is
conforms to the specification, but the interface and structure are
flexible.
It is preferable to have contributions follow the idioms of the
@@ -193,6 +191,35 @@ should have `go test -bench` output in their description.
should have [`benchstat`](https://pkg.go.dev/golang.org/x/perf/cmd/benchstat)
output in their description.
## Dependencies
This project uses [Go Modules] for dependency management. All modules will use
`go.mod` to explicitly list all direct and indirect dependencies, ensuring a
clear dependency graph. The `go.sum` file for each module will be committed to
the repository and used to verify the integrity of downloaded modules,
preventing malicious tampering.
This project uses automated dependency update tools (i.e. dependabot,
renovatebot) to manage updates to dependencies. This ensures that dependencies
are kept up-to-date with the latest security patches and features and are
reviewed before being merged. If you would like to propose a change to a
dependency it should be done through a pull request that updates the `go.mod`
file and includes a description of the change.
See the [versioning and compatibility](./VERSIONING.md) policy for more details
about dependency compatibility.
[Go Modules]: https://pkg.go.dev/cmd/go#hdr-Modules__module_versions__and_more
### Environment Dependencies
This project does not partition dependencies based on the environment (i.e.
`development`, `staging`, `production`).
Only the dependencies explicitly included in the released modules have been
tested and verified to work with the released code. No other guarantee is made
about the compatibility of other dependencies.
## Documentation
Each (non-internal, non-test) package must be documented using
@@ -234,6 +261,10 @@ For a non-comprehensive but foundational overview of these best practices
the [Effective Go](https://golang.org/doc/effective_go.html) documentation
is an excellent starting place.
We also recommend following the
[Go Code Review Comments](https://go.dev/wiki/CodeReviewComments)
that collects common comments made during reviews of Go code.
As a convenience for developers building this project the `make precommit`
will format, lint, validate, and in some cases fix the changes you plan to
submit. This check will need to pass for your changes to be able to be
@@ -587,6 +618,10 @@ See also:
### Testing
We allow using [`testify`](https://github.com/stretchr/testify) even though
it is seen as non-idiomatic according to
the [Go Test Comments](https://go.dev/wiki/TestComments#assert-libraries) page.
The tests should never leak goroutines.
Use the term `ConcurrentSafe` in the test name when it aims to verify the
@@ -599,8 +634,8 @@ is not in their root name.
The use of internal packages should be scoped to a single module. A sub-module
should never import from a parent internal package. This creates a coupling
between the two modules where a user can upgrade the parent without the child
and if the internal package API has changed it will fail to upgrade[^3].
between the two modules where a user can upgrade the parent without the child,
and if the internal package API has changed, it will fail to upgrade[^3].
There are two known exceptions to this rule:
@@ -621,7 +656,7 @@ this.
### Ignoring context cancellation
OpenTelemetry API implementations need to ignore the cancellation of the context that are
OpenTelemetry API implementations need to ignore the cancellation of the context that is
passed when recording a value (e.g. starting a span, recording a measurement, emitting a log).
Recording methods should not return an error describing the cancellation state of the context
when they complete, nor should they abort any work.
@@ -639,33 +674,478 @@ force flushing telemetry, shutting down a signal provider) the context cancellat
should be honored. This means all work done on behalf of the user provided context
should be canceled.
### Observability
OpenTelemetry Go SDK components should be instrumented to enable users observability for the health and performance of the telemetry pipeline itself.
This allows operators to understand how well their observability infrastructure is functioning and to identify potential issues before they impact their applications.
This section outlines the best practices for building instrumentation in OpenTelemetry Go SDK components.
#### Environment Variable Activation
Observability features are currently experimental.
They should be disabled by default and activated through the `OTEL_GO_X_OBSERVABILITY` environment variable.
This follows the established experimental feature pattern used throughout the SDK.
Components should check for this environment variable using a consistent pattern:
```go
import "go.opentelemetry.io/otel/*/internal/x"
if x.Observability.Enabled() {
// Initialize observability metrics
}
```
**References**:
- [stdouttrace exporter](./exporters/stdout/stdouttrace/internal/x/x.go)
- [sdk](./sdk/internal/x/x.go)
#### Encapsulation
Instrumentation should be encapsulated within a dedicated `struct` (e.g. `instrumentation`).
It should not be mixed into the instrumented component.
Prefer this:
```go
type SDKComponent struct {
inst *instrumentation
}
type instrumentation struct {
inflight otelconv.SDKComponentInflight
exported otelconv.SDKComponentExported
}
```
To this:
```go
// ❌ Avoid this pattern.
type SDKComponent struct {
/* other SDKComponent fields... */
inflight otelconv.SDKComponentInflight
exported otelconv.SDKComponentExported
}
```
The instrumentation code should not bloat the code being instrumented.
Likely, this means its own file, or its own package if it is complex or reused.
#### Initialization
Instrumentation setup should be explicit, side-effect free, and local to the relevant component.
Avoid relying on global or implicit [side effects][side-effect] for initialization.
Encapsulate setup in constructor functions, ensuring clear ownership and scope:
```go
import (
"errors"
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
"go.opentelemetry.io/otel/semconv/v1.37.0/otelconv"
)
type SDKComponent struct {
inst *instrumentation
}
func NewSDKComponent(config Config) (*SDKComponent, error) {
inst, err := newInstrumentation()
if err != nil {
return nil, err
}
return &SDKComponent{inst: inst}, nil
}
type instrumentation struct {
inflight otelconv.SDKComponentInflight
exported otelconv.SDKComponentExported
}
func newInstrumentation() (*instrumentation, error) {
if !x.Observability.Enabled() {
return nil, nil
}
meter := otel.GetMeterProvider().Meter(
"<component-package-name>",
metric.WithInstrumentationVersion(sdk.Version()),
metric.WithSchemaURL(semconv.SchemaURL),
)
inst := &instrumentation{}
var err, e error
inst.inflight, e = otelconv.NewSDKComponentInflight(meter)
err = errors.Join(err, e)
inst.exported, e = otelconv.NewSDKComponentExported(meter)
err = errors.Join(err, e)
return inst, err
}
```
```go
// ❌ Avoid this pattern.
func (c *Component) initObservability() {
// Initialize observability metrics
if !x.Observability.Enabled() {
return
}
// Initialize observability metrics
c.inst = &instrumentation{/* ... */}
}
```
[side-effect]: https://en.wikipedia.org/wiki/Side_effect_(computer_science)
#### Performance
When observability is disabled there should be little to no overhead.
```go
func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error {
if e.inst != nil {
attrs := expensiveOperation()
e.inst.recordSpanInflight(ctx, int64(len(spans)), attrs...)
}
// Export spans...
}
```
```go
// ❌ Avoid this pattern.
func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error {
attrs := expensiveOperation()
e.inst.recordSpanInflight(ctx, int64(len(spans)), attrs...)
// Export spans...
}
func (i *instrumentation) recordSpanInflight(ctx context.Context, count int64, attrs ...attribute.KeyValue) {
if i == nil || i.inflight == nil {
return
}
i.inflight.Add(ctx, count, metric.WithAttributes(attrs...))
}
```
When observability is enabled, the instrumentation code paths should be optimized to reduce allocation and computation overhead.
##### Attribute and Option Allocation Management
Pool attribute slices and options with [`sync.Pool`] to minimize allocations in measurement calls with dynamic attributes.
```go
var (
attrPool = sync.Pool{
New: func() any {
// Pre-allocate common capacity
knownCap := 8 // Adjust based on expected usage
s := make([]attribute.KeyValue, 0, knownCap)
// Return a pointer to avoid extra allocation on Put().
return &s
},
}
addOptPool = &sync.Pool{
New: func() any {
const n = 1 // WithAttributeSet
o := make([]metric.AddOption, 0, n)
// Return a pointer to avoid extra allocation on Put().
return &o
},
}
)
func (i *instrumentation) record(ctx context.Context, value int64, baseAttrs ...attribute.KeyValue) {
attrs := attrPool.Get().(*[]attribute.KeyValue)
defer func() {
*attrs = (*attrs)[:0] // Reset.
attrPool.Put(attrs)
}()
*attrs = append(*attrs, baseAttrs...)
// Add any dynamic attributes.
*attrs = append(*attrs, semconv.OTelComponentName("exporter-1"))
addOpt := addOptPool.Get().(*[]metric.AddOption)
defer func() {
*addOpt = (*addOpt)[:0]
addOptPool.Put(addOpt)
}()
set := attribute.NewSet(*attrs...)
*addOpt = append(*addOpt, metric.WithAttributeSet(set))
i.counter.Add(ctx, value, *addOpt...)
}
```
Pools are most effective when there are many pooled objects of the same sufficiently large size, and the objects are repeatedly used.
This amortizes the cost of allocation and synchronization.
Ideally, the pools should be scoped to be used as widely as possible within the component to maximize this efficiency while still ensuring correctness.
[`sync.Pool`]: https://pkg.go.dev/sync#Pool
##### Cache common attribute sets for repeated measurements
If a static set of attributes are used for measurements and they are known at compile time, pre-compute and cache these attributes.
```go
type spanLiveSetKey struct {
sampled bool
}
var spanLiveSetCache = map[spanLiveSetKey]attribute.Set{
{true}: attribute.NewSet(
otelconv.SDKSpanLive{}.AttrSpanSamplingResult(
otelconv.SpanSamplingResultRecordAndSample,
),
),
{false}: attribute.NewSet(
otelconv.SDKSpanLive{}.AttrSpanSamplingResult(
otelconv.SpanSamplingResultRecordOnly,
),
),
}
func spanLiveSet(sampled bool) attribute.Set {
key := spanLiveSetKey{sampled: sampled}
return spanLiveSetCache[key]
}
```
##### Benchmarking
Always provide benchmarks when introducing or refactoring instrumentation.
Demonstrate the impact (allocs/op, B/op, ns/op) in enabled/disabled scenarios:
```go
func BenchmarkExportSpans(b *testing.B) {
scenarios := []struct {
name string
obsEnabled bool
}{
{"ObsDisabled", false},
{"ObsEnabled", true},
}
for _, scenario := range scenarios {
b.Run(scenario.name, func(b *testing.B) {
b.Setenv(
"OTEL_GO_X_OBSERVABILITY",
strconv.FormatBool(scenario.obsEnabled),
)
exporter := NewExporter()
spans := generateTestSpans(100)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = exporter.ExportSpans(context.Background(), spans)
}
})
}
}
```
#### Error Handling and Robustness
Errors should be reported back to the caller if possible, and partial failures should be handled as gracefully as possible.
```go
func newInstrumentation() (*instrumentation, error) {
if !x.Observability.Enabled() {
return nil, nil
}
m := otel.GetMeterProvider().Meter(/* initialize meter */)
counter, err := otelconv.NewSDKComponentCounter(m)
// Use the partially initialized counter if available.
i := &instrumentation{counter: counter}
// Return any error to the caller.
return i, err
}
```
```go
// ❌ Avoid this pattern.
func newInstrumentation() *instrumentation {
if !x.Observability.Enabled() {
return nil, nil
}
m := otel.GetMeterProvider().Meter(/* initialize meter */)
counter, err := otelconv.NewSDKComponentCounter(m)
if err != nil {
// ❌ Do not dump the error to the OTel Handler. Return it to the
// caller.
otel.Handle(err)
// ❌ Do not return nil if we can still use the partially initialized
// counter.
return nil
}
return &instrumentation{counter: counter}
}
```
If the instrumented component cannot report the error to the user, let it report the error to `otel.Handle`.
#### Context Propagation
Ensure observability measurements receive the correct context, especially for trace exemplars and distributed context:
```go
func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error {
// Use the provided context for observability measurements
e.inst.recordSpanExportStarted(ctx, len(spans))
err := e.doExport(ctx, spans)
if err != nil {
e.inst.recordSpanExportFailed(ctx, len(spans), err)
} else {
e.inst.recordSpanExportSucceeded(ctx, len(spans))
}
return err
}
```
```go
// ❌ Avoid this pattern.
func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error {
// ❌ Do not break the context propagation.
e.inst.recordSpanExportStarted(context.Background(), len(spans))
err := e.doExport(ctx, spans)
/* ... */
return err
}
```
#### Semantic Conventions Compliance
All observability metrics should follow the [OpenTelemetry Semantic Conventions for SDK metrics](https://github.com/open-telemetry/semantic-conventions/blob/1cf2476ae5e518225a766990a28a6d5602bd5a30/docs/otel/sdk-metrics.md).
Use the metric semantic conventions convenience package [otelconv](./semconv/v1.37.0/otelconv/metric.go).
##### Component Identification
Component names and types should follow [semantic convention](https://github.com/open-telemetry/semantic-conventions/blob/1cf2476ae5e518225a766990a28a6d5602bd5a30/docs/registry/attributes/otel.md#otel-component-attributes).
If a component is not a well-known type specified in the semantic conventions, use the package path scope type as a stable identifier.
```go
componentType := "go.opentelemetry.io/otel/sdk/trace.Span"
```
```go
// ❌ Do not do this.
componentType := "trace-span"
```
The component name should be a stable unique identifier for the specific instance of the component.
Use a global counter to ensure uniqueness if necessary.
```go
// Unique 0-based ID counter for component instances.
var componentIDCounter atomic.Int64
// nextID returns the next unique ID for a component.
func nextID() int64 {
return componentIDCounter.Add(1) - 1
}
// componentName returns a unique name for the component instance.
func componentName() attribute.KeyValue {
id := nextID()
name := fmt.Sprintf("%s/%d", componentType, id)
return semconv.OTelComponentName(name)
}
```
The component ID will need to be resettable for deterministic testing.
If tests are in a different package than the component being tested (i.e. a `<component package>_test` package name), use a generated `counter` internal package to manage the counter.
See [stdouttrace exporter example](./exporters/stdout/stdouttrace/internal/gen.go) for reference.
#### Testing
Use deterministic testing with isolated state:
```go
func TestObservability(t *testing.T) {
// Restore state after test to ensure this does not affect other tests.
prev := otel.GetMeterProvider()
t.Cleanup(func() { otel.SetMeterProvider(prev) })
// Isolate the meter provider for deterministic testing
reader := metric.NewManualReader()
meterProvider := metric.NewMeterProvider(metric.WithReader(reader))
otel.SetMeterProvider(meterProvider)
// Use t.Setenv to ensure environment variable is restored after test.
t.Setenv("OTEL_GO_X_OBSERVABILITY", "true")
// Reset component ID counter to ensure deterministic component names.
componentIDCounter.Store(0)
/* ... test code ... */
}
```
Test order should not affect results.
Ensure that any global state (e.g. component ID counters) is reset between tests.
## Approvers and Maintainers
### Maintainers
- [Damien Mathieu](https://github.com/dmathieu), Elastic ([GPG](https://keys.openpgp.org/search?q=5A126B972A81A6CE443E5E1B408B8E44F0873832))
- [David Ashpole](https://github.com/dashpole), Google ([GPG](https://keys.openpgp.org/search?q=C0D1BDDCAAEAE573673085F176327DA4D864DC70))
- [Robert Pająk](https://github.com/pellared), Splunk ([GPG](https://keys.openpgp.org/search?q=CDAD3A60476A3DE599AA5092E5F7C35A4DBE90C2))
- [Sam Xie](https://github.com/XSAM), Splunk ([GPG](https://keys.openpgp.org/search?q=AEA033782371ABB18EE39188B8044925D6FEEBEA))
- [Tyler Yahn](https://github.com/MrAlias), Splunk ([GPG](https://keys.openpgp.org/search?q=0x46B0F3E1A8B1BA5A))
For more information about the maintainer role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#maintainer).
### Approvers
- [Flc](https://github.com/flc1125), Independent
For more information about the approver role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#approver).
### Triagers
- [Alex Kats](https://github.com/akats7), Capital One
- [Cheng-Zhen Yang](https://github.com/scorpionknifes), Independent
### Approvers
### Maintainers
- [Damien Mathieu](https://github.com/dmathieu), Elastic
- [David Ashpole](https://github.com/dashpole), Google
- [Robert Pająk](https://github.com/pellared), Splunk
- [Sam Xie](https://github.com/XSAM), Cisco/AppDynamics
- [Tyler Yahn](https://github.com/MrAlias), Splunk
For more information about the triager role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#triager).
### Emeritus
- [Aaron Clawson](https://github.com/MadVikingGod)
- [Anthony Mirabella](https://github.com/Aneurysm9)
- [Cheng-Zhen Yang](https://github.com/scorpionknifes)
- [Chester Cheung](https://github.com/hanyuancheung)
- [Evan Torrie](https://github.com/evantorrie)
- [Gustavo Silva Paiva](https://github.com/paivagustavo)
- [Josh MacDonald](https://github.com/jmacd)
- [Liz Fong-Jones](https://github.com/lizthegrey)
For more information about the emeritus role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#emeritus-maintainerapprovertriager).
### Become an Approver or a Maintainer
See the [community membership document in OpenTelemetry community

View File

@@ -199,3 +199,33 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -34,9 +34,6 @@ $(TOOLS)/%: $(TOOLS_MOD_DIR)/go.mod | $(TOOLS)
MULTIMOD = $(TOOLS)/multimod
$(TOOLS)/multimod: PACKAGE=go.opentelemetry.io/build-tools/multimod
SEMCONVGEN = $(TOOLS)/semconvgen
$(TOOLS)/semconvgen: PACKAGE=go.opentelemetry.io/build-tools/semconvgen
CROSSLINK = $(TOOLS)/crosslink
$(TOOLS)/crosslink: PACKAGE=go.opentelemetry.io/build-tools/crosslink
@@ -71,7 +68,7 @@ GOVULNCHECK = $(TOOLS)/govulncheck
$(TOOLS)/govulncheck: PACKAGE=golang.org/x/vuln/cmd/govulncheck
.PHONY: tools
tools: $(CROSSLINK) $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(PORTO) $(SEMCONVGEN) $(VERIFYREADMES) $(MULTIMOD) $(SEMCONVKIT) $(GOTMPL) $(GORELEASE)
tools: $(CROSSLINK) $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(PORTO) $(VERIFYREADMES) $(MULTIMOD) $(SEMCONVKIT) $(GOTMPL) $(GORELEASE)
# Virtualized python tools via docker
@@ -149,11 +146,12 @@ build-tests/%:
# Tests
TEST_TARGETS := test-default test-bench test-short test-verbose test-race test-concurrent-safe
TEST_TARGETS := test-default test-bench test-short test-verbose test-race test-concurrent-safe test-fuzz
.PHONY: $(TEST_TARGETS) test
test-default test-race: ARGS=-race
test-bench: ARGS=-run=xxxxxMatchNothingxxxxx -test.benchtime=1ms -bench=.
test-short: ARGS=-short
test-fuzz: ARGS=-fuzztime=10s -fuzz
test-verbose: ARGS=-v -race
test-concurrent-safe: ARGS=-run=ConcurrentSafe -count=100 -race
test-concurrent-safe: TIMEOUT=120
@@ -284,7 +282,7 @@ semconv-generate: $(SEMCONVKIT)
docker run --rm \
-u $(DOCKER_USER) \
--env HOME=/tmp/weaver \
--mount 'type=bind,source=$(PWD)/semconv,target=/home/weaver/templates/registry/go,readonly' \
--mount 'type=bind,source=$(PWD)/semconv/templates,target=/home/weaver/templates,readonly' \
--mount 'type=bind,source=$(PWD)/semconv/${TAG},target=/home/weaver/target' \
--mount 'type=bind,source=$(HOME)/.weaver,target=/tmp/weaver/.weaver' \
$(WEAVER_IMAGE) registry generate \
@@ -293,7 +291,7 @@ semconv-generate: $(SEMCONVKIT)
--param tag=$(TAG) \
go \
/home/weaver/target
$(SEMCONVKIT) -output "$(SEMCONVPKG)/$(TAG)" -tag "$(TAG)"
$(SEMCONVKIT) -semconv "$(SEMCONVPKG)" -tag "$(TAG)"
.PHONY: gorelease
gorelease: $(OTEL_GO_MOD_DIRS:%=gorelease/%)

View File

@@ -7,6 +7,7 @@
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/open-telemetry/opentelemetry-go/badge)](https://scorecard.dev/viewer/?uri=github.com/open-telemetry/opentelemetry-go)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/9996/badge)](https://www.bestpractices.dev/projects/9996)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/opentelemetry-go.svg)](https://issues.oss-fuzz.com/issues?q=project:opentelemetry-go)
[![FOSSA Status](https://app.fossa.com/api/projects/custom%2B162%2Fgithub.com%2Fopen-telemetry%2Fopentelemetry-go.svg?type=shield&issueType=license)](https://app.fossa.com/projects/custom%2B162%2Fgithub.com%2Fopen-telemetry%2Fopentelemetry-go?ref=badge_shield&issueType=license)
[![Slack](https://img.shields.io/badge/slack-@cncf/otel--go-brightgreen.svg?logo=slack)](https://cloud-native.slack.com/archives/C01NPAXACKT)
OpenTelemetry-Go is the [Go](https://golang.org/) implementation of [OpenTelemetry](https://opentelemetry.io/).
@@ -52,20 +53,20 @@ Currently, this project supports the following environments.
| OS | Go Version | Architecture |
|----------|------------|--------------|
| Ubuntu | 1.25 | amd64 |
| Ubuntu | 1.24 | amd64 |
| Ubuntu | 1.23 | amd64 |
| Ubuntu | 1.25 | 386 |
| Ubuntu | 1.24 | 386 |
| Ubuntu | 1.23 | 386 |
| Ubuntu | 1.25 | arm64 |
| Ubuntu | 1.24 | arm64 |
| Ubuntu | 1.23 | arm64 |
| macOS 13 | 1.24 | amd64 |
| macOS 13 | 1.23 | amd64 |
| macOS | 1.25 | amd64 |
| macOS | 1.24 | amd64 |
| macOS | 1.25 | arm64 |
| macOS | 1.24 | arm64 |
| macOS | 1.23 | arm64 |
| Windows | 1.25 | amd64 |
| Windows | 1.24 | amd64 |
| Windows | 1.23 | amd64 |
| Windows | 1.25 | 386 |
| Windows | 1.24 | 386 |
| Windows | 1.23 | 386 |
While this project should work for other systems, no compatibility guarantees
are made for those systems currently.

View File

@@ -24,7 +24,7 @@ Ensure things look correct before submitting a pull request to include the addit
## Breaking changes validation
You can run `make gorelease` that runs [gorelease](https://pkg.go.dev/golang.org/x/exp/cmd/gorelease) to ensure that there are no unwanted changes done in the public API.
You can run `make gorelease` which runs [gorelease](https://pkg.go.dev/golang.org/x/exp/cmd/gorelease) to ensure that there are no unwanted changes made in the public API.
You can check/report problems with `gorelease` [here](https://golang.org/issues/26420).
@@ -62,7 +62,7 @@ Update go.mod for submodules to depend on the new release which will happen in t
```
3. Update the [Changelog](./CHANGELOG.md).
- Make sure all relevant changes for this release are included and are in language that non-contributors to the project can understand.
- Make sure all relevant changes for this release are included and are written in language that non-contributors to the project can understand.
To verify this, you can look directly at the commits since the `<last tag>`.
```
@@ -107,11 +107,50 @@ It is critical you make sure the version you push upstream is correct.
...
```
## Sign artifacts
To ensure we comply with CNCF best practices, we need to sign the release artifacts.
Download the `.tar.gz` and `.zip` archives from the [tags page](https://github.com/open-telemetry/opentelemetry-go/tags) for the new release tag.
Both archives need to be signed with your GPG key.
You can use [this script] to verify the contents of the archives before signing them.
To find your GPG key ID, run:
```terminal
gpg --list-secret-keys --keyid-format=long
```
The key ID is the 16-character string after `sec rsa4096/` (or similar).
Set environment variables and sign both artifacts:
```terminal
export VERSION="<version>" # e.g., v1.32.0
export KEY_ID="<your-gpg-key-id>"
gpg --local-user $KEY_ID --armor --detach-sign opentelemetry-go-$VERSION.tar.gz
gpg --local-user $KEY_ID --armor --detach-sign opentelemetry-go-$VERSION.zip
```
You can verify the signatures with:
```terminal
gpg --verify opentelemetry-go-$VERSION.tar.gz.asc opentelemetry-go-$VERSION.tar.gz
gpg --verify opentelemetry-go-$VERSION.zip.asc opentelemetry-go-$VERSION.zip
```
[this script]: https://github.com/MrAlias/attest-sh
## Release
Finally create a Release for the new `<new tag>` on GitHub.
The release body should include all the release notes from the Changelog for this release.
***IMPORTANT***: GitHub Releases are immutable once created.
You must upload the signed artifacts (`.tar.gz`, `.tar.gz.asc`, `.zip`, and `.zip.asc`) when creating the release, as they cannot be added or modified later.
## Post-Release
### Contrib Repository
@@ -137,14 +176,6 @@ This helps track what changes were included in each release.
Once all related issues and PRs have been added to the milestone, close the milestone.
### Demo Repository
Bump the dependencies in the following Go services:
- [`accounting`](https://github.com/open-telemetry/opentelemetry-demo/tree/main/src/accounting)
- [`checkoutservice`](https://github.com/open-telemetry/opentelemetry-demo/tree/main/src/checkout)
- [`productcatalogservice`](https://github.com/open-telemetry/opentelemetry-demo/tree/main/src/product-catalog)
### Close the `Version Release` issue
Once the todo list in the `Version Release` issue is complete, close the issue.

203
vendor/go.opentelemetry.io/otel/SECURITY-INSIGHTS.yml generated vendored Normal file
View File

@@ -0,0 +1,203 @@
header:
schema-version: "1.0.0"
expiration-date: "2026-08-04T00:00:00.000Z"
last-updated: "2025-08-04"
last-reviewed: "2025-08-04"
commit-hash: 69e81088ad40f45a0764597326722dea8f3f00a8
project-url: https://github.com/open-telemetry/opentelemetry-go
project-release: "v1.37.0"
changelog: https://github.com/open-telemetry/opentelemetry-go/blob/69e81088ad40f45a0764597326722dea8f3f00a8/CHANGELOG.md
license: https://github.com/open-telemetry/opentelemetry-go/blob/69e81088ad40f45a0764597326722dea8f3f00a8/LICENSE
project-lifecycle:
status: active
bug-fixes-only: false
core-maintainers:
- https://github.com/dmathieu
- https://github.com/dashpole
- https://github.com/pellared
- https://github.com/XSAM
- https://github.com/MrAlias
release-process: |
See https://github.com/open-telemetry/opentelemetry-go/blob/69e81088ad40f45a0764597326722dea8f3f00a8/RELEASING.md
contribution-policy:
accepts-pull-requests: true
accepts-automated-pull-requests: true
automated-tools-list:
- automated-tool: dependabot
action: allowed
comment: Automated dependency updates are accepted.
- automated-tool: renovatebot
action: allowed
comment: Automated dependency updates are accepted.
- automated-tool: opentelemetrybot
action: allowed
comment: Automated OpenTelemetry actions are accepted.
contributing-policy: https://github.com/open-telemetry/opentelemetry-go/blob/69e81088ad40f45a0764597326722dea8f3f00a8/CONTRIBUTING.md
code-of-conduct: https://github.com/open-telemetry/.github/blob/ffa15f76b65ec7bcc41f6a0b277edbb74f832206/CODE_OF_CONDUCT.md
documentation:
- https://pkg.go.dev/go.opentelemetry.io/otel
- https://opentelemetry.io/docs/instrumentation/go/
distribution-points:
- pkg:golang/go.opentelemetry.io/otel
- pkg:golang/go.opentelemetry.io/otel/bridge/opencensus
- pkg:golang/go.opentelemetry.io/otel/bridge/opencensus/test
- pkg:golang/go.opentelemetry.io/otel/bridge/opentracing
- pkg:golang/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc
- pkg:golang/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp
- pkg:golang/go.opentelemetry.io/otel/exporters/otlp/otlptrace
- pkg:golang/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc
- pkg:golang/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
- pkg:golang/go.opentelemetry.io/otel/exporters/stdout/stdoutmetric
- pkg:golang/go.opentelemetry.io/otel/exporters/stdout/stdouttrace
- pkg:golang/go.opentelemetry.io/otel/exporters/zipkin
- pkg:golang/go.opentelemetry.io/otel/metric
- pkg:golang/go.opentelemetry.io/otel/sdk
- pkg:golang/go.opentelemetry.io/otel/sdk/metric
- pkg:golang/go.opentelemetry.io/otel/trace
- pkg:golang/go.opentelemetry.io/otel/exporters/prometheus
- pkg:golang/go.opentelemetry.io/otel/log
- pkg:golang/go.opentelemetry.io/otel/log/logtest
- pkg:golang/go.opentelemetry.io/otel/sdk/log
- pkg:golang/go.opentelemetry.io/otel/sdk/log/logtest
- pkg:golang/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc
- pkg:golang/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp
- pkg:golang/go.opentelemetry.io/otel/exporters/stdout/stdoutlog
- pkg:golang/go.opentelemetry.io/otel/schema
security-artifacts:
threat-model:
threat-model-created: false
comment: |
No formal threat model created yet.
self-assessment:
self-assessment-created: false
comment: |
No formal self-assessment yet.
security-testing:
- tool-type: sca
tool-name: Dependabot
tool-version: latest
tool-url: https://github.com/dependabot
tool-rulesets:
- built-in
integration:
ad-hoc: false
ci: true
before-release: true
comment: |
Automated dependency updates.
- tool-type: sast
tool-name: golangci-lint
tool-version: latest
tool-url: https://github.com/golangci/golangci-lint
tool-rulesets:
- built-in
integration:
ad-hoc: false
ci: true
before-release: true
comment: |
Static analysis in CI.
- tool-type: fuzzing
tool-name: OSS-Fuzz
tool-version: latest
tool-url: https://github.com/google/oss-fuzz
tool-rulesets:
- default
integration:
ad-hoc: false
ci: false
before-release: false
comment: |
OpenTelemetry Go is integrated with OSS-Fuzz for continuous fuzz testing. See https://github.com/google/oss-fuzz/tree/f0f9b221190c6063a773bea606d192ebfc3d00cf/projects/opentelemetry-go for more details.
- tool-type: sast
tool-name: CodeQL
tool-version: latest
tool-url: https://github.com/github/codeql
tool-rulesets:
- default
integration:
ad-hoc: false
ci: true
before-release: true
comment: |
CodeQL static analysis is run in CI for all commits and pull requests to detect security vulnerabilities in the Go source code. See https://github.com/open-telemetry/opentelemetry-go/blob/d5b5b059849720144a03ca5c87561bfbdb940119/.github/workflows/codeql-analysis.yml for workflow details.
- tool-type: sca
tool-name: govulncheck
tool-version: latest
tool-url: https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck
tool-rulesets:
- default
integration:
ad-hoc: false
ci: true
before-release: true
comment: |
govulncheck is run in CI to detect known vulnerabilities in Go modules and code paths. See https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/.github/workflows/ci.yml for workflow configuration.
security-assessments:
- auditor-name: 7ASecurity
auditor-url: https://7asecurity.com
auditor-report: https://7asecurity.com/reports/pentest-report-opentelemetry.pdf
report-year: 2023
comment: |
This independent penetration test by 7ASecurity covered OpenTelemetry repositories including opentelemetry-go. The assessment focused on codebase review, threat modeling, and vulnerability identification. See the report for details of findings and recommendations applicable to opentelemetry-go. No critical vulnerabilities were found for this repository.
security-contacts:
- type: email
value: cncf-opentelemetry-security@lists.cncf.io
primary: true
- type: website
value: https://github.com/open-telemetry/opentelemetry-go/security/policy
primary: false
vulnerability-reporting:
accepts-vulnerability-reports: true
email-contact: cncf-opentelemetry-security@lists.cncf.io
security-policy: https://github.com/open-telemetry/opentelemetry-go/security/policy
comment: |
Security issues should be reported via email or GitHub security policy page.
dependencies:
third-party-packages: true
dependencies-lists:
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/bridge/opencensus/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/bridge/opencensus/test/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/bridge/opentracing/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/otlp/otlplog/otlploggrpc/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/otlp/otlplog/otlploghttp/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/otlp/otlpmetric/otlpmetricgrpc/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/otlp/otlpmetric/otlpmetrichttp/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/otlp/otlptrace/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/otlp/otlptrace/otlptracegrpc/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/otlp/otlptrace/otlptracehttp/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/prometheus/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/stdout/stdoutlog/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/stdout/stdoutmetric/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/stdout/stdouttrace/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/exporters/zipkin/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/internal/tools/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/log/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/log/logtest/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/metric/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/schema/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/sdk/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/sdk/log/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/sdk/log/logtest/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/sdk/metric/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/trace/go.mod
- https://github.com/open-telemetry/opentelemetry-go/blob/v1.37.0/trace/internal/telemetry/test/go.mod
dependencies-lifecycle:
policy-url: https://github.com/open-telemetry/opentelemetry-go/blob/69e81088ad40f45a0764597326722dea8f3f00a8/CONTRIBUTING.md
comment: |
Dependency lifecycle managed via go.mod and renovatebot.
env-dependencies-policy:
policy-url: https://github.com/open-telemetry/opentelemetry-go/blob/69e81088ad40f45a0764597326722dea8f3f00a8/CONTRIBUTING.md
comment: |
See contributing policy for environment usage.

View File

@@ -83,7 +83,7 @@ is designed so the following goals can be achieved.
in either the module path or the import path.
* In addition to public APIs, telemetry produced by stable instrumentation
will remain stable and backwards compatible. This is to avoid breaking
alerts and dashboard.
alerts and dashboards.
* Modules will be used to encapsulate instrumentation, detectors, exporters,
propagators, and any other independent sets of related components.
* Experimental modules still under active development will be versioned at

View File

@@ -16,7 +16,7 @@ type (
// set into a wire representation.
Encoder interface {
// Encode returns the serialized encoding of the attribute set using
// its Iterator. This result may be cached by a attribute.Set.
// its Iterator. This result may be cached by an attribute.Set.
Encode(iterator Iterator) string
// ID returns a value that is unique for each class of attribute
@@ -78,7 +78,7 @@ func DefaultEncoder() Encoder {
defaultEncoderOnce.Do(func() {
defaultEncoderInstance = &defaultAttrEncoder{
pool: sync.Pool{
New: func() interface{} {
New: func() any {
return &bytes.Buffer{}
},
},
@@ -96,11 +96,11 @@ func (d *defaultAttrEncoder) Encode(iter Iterator) string {
for iter.Next() {
i, keyValue := iter.IndexedAttribute()
if i > 0 {
_, _ = buf.WriteRune(',')
_ = buf.WriteByte(',')
}
copyAndEscape(buf, string(keyValue.Key))
_, _ = buf.WriteRune('=')
_ = buf.WriteByte('=')
if keyValue.Value.Type() == STRING {
copyAndEscape(buf, keyValue.Value.AsString())
@@ -122,14 +122,14 @@ func copyAndEscape(buf *bytes.Buffer, val string) {
for _, ch := range val {
switch ch {
case '=', ',', escapeChar:
_, _ = buf.WriteRune(escapeChar)
_ = buf.WriteByte(escapeChar)
}
_, _ = buf.WriteRune(ch)
}
}
// Valid returns true if this encoder ID was allocated by
// `NewEncoderID`. Invalid encoder IDs will not be cached.
// Valid reports whether this encoder ID was allocated by
// [NewEncoderID]. Invalid encoder IDs will not be cached.
func (id EncoderID) Valid() bool {
return id.value != 0
}

View File

@@ -15,8 +15,8 @@ type Filter func(KeyValue) bool
//
// If keys is empty a deny-all filter is returned.
func NewAllowKeysFilter(keys ...Key) Filter {
if len(keys) <= 0 {
return func(kv KeyValue) bool { return false }
if len(keys) == 0 {
return func(KeyValue) bool { return false }
}
allowed := make(map[Key]struct{}, len(keys))
@@ -34,8 +34,8 @@ func NewAllowKeysFilter(keys ...Key) Filter {
//
// If keys is empty an allow-all filter is returned.
func NewDenyKeysFilter(keys ...Key) Filter {
if len(keys) <= 0 {
return func(kv KeyValue) bool { return true }
if len(keys) == 0 {
return func(KeyValue) bool { return true }
}
forbid := make(map[Key]struct{}, len(keys))

92
vendor/go.opentelemetry.io/otel/attribute/hash.go generated vendored Normal file
View File

@@ -0,0 +1,92 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package attribute // import "go.opentelemetry.io/otel/attribute"
import (
"fmt"
"reflect"
"go.opentelemetry.io/otel/attribute/internal/xxhash"
)
// Type identifiers. These identifiers are hashed before the value of the
// corresponding type. This is done to distinguish values that are hashed with
// the same value representation (e.g. `int64(1)` and `true`, []int64{0} and
// int64(0)).
//
// These are all 8 byte length strings converted to a uint64 representation. A
// uint64 is used instead of the string directly as an optimization, it avoids
// the for loop in [xxhash] which adds minor overhead.
const (
boolID uint64 = 7953749933313450591 // "_boolean" (little endian)
int64ID uint64 = 7592915492740740150 // "64_bit_i" (little endian)
float64ID uint64 = 7376742710626956342 // "64_bit_f" (little endian)
stringID uint64 = 6874584755375207263 // "_string_" (little endian)
boolSliceID uint64 = 6875993255270243167 // "_[]bool_" (little endian)
int64SliceID uint64 = 3762322556277578591 // "_[]int64" (little endian)
float64SliceID uint64 = 7308324551835016539 // "[]double" (little endian)
stringSliceID uint64 = 7453010373645655387 // "[]string" (little endian)
)
// hashKVs returns a new xxHash64 hash of kvs.
func hashKVs(kvs []KeyValue) uint64 {
h := xxhash.New()
for _, kv := range kvs {
h = hashKV(h, kv)
}
return h.Sum64()
}
// hashKV returns the xxHash64 hash of kv with h as the base.
func hashKV(h xxhash.Hash, kv KeyValue) xxhash.Hash {
h = h.String(string(kv.Key))
switch kv.Value.Type() {
case BOOL:
h = h.Uint64(boolID)
h = h.Uint64(kv.Value.numeric)
case INT64:
h = h.Uint64(int64ID)
h = h.Uint64(kv.Value.numeric)
case FLOAT64:
h = h.Uint64(float64ID)
// Assumes numeric stored with math.Float64bits.
h = h.Uint64(kv.Value.numeric)
case STRING:
h = h.Uint64(stringID)
h = h.String(kv.Value.stringly)
case BOOLSLICE:
h = h.Uint64(boolSliceID)
rv := reflect.ValueOf(kv.Value.slice)
for i := 0; i < rv.Len(); i++ {
h = h.Bool(rv.Index(i).Bool())
}
case INT64SLICE:
h = h.Uint64(int64SliceID)
rv := reflect.ValueOf(kv.Value.slice)
for i := 0; i < rv.Len(); i++ {
h = h.Int64(rv.Index(i).Int())
}
case FLOAT64SLICE:
h = h.Uint64(float64SliceID)
rv := reflect.ValueOf(kv.Value.slice)
for i := 0; i < rv.Len(); i++ {
h = h.Float64(rv.Index(i).Float())
}
case STRINGSLICE:
h = h.Uint64(stringSliceID)
rv := reflect.ValueOf(kv.Value.slice)
for i := 0; i < rv.Len(); i++ {
h = h.String(rv.Index(i).String())
}
case INVALID:
default:
// Logging is an alternative, but using the internal logger here
// causes an import cycle so it is not done.
v := kv.Value.AsInterface()
msg := fmt.Sprintf("unknown value type: %[1]v (%[1]T)", v)
panic(msg)
}
return h
}

View File

@@ -12,7 +12,7 @@ import (
)
// BoolSliceValue converts a bool slice into an array with same elements as slice.
func BoolSliceValue(v []bool) interface{} {
func BoolSliceValue(v []bool) any {
var zero bool
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))).Elem()
reflect.Copy(cp, reflect.ValueOf(v))
@@ -20,7 +20,7 @@ func BoolSliceValue(v []bool) interface{} {
}
// Int64SliceValue converts an int64 slice into an array with same elements as slice.
func Int64SliceValue(v []int64) interface{} {
func Int64SliceValue(v []int64) any {
var zero int64
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))).Elem()
reflect.Copy(cp, reflect.ValueOf(v))
@@ -28,7 +28,7 @@ func Int64SliceValue(v []int64) interface{} {
}
// Float64SliceValue converts a float64 slice into an array with same elements as slice.
func Float64SliceValue(v []float64) interface{} {
func Float64SliceValue(v []float64) any {
var zero float64
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))).Elem()
reflect.Copy(cp, reflect.ValueOf(v))
@@ -36,7 +36,7 @@ func Float64SliceValue(v []float64) interface{} {
}
// StringSliceValue converts a string slice into an array with same elements as slice.
func StringSliceValue(v []string) interface{} {
func StringSliceValue(v []string) any {
var zero string
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))).Elem()
reflect.Copy(cp, reflect.ValueOf(v))
@@ -44,7 +44,7 @@ func StringSliceValue(v []string) interface{} {
}
// AsBoolSlice converts a bool array into a slice into with same elements as array.
func AsBoolSlice(v interface{}) []bool {
func AsBoolSlice(v any) []bool {
rv := reflect.ValueOf(v)
if rv.Type().Kind() != reflect.Array {
return nil
@@ -57,7 +57,7 @@ func AsBoolSlice(v interface{}) []bool {
}
// AsInt64Slice converts an int64 array into a slice into with same elements as array.
func AsInt64Slice(v interface{}) []int64 {
func AsInt64Slice(v any) []int64 {
rv := reflect.ValueOf(v)
if rv.Type().Kind() != reflect.Array {
return nil
@@ -70,7 +70,7 @@ func AsInt64Slice(v interface{}) []int64 {
}
// AsFloat64Slice converts a float64 array into a slice into with same elements as array.
func AsFloat64Slice(v interface{}) []float64 {
func AsFloat64Slice(v any) []float64 {
rv := reflect.ValueOf(v)
if rv.Type().Kind() != reflect.Array {
return nil
@@ -83,7 +83,7 @@ func AsFloat64Slice(v interface{}) []float64 {
}
// AsStringSlice converts a string array into a slice into with same elements as array.
func AsStringSlice(v interface{}) []string {
func AsStringSlice(v any) []string {
rv := reflect.ValueOf(v)
if rv.Type().Kind() != reflect.Array {
return nil

View File

@@ -0,0 +1,64 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
// Package xxhash provides a wrapper around the xxhash library for attribute hashing.
package xxhash // import "go.opentelemetry.io/otel/attribute/internal/xxhash"
import (
"encoding/binary"
"math"
"github.com/cespare/xxhash/v2"
)
// Hash wraps xxhash.Digest to provide an API friendly for hashing attribute values.
type Hash struct {
d *xxhash.Digest
}
// New returns a new initialized xxHash64 hasher.
func New() Hash {
return Hash{d: xxhash.New()}
}
func (h Hash) Uint64(val uint64) Hash {
var buf [8]byte
binary.LittleEndian.PutUint64(buf[:], val)
// errors from Write are always nil for xxhash
// if it returns an err then panic
_, err := h.d.Write(buf[:])
if err != nil {
panic("xxhash write of uint64 failed: " + err.Error())
}
return h
}
func (h Hash) Bool(val bool) Hash { // nolint:revive // This is a hashing function.
if val {
return h.Uint64(1)
}
return h.Uint64(0)
}
func (h Hash) Float64(val float64) Hash {
return h.Uint64(math.Float64bits(val))
}
func (h Hash) Int64(val int64) Hash {
return h.Uint64(uint64(val)) // nolint:gosec // Overflow doesn't matter since we are hashing.
}
func (h Hash) String(val string) Hash {
// errors from WriteString are always nil for xxhash
// if it returns an err then panic
_, err := h.d.WriteString(val)
if err != nil {
panic("xxhash write of string failed: " + err.Error())
}
return h
}
// Sum64 returns the current hash value.
func (h Hash) Sum64() uint64 {
return h.d.Sum64()
}

View File

@@ -25,8 +25,8 @@ type oneIterator struct {
attr KeyValue
}
// Next moves the iterator to the next position. Returns false if there are no
// more attributes.
// Next moves the iterator to the next position.
// Next reports whether there are more attributes.
func (i *Iterator) Next() bool {
i.idx++
return i.idx < i.Len()
@@ -106,7 +106,8 @@ func (oi *oneIterator) advance() {
}
}
// Next returns true if there is another attribute available.
// Next moves the iterator to the next position.
// Next reports whether there is another attribute available.
func (m *MergeIterator) Next() bool {
if m.one.done && m.two.done {
return false

View File

@@ -117,7 +117,7 @@ func (k Key) StringSlice(v []string) KeyValue {
}
}
// Defined returns true for non-empty keys.
// Defined reports whether the key is not empty.
func (k Key) Defined() bool {
return len(k) != 0
}

View File

@@ -13,7 +13,7 @@ type KeyValue struct {
Value Value
}
// Valid returns if kv is a valid OpenTelemetry attribute.
// Valid reports whether kv is a valid OpenTelemetry attribute.
func (kv KeyValue) Valid() bool {
return kv.Key.Defined() && kv.Value.Type() != INVALID
}

View File

@@ -9,6 +9,8 @@ import (
"reflect"
"slices"
"sort"
"go.opentelemetry.io/otel/attribute/internal/xxhash"
)
type (
@@ -23,19 +25,19 @@ type (
// the Equals method to ensure stable equivalence checking.
//
// Users should also use the Distinct returned from Equivalent as a map key
// instead of a Set directly. In addition to that type providing guarantees
// on stable equivalence, it may also provide performance improvements.
// instead of a Set directly. Set has relatively poor performance when used
// as a map key compared to Distinct.
Set struct {
equivalent Distinct
hash uint64
data any
}
// Distinct is a unique identifier of a Set.
// Distinct is an identifier of a Set which is very likely to be unique.
//
// Distinct is designed to be ensures equivalence stability: comparisons
// will return the save value across versions. For this reason, Distinct
// should always be used as a map key instead of a Set.
// Distinct should be used as a map key instead of a Set for to provide better
// performance for map operations.
Distinct struct {
iface interface{}
hash uint64
}
// Sortable implements sort.Interface, used for sorting KeyValue.
@@ -46,15 +48,34 @@ type (
Sortable []KeyValue
)
// Compile time check these types remain comparable.
var (
_ = isComparable(Set{})
_ = isComparable(Distinct{})
)
func isComparable[T comparable](t T) T { return t }
var (
// keyValueType is used in computeDistinctReflect.
keyValueType = reflect.TypeOf(KeyValue{})
// emptySet is returned for empty attribute sets.
emptySet = &Set{
equivalent: Distinct{
iface: [0]KeyValue{},
},
// emptyHash is the hash of an empty set.
emptyHash = xxhash.New().Sum64()
// userDefinedEmptySet is an empty set. It was mistakenly exposed to users
// as something they can assign to, so it must remain addressable and
// mutable.
//
// This is kept for backwards compatibility, but should not be used in new code.
userDefinedEmptySet = &Set{
hash: emptyHash,
data: [0]KeyValue{},
}
emptySet = Set{
hash: emptyHash,
data: [0]KeyValue{},
}
)
@@ -62,33 +83,35 @@ var (
//
// This is a convenience provided for optimized calling utility.
func EmptySet() *Set {
return emptySet
// Continue to return the pointer to the user-defined empty set for
// backwards-compatibility.
//
// New code should not use this, instead use emptySet.
return userDefinedEmptySet
}
// Valid reports whether this value refers to a valid Set.
func (d Distinct) Valid() bool { return d.hash != 0 }
// reflectValue abbreviates reflect.ValueOf(d).
func (d Distinct) reflectValue() reflect.Value {
return reflect.ValueOf(d.iface)
}
// Valid returns true if this value refers to a valid Set.
func (d Distinct) Valid() bool {
return d.iface != nil
func (l Set) reflectValue() reflect.Value {
return reflect.ValueOf(l.data)
}
// Len returns the number of attributes in this set.
func (l *Set) Len() int {
if l == nil || !l.equivalent.Valid() {
if l == nil || l.hash == 0 {
return 0
}
return l.equivalent.reflectValue().Len()
return l.reflectValue().Len()
}
// Get returns the KeyValue at ordered position idx in this set.
func (l *Set) Get(idx int) (KeyValue, bool) {
if l == nil || !l.equivalent.Valid() {
if l == nil || l.hash == 0 {
return KeyValue{}, false
}
value := l.equivalent.reflectValue()
value := l.reflectValue()
if idx >= 0 && idx < value.Len() {
// Note: The Go compiler successfully avoids an allocation for
@@ -101,10 +124,10 @@ func (l *Set) Get(idx int) (KeyValue, bool) {
// Value returns the value of a specified key in this set.
func (l *Set) Value(k Key) (Value, bool) {
if l == nil || !l.equivalent.Valid() {
if l == nil || l.hash == 0 {
return Value{}, false
}
rValue := l.equivalent.reflectValue()
rValue := l.reflectValue()
vlen := rValue.Len()
idx := sort.Search(vlen, func(idx int) bool {
@@ -120,7 +143,7 @@ func (l *Set) Value(k Key) (Value, bool) {
return Value{}, false
}
// HasValue tests whether a key is defined in this set.
// HasValue reports whether a key is defined in this set.
func (l *Set) HasValue(k Key) bool {
if l == nil {
return false
@@ -144,20 +167,29 @@ func (l *Set) ToSlice() []KeyValue {
return iter.ToSlice()
}
// Equivalent returns a value that may be used as a map key. The Distinct type
// guarantees that the result will equal the equivalent. Distinct value of any
// Equivalent returns a value that may be used as a map key. Equal Distinct
// values are very likely to be equivalent attribute Sets. Distinct value of any
// attribute set with the same elements as this, where sets are made unique by
// choosing the last value in the input for any given key.
func (l *Set) Equivalent() Distinct {
if l == nil || !l.equivalent.Valid() {
return emptySet.equivalent
if l == nil || l.hash == 0 {
return Distinct{hash: emptySet.hash}
}
return l.equivalent
return Distinct{hash: l.hash}
}
// Equals returns true if the argument set is equivalent to this set.
// Equals reports whether the argument set is equivalent to this set.
func (l *Set) Equals(o *Set) bool {
return l.Equivalent() == o.Equivalent()
if l.Equivalent() != o.Equivalent() {
return false
}
if l == nil || l.hash == 0 {
l = &emptySet
}
if o == nil || o.hash == 0 {
o = &emptySet
}
return l.data == o.data
}
// Encoded returns the encoded form of this set, according to encoder.
@@ -169,12 +201,6 @@ func (l *Set) Encoded(encoder Encoder) string {
return encoder.Encode(l.Iter())
}
func empty() Set {
return Set{
equivalent: emptySet.equivalent,
}
}
// NewSet returns a new Set. See the documentation for
// NewSetWithSortableFiltered for more details.
//
@@ -204,7 +230,7 @@ func NewSetWithSortable(kvs []KeyValue, _ *Sortable) Set {
func NewSetWithFiltered(kvs []KeyValue, filter Filter) (Set, []KeyValue) {
// Check for empty set.
if len(kvs) == 0 {
return empty(), nil
return emptySet, nil
}
// Stable sort so the following de-duplication can implement
@@ -233,10 +259,10 @@ func NewSetWithFiltered(kvs []KeyValue, filter Filter) (Set, []KeyValue) {
if filter != nil {
if div := filteredToFront(kvs, filter); div != 0 {
return Set{equivalent: computeDistinct(kvs[div:])}, kvs[:div]
return newSet(kvs[div:]), kvs[:div]
}
}
return Set{equivalent: computeDistinct(kvs)}, nil
return newSet(kvs), nil
}
// NewSetWithSortableFiltered returns a new Set.
@@ -316,7 +342,7 @@ func (l *Set) Filter(re Filter) (Set, []KeyValue) {
if first == 0 {
// It is safe to assume len(slice) >= 1 given we found at least one
// attribute above that needs to be filtered out.
return Set{equivalent: computeDistinct(slice[1:])}, slice[:1]
return newSet(slice[1:]), slice[:1]
}
// Move the filtered slice[first] to the front (preserving order).
@@ -326,25 +352,24 @@ func (l *Set) Filter(re Filter) (Set, []KeyValue) {
// Do not re-evaluate re(slice[first+1:]).
div := filteredToFront(slice[1:first+1], re) + 1
return Set{equivalent: computeDistinct(slice[div:])}, slice[:div]
return newSet(slice[div:]), slice[:div]
}
// computeDistinct returns a Distinct using either the fixed- or
// reflect-oriented code path, depending on the size of the input. The input
// slice is assumed to already be sorted and de-duplicated.
func computeDistinct(kvs []KeyValue) Distinct {
iface := computeDistinctFixed(kvs)
if iface == nil {
iface = computeDistinctReflect(kvs)
// newSet returns a new set based on the sorted and uniqued kvs.
func newSet(kvs []KeyValue) Set {
s := Set{
hash: hashKVs(kvs),
data: computeDataFixed(kvs),
}
return Distinct{
iface: iface,
if s.data == nil {
s.data = computeDataReflect(kvs)
}
return s
}
// computeDistinctFixed computes a Distinct for small slices. It returns nil
// if the input is too large for this code path.
func computeDistinctFixed(kvs []KeyValue) interface{} {
// computeDataFixed computes a Set data for small slices. It returns nil if the
// input is too large for this code path.
func computeDataFixed(kvs []KeyValue) any {
switch len(kvs) {
case 1:
return [1]KeyValue(kvs)
@@ -371,9 +396,9 @@ func computeDistinctFixed(kvs []KeyValue) interface{} {
}
}
// computeDistinctReflect computes a Distinct using reflection, works for any
// size input.
func computeDistinctReflect(kvs []KeyValue) interface{} {
// computeDataReflect computes a Set data using reflection, works for any size
// input.
func computeDataReflect(kvs []KeyValue) any {
at := reflect.New(reflect.ArrayOf(len(kvs), keyValueType)).Elem()
for i, keyValue := range kvs {
*(at.Index(i).Addr().Interface().(*KeyValue)) = keyValue
@@ -383,11 +408,11 @@ func computeDistinctReflect(kvs []KeyValue) interface{} {
// MarshalJSON returns the JSON encoding of the Set.
func (l *Set) MarshalJSON() ([]byte, error) {
return json.Marshal(l.equivalent.iface)
return json.Marshal(l.data)
}
// MarshalLog is the marshaling function used by the logging system to represent this Set.
func (l Set) MarshalLog() interface{} {
func (l Set) MarshalLog() any {
kvs := make(map[string]string)
for _, kv := range l.ToSlice() {
kvs[string(kv.Key)] = kv.Value.Emit()

View File

@@ -24,8 +24,9 @@ const _Type_name = "INVALIDBOOLINT64FLOAT64STRINGBOOLSLICEINT64SLICEFLOAT64SLICE
var _Type_index = [...]uint8{0, 7, 11, 16, 23, 29, 38, 48, 60, 71}
func (i Type) String() string {
if i < 0 || i >= Type(len(_Type_index)-1) {
idx := int(i) - 0
if i < 0 || idx >= len(_Type_index)-1 {
return "Type(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Type_name[_Type_index[i]:_Type_index[i+1]]
return _Type_name[_Type_index[idx]:_Type_index[idx+1]]
}

View File

@@ -22,7 +22,7 @@ type Value struct {
vtype Type
numeric uint64
stringly string
slice interface{}
slice any
}
const (
@@ -199,8 +199,8 @@ func (v Value) asStringSlice() []string {
type unknownValueType struct{}
// AsInterface returns Value's data as interface{}.
func (v Value) AsInterface() interface{} {
// AsInterface returns Value's data as any.
func (v Value) AsInterface() any {
switch v.Type() {
case BOOL:
return v.AsBool()
@@ -262,7 +262,7 @@ func (v Value) Emit() string {
func (v Value) MarshalJSON() ([]byte, error) {
var jsonVal struct {
Type string
Value interface{}
Value any
}
jsonVal.Type = v.Type().String()
jsonVal.Value = v.AsInterface()

View File

@@ -648,7 +648,7 @@ func parsePropertyInternal(s string) (p Property, ok bool) {
// If we couldn't find any valid key character,
// it means the key is either empty or invalid.
if keyStart == keyEnd {
return
return p, ok
}
// Skip spaces after the key: " key< >= value ".
@@ -658,13 +658,13 @@ func parsePropertyInternal(s string) (p Property, ok bool) {
// A key can have no value, like: " key ".
ok = true
p.key = s[keyStart:keyEnd]
return
return p, ok
}
// If we have not reached the end and we can't find the '=' delimiter,
// it means the property is invalid.
if s[index] != keyValueDelimiter[0] {
return
return p, ok
}
// Attempting to parse the value.
@@ -690,14 +690,14 @@ func parsePropertyInternal(s string) (p Property, ok bool) {
// we have not reached the end, it means the property is
// invalid, something like: " key = value value1".
if index != len(s) {
return
return p, ok
}
// Decode a percent-encoded value.
rawVal := s[valueStart:valueEnd]
unescapeVal, err := url.PathUnescape(rawVal)
if err != nil {
return
return p, ok
}
value := replaceInvalidUTF8Sequences(len(rawVal), unescapeVal)
@@ -706,7 +706,7 @@ func parsePropertyInternal(s string) (p Property, ok bool) {
p.hasValue = true
p.value = value
return
return p, ok
}
func skipSpace(s string, offset int) int {
@@ -812,7 +812,7 @@ var safeKeyCharset = [utf8.RuneSelf]bool{
// validateBaggageName checks if the string is a valid OpenTelemetry Baggage name.
// Baggage name is a valid, non-empty UTF-8 string.
func validateBaggageName(s string) bool {
if len(s) == 0 {
if s == "" {
return false
}
@@ -828,7 +828,7 @@ func validateBaggageValue(s string) bool {
// validateKey checks if the string is a valid W3C Baggage key.
func validateKey(s string) bool {
if len(s) == 0 {
if s == "" {
return false
}

View File

@@ -67,7 +67,7 @@ func (c *Code) UnmarshalJSON(b []byte) error {
return errors.New("nil receiver passed to UnmarshalJSON")
}
var x interface{}
var x any
if err := json.Unmarshal(b, &x); err != nil {
return err
}
@@ -102,5 +102,5 @@ func (c *Code) MarshalJSON() ([]byte, error) {
if !ok {
return nil, fmt.Errorf("invalid code: %d", *c)
}
return []byte(fmt.Sprintf("%q", str)), nil
return fmt.Appendf(nil, "%q", str), nil
}

View File

@@ -1,4 +1,4 @@
# This is a renovate-friendly source of Docker images.
FROM python:3.13.3-slim-bullseye@sha256:9e3f9243e06fd68eb9519074b49878eda20ad39a855fac51aaffb741de20726e AS python
FROM otel/weaver:v0.15.0@sha256:1cf1c72eaed57dad813c2e359133b8a15bd4facf305aae5b13bdca6d3eccff56 AS weaver
FROM python:3.13.6-slim-bullseye@sha256:e98b521460ee75bca92175c16247bdf7275637a8faaeb2bcfa19d879ae5c4b9a AS python
FROM otel/weaver:v0.19.0@sha256:3d20814cef548f1d31f27f054fb4cd6a05125641a9f7cc29fc7eb234e8052cd9 AS weaver
FROM avtodev/markdown-lint:v1@sha256:6aeedc2f49138ce7a1cd0adffc1b1c0321b841dc2102408967d9301c031949ee AS markdown

View File

@@ -41,22 +41,22 @@ func GetLogger() logr.Logger {
// Info prints messages about the general state of the API or SDK.
// This should usually be less than 5 messages a minute.
func Info(msg string, keysAndValues ...interface{}) {
func Info(msg string, keysAndValues ...any) {
GetLogger().V(4).Info(msg, keysAndValues...)
}
// Error prints messages about exceptional states of the API or SDK.
func Error(err error, msg string, keysAndValues ...interface{}) {
func Error(err error, msg string, keysAndValues ...any) {
GetLogger().Error(err, msg, keysAndValues...)
}
// Debug prints messages about all internal changes in the API or SDK.
func Debug(msg string, keysAndValues ...interface{}) {
func Debug(msg string, keysAndValues ...any) {
GetLogger().V(8).Info(msg, keysAndValues...)
}
// Warn prints messages about warnings in the API or SDK.
// Not an error but is likely more important than an informational event.
func Warn(msg string, keysAndValues ...interface{}) {
func Warn(msg string, keysAndValues ...any) {
GetLogger().V(1).Info(msg, keysAndValues...)
}

View File

@@ -105,7 +105,7 @@ type delegatedInstrument interface {
setDelegate(metric.Meter)
}
// instID are the identifying properties of a instrument.
// instID are the identifying properties of an instrument.
type instID struct {
// name is the name of the stream.
name string

View File

@@ -26,6 +26,7 @@ import (
"sync/atomic"
"go.opentelemetry.io/auto/sdk"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"

View File

@@ -11,7 +11,7 @@ import (
// Meter returns a Meter from the global MeterProvider. The name must be the
// name of the library providing instrumentation. This name may be the same as
// the instrumented code only if that code provides built-in instrumentation.
// If the name is empty, then a implementation defined default name will be
// If the name is empty, then an implementation defined default name will be
// used instead.
//
// If this is called before a global MeterProvider is registered the returned

View File

@@ -199,3 +199,33 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -3,7 +3,11 @@
package metric // import "go.opentelemetry.io/otel/metric"
import "go.opentelemetry.io/otel/attribute"
import (
"slices"
"go.opentelemetry.io/otel/attribute"
)
// MeterConfig contains options for Meters.
type MeterConfig struct {
@@ -62,12 +66,38 @@ func WithInstrumentationVersion(version string) MeterOption {
})
}
// WithInstrumentationAttributes sets the instrumentation attributes.
// WithInstrumentationAttributes adds the instrumentation attributes.
//
// The passed attributes will be de-duplicated.
// This is equivalent to calling [WithInstrumentationAttributeSet] with an
// [attribute.Set] created from a clone of the passed attributes.
// [WithInstrumentationAttributeSet] is recommended for more control.
//
// If multiple [WithInstrumentationAttributes] or [WithInstrumentationAttributeSet]
// options are passed, the attributes will be merged together in the order
// they are passed. Attributes with duplicate keys will use the last value passed.
func WithInstrumentationAttributes(attr ...attribute.KeyValue) MeterOption {
set := attribute.NewSet(slices.Clone(attr)...)
return WithInstrumentationAttributeSet(set)
}
// WithInstrumentationAttributeSet adds the instrumentation attributes.
//
// If multiple [WithInstrumentationAttributes] or [WithInstrumentationAttributeSet]
// options are passed, the attributes will be merged together in the order
// they are passed. Attributes with duplicate keys will use the last value passed.
func WithInstrumentationAttributeSet(set attribute.Set) MeterOption {
if set.Len() == 0 {
return meterOptionFunc(func(config MeterConfig) MeterConfig {
return config
})
}
return meterOptionFunc(func(config MeterConfig) MeterConfig {
config.attrs = attribute.NewSet(attr...)
if config.attrs.Len() == 0 {
config.attrs = set
} else {
config.attrs = mergeSets(config.attrs, set)
}
return config
})
}

View File

@@ -20,7 +20,7 @@ type Baggage struct{}
var _ TextMapPropagator = Baggage{}
// Inject sets baggage key-values from ctx into the carrier.
func (b Baggage) Inject(ctx context.Context, carrier TextMapCarrier) {
func (Baggage) Inject(ctx context.Context, carrier TextMapCarrier) {
bStr := baggage.FromContext(ctx).String()
if bStr != "" {
carrier.Set(baggageHeader, bStr)
@@ -30,7 +30,7 @@ func (b Baggage) Inject(ctx context.Context, carrier TextMapCarrier) {
// Extract returns a copy of parent with the baggage from the carrier added.
// If carrier implements [ValuesGetter] (e.g. [HeaderCarrier]), Values is invoked
// for multiple values extraction. Otherwise, Get is called.
func (b Baggage) Extract(parent context.Context, carrier TextMapCarrier) context.Context {
func (Baggage) Extract(parent context.Context, carrier TextMapCarrier) context.Context {
if multiCarrier, ok := carrier.(ValuesGetter); ok {
return extractMultiBaggage(parent, multiCarrier)
}
@@ -38,7 +38,7 @@ func (b Baggage) Extract(parent context.Context, carrier TextMapCarrier) context
}
// Fields returns the keys who's values are set with Inject.
func (b Baggage) Fields() []string {
func (Baggage) Fields() []string {
return []string{baggageHeader}
}

View File

@@ -20,7 +20,7 @@ type TextMapCarrier interface {
// must never be done outside of a new major release.
// Set stores the key-value pair.
Set(key string, value string)
Set(key, value string)
// DO NOT CHANGE: any modification will not be backwards compatible and
// must never be done outside of a new major release.
@@ -88,7 +88,7 @@ func (hc HeaderCarrier) Values(key string) []string {
}
// Set stores the key-value pair.
func (hc HeaderCarrier) Set(key string, value string) {
func (hc HeaderCarrier) Set(key, value string) {
http.Header(hc).Set(key, value)
}

View File

@@ -36,7 +36,7 @@ var (
)
// Inject injects the trace context from ctx into carrier.
func (tc TraceContext) Inject(ctx context.Context, carrier TextMapCarrier) {
func (TraceContext) Inject(ctx context.Context, carrier TextMapCarrier) {
sc := trace.SpanContextFromContext(ctx)
if !sc.IsValid() {
return
@@ -77,7 +77,7 @@ func (tc TraceContext) Extract(ctx context.Context, carrier TextMapCarrier) cont
return trace.ContextWithRemoteSpanContext(ctx, sc)
}
func (tc TraceContext) extract(carrier TextMapCarrier) trace.SpanContext {
func (TraceContext) extract(carrier TextMapCarrier) trace.SpanContext {
h := carrier.Get(traceparentHeader)
if h == "" {
return trace.SpanContext{}
@@ -111,7 +111,7 @@ func (tc TraceContext) extract(carrier TextMapCarrier) trace.SpanContext {
}
// Clear all flags other than the trace-context supported sampling bit.
scc.TraceFlags = trace.TraceFlags(opts[0]) & trace.FlagsSampled
scc.TraceFlags = trace.TraceFlags(opts[0]) & trace.FlagsSampled // nolint:gosec // slice size already checked.
// Ignore the error returned here. Failure to parse tracestate MUST NOT
// affect the parsing of traceparent according to the W3C tracecontext
@@ -151,6 +151,6 @@ func extractPart(dst []byte, h *string, n int) bool {
}
// Fields returns the keys who's values are set with Inject.
func (tc TraceContext) Fields() []string {
func (TraceContext) Fields() []string {
return []string{traceparentHeader, tracestateHeader}
}

View File

@@ -0,0 +1,41 @@
<!-- Generated. DO NOT MODIFY. -->
# Migration from v1.36.0 to v1.37.0
The `go.opentelemetry.io/otel/semconv/v1.37.0` package should be a drop-in replacement for `go.opentelemetry.io/otel/semconv/v1.36.0` with the following exceptions.
## Removed
The following declarations have been removed.
Refer to the [OpenTelemetry Semantic Conventions documentation] for deprecation instructions.
If the type is not listed in the documentation as deprecated, it has been removed in this version due to lack of applicability or use.
If you use any of these non-deprecated declarations in your Go application, please [open an issue] describing your use-case.
- `ContainerRuntime`
- `ContainerRuntimeKey`
- `GenAIOpenAIRequestServiceTierAuto`
- `GenAIOpenAIRequestServiceTierDefault`
- `GenAIOpenAIRequestServiceTierKey`
- `GenAIOpenAIResponseServiceTier`
- `GenAIOpenAIResponseServiceTierKey`
- `GenAIOpenAIResponseSystemFingerprint`
- `GenAIOpenAIResponseSystemFingerprintKey`
- `GenAISystemAWSBedrock`
- `GenAISystemAnthropic`
- `GenAISystemAzureAIInference`
- `GenAISystemAzureAIOpenAI`
- `GenAISystemCohere`
- `GenAISystemDeepseek`
- `GenAISystemGCPGemini`
- `GenAISystemGCPGenAI`
- `GenAISystemGCPVertexAI`
- `GenAISystemGroq`
- `GenAISystemIBMWatsonxAI`
- `GenAISystemKey`
- `GenAISystemMistralAI`
- `GenAISystemOpenAI`
- `GenAISystemPerplexity`
- `GenAISystemXai`
[OpenTelemetry Semantic Conventions documentation]: https://github.com/open-telemetry/semantic-conventions
[open an issue]: https://github.com/open-telemetry/opentelemetry-go/issues/new?template=Blank+issue

View File

@@ -0,0 +1,3 @@
# Semconv v1.37.0
[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/semconv/v1.37.0)](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.37.0)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
// Package semconv implements OpenTelemetry semantic conventions.
//
// OpenTelemetry semantic conventions are agreed standardized naming
// patterns for OpenTelemetry things. This package represents the v1.37.0
// version of the OpenTelemetry semantic conventions.
package semconv // import "go.opentelemetry.io/otel/semconv/v1.37.0"

View File

@@ -0,0 +1,56 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package semconv // import "go.opentelemetry.io/otel/semconv/v1.37.0"
import (
"reflect"
"go.opentelemetry.io/otel/attribute"
)
// ErrorType returns an [attribute.KeyValue] identifying the error type of err.
//
// If err is nil, the returned attribute has the default value
// [ErrorTypeOther].
//
// If err's type has the method
//
// ErrorType() string
//
// then the returned attribute has the value of err.ErrorType(). Otherwise, the
// returned attribute has a value derived from the concrete type of err.
//
// The key of the returned attribute is [ErrorTypeKey].
func ErrorType(err error) attribute.KeyValue {
if err == nil {
return ErrorTypeOther
}
return ErrorTypeKey.String(errorType(err))
}
func errorType(err error) string {
var s string
if et, ok := err.(interface{ ErrorType() string }); ok {
// Prioritize the ErrorType method if available.
s = et.ErrorType()
}
if s == "" {
// Fallback to reflection if the ErrorType method is not supported or
// returns an empty value.
t := reflect.TypeOf(err)
pkg, name := t.PkgPath(), t.Name()
if pkg != "" && name != "" {
s = pkg + "." + name
} else {
// The type has no package path or name (predeclared, not-defined,
// or alias for a not-defined type).
//
// This is not guaranteed to be unique, but is a best effort.
s = t.String()
}
}
return s
}

View File

@@ -0,0 +1,9 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package semconv // import "go.opentelemetry.io/otel/semconv/v1.37.0"
const (
// ExceptionEventName is the name of the Span event representing an exception.
ExceptionEventName = "exception"
)

View File

@@ -0,0 +1,9 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package semconv // import "go.opentelemetry.io/otel/semconv/v1.37.0"
// SchemaURL is the schema URL that matches the version of the semantic conventions
// that this package defines. Semconv packages starting from v1.4.0 must declare
// non-empty schema URL in the form https://opentelemetry.io/schemas/<version>
const SchemaURL = "https://opentelemetry.io/schemas/1.37.0"

View File

@@ -199,3 +199,33 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--------------------------------------------------------------------------------
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -20,7 +20,7 @@ import (
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
"go.opentelemetry.io/otel/trace/embedded"
"go.opentelemetry.io/otel/trace/internal/telemetry"
)
@@ -39,7 +39,7 @@ type autoTracerProvider struct{ embedded.TracerProvider }
var _ TracerProvider = autoTracerProvider{}
func (p autoTracerProvider) Tracer(name string, opts ...TracerOption) Tracer {
func (autoTracerProvider) Tracer(name string, opts ...TracerOption) Tracer {
cfg := NewTracerConfig(opts...)
return autoTracer{
name: name,
@@ -81,7 +81,7 @@ func (t autoTracer) Start(ctx context.Context, name string, opts ...SpanStartOpt
// Expected to be implemented in eBPF.
//
//go:noinline
func (t *autoTracer) start(
func (*autoTracer) start(
ctx context.Context,
spanPtr *autoSpan,
psc *SpanContext,

View File

@@ -4,6 +4,7 @@
package trace // import "go.opentelemetry.io/otel/trace"
import (
"slices"
"time"
"go.opentelemetry.io/otel/attribute"
@@ -73,7 +74,7 @@ func (cfg *SpanConfig) Timestamp() time.Time {
return cfg.timestamp
}
// StackTrace checks whether stack trace capturing is enabled.
// StackTrace reports whether stack trace capturing is enabled.
func (cfg *SpanConfig) StackTrace() bool {
return cfg.stackTrace
}
@@ -154,7 +155,7 @@ func (cfg *EventConfig) Timestamp() time.Time {
return cfg.timestamp
}
// StackTrace checks whether stack trace capturing is enabled.
// StackTrace reports whether stack trace capturing is enabled.
func (cfg *EventConfig) StackTrace() bool {
return cfg.stackTrace
}
@@ -304,12 +305,50 @@ func WithInstrumentationVersion(version string) TracerOption {
})
}
// WithInstrumentationAttributes sets the instrumentation attributes.
// mergeSets returns the union of keys between a and b. Any duplicate keys will
// use the value associated with b.
func mergeSets(a, b attribute.Set) attribute.Set {
// NewMergeIterator uses the first value for any duplicates.
iter := attribute.NewMergeIterator(&b, &a)
merged := make([]attribute.KeyValue, 0, a.Len()+b.Len())
for iter.Next() {
merged = append(merged, iter.Attribute())
}
return attribute.NewSet(merged...)
}
// WithInstrumentationAttributes adds the instrumentation attributes.
//
// The passed attributes will be de-duplicated.
// This is equivalent to calling [WithInstrumentationAttributeSet] with an
// [attribute.Set] created from a clone of the passed attributes.
// [WithInstrumentationAttributeSet] is recommended for more control.
//
// If multiple [WithInstrumentationAttributes] or [WithInstrumentationAttributeSet]
// options are passed, the attributes will be merged together in the order
// they are passed. Attributes with duplicate keys will use the last value passed.
func WithInstrumentationAttributes(attr ...attribute.KeyValue) TracerOption {
set := attribute.NewSet(slices.Clone(attr)...)
return WithInstrumentationAttributeSet(set)
}
// WithInstrumentationAttributeSet adds the instrumentation attributes.
//
// If multiple [WithInstrumentationAttributes] or [WithInstrumentationAttributeSet]
// options are passed, the attributes will be merged together in the order
// they are passed. Attributes with duplicate keys will use the last value passed.
func WithInstrumentationAttributeSet(set attribute.Set) TracerOption {
if set.Len() == 0 {
return tracerOptionFunc(func(config TracerConfig) TracerConfig {
return config
})
}
return tracerOptionFunc(func(config TracerConfig) TracerConfig {
config.attrs = attribute.NewSet(attr...)
if config.attrs.Len() == 0 {
config.attrs = set
} else {
config.attrs = mergeSets(config.attrs, set)
}
return config
})
}

38
vendor/go.opentelemetry.io/otel/trace/hex.go generated vendored Normal file
View File

@@ -0,0 +1,38 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package trace // import "go.opentelemetry.io/otel/trace"
const (
// hexLU is a hex lookup table of the 16 lowercase hex digits.
// The character values of the string are indexed at the equivalent
// hexadecimal value they represent. This table efficiently encodes byte data
// into a string representation of hexadecimal.
hexLU = "0123456789abcdef"
// hexRev is a reverse hex lookup table for lowercase hex digits.
// The table is efficiently decodes a hexadecimal string into bytes.
// Valid hexadecimal characters are indexed at their respective values. All
// other invalid ASCII characters are represented with '\xff'.
//
// The '\xff' character is used as invalid because no valid character has
// the upper 4 bits set. Meaning, an efficient validation can be performed
// over multiple character parsing by checking these bits remain zero.
hexRev = "" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
)

View File

@@ -52,7 +52,7 @@ func Map(key string, value ...Attr) Attr {
return Attr{key, MapValue(value...)}
}
// Equal returns if a is equal to b.
// Equal reports whether a is equal to b.
func (a Attr) Equal(b Attr) bool {
return a.Key == b.Key && a.Value.Equal(b.Value)
}

View File

@@ -22,7 +22,7 @@ func (tid TraceID) String() string {
return hex.EncodeToString(tid[:])
}
// IsEmpty returns false if id contains at least one non-zero byte.
// IsEmpty reports whether the TraceID contains only zero bytes.
func (tid TraceID) IsEmpty() bool {
return tid == [traceIDSize]byte{}
}
@@ -50,7 +50,7 @@ func (sid SpanID) String() string {
return hex.EncodeToString(sid[:])
}
// IsEmpty returns true if the span ID contains at least one non-zero byte.
// IsEmpty reports whether the SpanID contains only zero bytes.
func (sid SpanID) IsEmpty() bool {
return sid == [spanIDSize]byte{}
}
@@ -82,7 +82,7 @@ func marshalJSON(id []byte) ([]byte, error) {
}
// unmarshalJSON inflates trace id from hex string, possibly enclosed in quotes.
func unmarshalJSON(dst []byte, src []byte) error {
func unmarshalJSON(dst, src []byte) error {
if l := len(src); l >= 2 && src[0] == '"' && src[l-1] == '"' {
src = src[1 : l-1]
}

View File

@@ -257,10 +257,10 @@ func (v Value) Kind() ValueKind {
}
}
// Empty returns if v does not hold any value.
// Empty reports whether v does not hold any value.
func (v Value) Empty() bool { return v.Kind() == ValueKindEmpty }
// Equal returns if v is equal to w.
// Equal reports whether v is equal to w.
func (v Value) Equal(w Value) bool {
k1 := v.Kind()
k2 := w.Kind()

View File

@@ -26,7 +26,7 @@ type noopTracerProvider struct{ embedded.TracerProvider }
var _ TracerProvider = noopTracerProvider{}
// Tracer returns noop implementation of Tracer.
func (p noopTracerProvider) Tracer(string, ...TracerOption) Tracer {
func (noopTracerProvider) Tracer(string, ...TracerOption) Tracer {
return noopTracer{}
}
@@ -37,7 +37,7 @@ var _ Tracer = noopTracer{}
// Start carries forward a non-recording Span, if one is present in the context, otherwise it
// creates a no-op Span.
func (t noopTracer) Start(ctx context.Context, name string, _ ...SpanStartOption) (context.Context, Span) {
func (noopTracer) Start(ctx context.Context, _ string, _ ...SpanStartOption) (context.Context, Span) {
span := SpanFromContext(ctx)
if _, ok := span.(nonRecordingSpan); !ok {
// span is likely already a noopSpan, but let's be sure

View File

@@ -51,7 +51,7 @@ type Tracer struct{ embedded.Tracer }
// If ctx contains a span context, the returned span will also contain that
// span context. If the span context in ctx is for a non-recording span, that
// span instance will be returned directly.
func (t Tracer) Start(ctx context.Context, _ string, _ ...trace.SpanStartOption) (context.Context, trace.Span) {
func (Tracer) Start(ctx context.Context, _ string, _ ...trace.SpanStartOption) (context.Context, trace.Span) {
span := trace.SpanFromContext(ctx)
// If the parent context contains a non-zero span context, that span

View File

@@ -66,6 +66,10 @@ type Span interface {
// SetAttributes sets kv as attributes of the Span. If a key from kv
// already exists for an attribute of the Span it will be overwritten with
// the value contained in kv.
//
// Note that adding attributes at span creation using [WithAttributes] is preferred
// to calling SetAttribute later, as samplers can only consider information
// already present during span creation.
SetAttributes(kv ...attribute.KeyValue)
// TracerProvider returns a TracerProvider that can be used to generate

View File

@@ -4,8 +4,6 @@
package trace // import "go.opentelemetry.io/otel/trace"
import (
"bytes"
"encoding/hex"
"encoding/json"
)
@@ -38,21 +36,47 @@ var (
_ json.Marshaler = nilTraceID
)
// IsValid checks whether the trace TraceID is valid. A valid trace ID does
// IsValid reports whether the trace TraceID is valid. A valid trace ID does
// not consist of zeros only.
func (t TraceID) IsValid() bool {
return !bytes.Equal(t[:], nilTraceID[:])
return t != nilTraceID
}
// MarshalJSON implements a custom marshal function to encode TraceID
// as a hex string.
func (t TraceID) MarshalJSON() ([]byte, error) {
return json.Marshal(t.String())
b := [32 + 2]byte{0: '"', 33: '"'}
h := t.hexBytes()
copy(b[1:], h[:])
return b[:], nil
}
// String returns the hex string representation form of a TraceID.
func (t TraceID) String() string {
return hex.EncodeToString(t[:])
h := t.hexBytes()
return string(h[:])
}
// hexBytes returns the hex string representation form of a TraceID.
func (t TraceID) hexBytes() [32]byte {
return [32]byte{
hexLU[t[0x0]>>4], hexLU[t[0x0]&0xf],
hexLU[t[0x1]>>4], hexLU[t[0x1]&0xf],
hexLU[t[0x2]>>4], hexLU[t[0x2]&0xf],
hexLU[t[0x3]>>4], hexLU[t[0x3]&0xf],
hexLU[t[0x4]>>4], hexLU[t[0x4]&0xf],
hexLU[t[0x5]>>4], hexLU[t[0x5]&0xf],
hexLU[t[0x6]>>4], hexLU[t[0x6]&0xf],
hexLU[t[0x7]>>4], hexLU[t[0x7]&0xf],
hexLU[t[0x8]>>4], hexLU[t[0x8]&0xf],
hexLU[t[0x9]>>4], hexLU[t[0x9]&0xf],
hexLU[t[0xa]>>4], hexLU[t[0xa]&0xf],
hexLU[t[0xb]>>4], hexLU[t[0xb]&0xf],
hexLU[t[0xc]>>4], hexLU[t[0xc]&0xf],
hexLU[t[0xd]>>4], hexLU[t[0xd]&0xf],
hexLU[t[0xe]>>4], hexLU[t[0xe]&0xf],
hexLU[t[0xf]>>4], hexLU[t[0xf]&0xf],
}
}
// SpanID is a unique identity of a span in a trace.
@@ -63,21 +87,38 @@ var (
_ json.Marshaler = nilSpanID
)
// IsValid checks whether the SpanID is valid. A valid SpanID does not consist
// IsValid reports whether the SpanID is valid. A valid SpanID does not consist
// of zeros only.
func (s SpanID) IsValid() bool {
return !bytes.Equal(s[:], nilSpanID[:])
return s != nilSpanID
}
// MarshalJSON implements a custom marshal function to encode SpanID
// as a hex string.
func (s SpanID) MarshalJSON() ([]byte, error) {
return json.Marshal(s.String())
b := [16 + 2]byte{0: '"', 17: '"'}
h := s.hexBytes()
copy(b[1:], h[:])
return b[:], nil
}
// String returns the hex string representation form of a SpanID.
func (s SpanID) String() string {
return hex.EncodeToString(s[:])
b := s.hexBytes()
return string(b[:])
}
func (s SpanID) hexBytes() [16]byte {
return [16]byte{
hexLU[s[0]>>4], hexLU[s[0]&0xf],
hexLU[s[1]>>4], hexLU[s[1]&0xf],
hexLU[s[2]>>4], hexLU[s[2]&0xf],
hexLU[s[3]>>4], hexLU[s[3]&0xf],
hexLU[s[4]>>4], hexLU[s[4]&0xf],
hexLU[s[5]>>4], hexLU[s[5]&0xf],
hexLU[s[6]>>4], hexLU[s[6]&0xf],
hexLU[s[7]>>4], hexLU[s[7]&0xf],
}
}
// TraceIDFromHex returns a TraceID from a hex string if it is compliant with
@@ -85,65 +126,58 @@ func (s SpanID) String() string {
// https://www.w3.org/TR/trace-context/#trace-id
// nolint:revive // revive complains about stutter of `trace.TraceIDFromHex`.
func TraceIDFromHex(h string) (TraceID, error) {
t := TraceID{}
if len(h) != 32 {
return t, errInvalidTraceIDLength
return [16]byte{}, errInvalidTraceIDLength
}
if err := decodeHex(h, t[:]); err != nil {
return t, err
var b [16]byte
invalidMark := byte(0)
for i := 0; i < len(h); i += 4 {
b[i/2] = (hexRev[h[i]] << 4) | hexRev[h[i+1]]
b[i/2+1] = (hexRev[h[i+2]] << 4) | hexRev[h[i+3]]
invalidMark |= hexRev[h[i]] | hexRev[h[i+1]] | hexRev[h[i+2]] | hexRev[h[i+3]]
}
if !t.IsValid() {
return t, errNilTraceID
// If the upper 4 bits of any byte are not zero, there was an invalid hex
// character since invalid hex characters are 0xff in hexRev.
if invalidMark&0xf0 != 0 {
return [16]byte{}, errInvalidHexID
}
return t, nil
// If we didn't set any bits, then h was all zeros.
if invalidMark == 0 {
return [16]byte{}, errNilTraceID
}
return b, nil
}
// SpanIDFromHex returns a SpanID from a hex string if it is compliant
// with the w3c trace-context specification.
// See more at https://www.w3.org/TR/trace-context/#parent-id
func SpanIDFromHex(h string) (SpanID, error) {
s := SpanID{}
if len(h) != 16 {
return s, errInvalidSpanIDLength
return [8]byte{}, errInvalidSpanIDLength
}
if err := decodeHex(h, s[:]); err != nil {
return s, err
var b [8]byte
invalidMark := byte(0)
for i := 0; i < len(h); i += 4 {
b[i/2] = (hexRev[h[i]] << 4) | hexRev[h[i+1]]
b[i/2+1] = (hexRev[h[i+2]] << 4) | hexRev[h[i+3]]
invalidMark |= hexRev[h[i]] | hexRev[h[i+1]] | hexRev[h[i+2]] | hexRev[h[i+3]]
}
if !s.IsValid() {
return s, errNilSpanID
// If the upper 4 bits of any byte are not zero, there was an invalid hex
// character since invalid hex characters are 0xff in hexRev.
if invalidMark&0xf0 != 0 {
return [8]byte{}, errInvalidHexID
}
return s, nil
}
func decodeHex(h string, b []byte) error {
for _, r := range h {
switch {
case 'a' <= r && r <= 'f':
continue
case '0' <= r && r <= '9':
continue
default:
return errInvalidHexID
}
// If we didn't set any bits, then h was all zeros.
if invalidMark == 0 {
return [8]byte{}, errNilSpanID
}
decoded, err := hex.DecodeString(h)
if err != nil {
return err
}
copy(b, decoded)
return nil
return b, nil
}
// TraceFlags contains flags that can be set on a SpanContext.
type TraceFlags byte //nolint:revive // revive complains about stutter of `trace.TraceFlags`.
// IsSampled returns if the sampling bit is set in the TraceFlags.
// IsSampled reports whether the sampling bit is set in the TraceFlags.
func (tf TraceFlags) IsSampled() bool {
return tf&FlagsSampled == FlagsSampled
}
@@ -160,12 +194,20 @@ func (tf TraceFlags) WithSampled(sampled bool) TraceFlags { // nolint:revive //
// MarshalJSON implements a custom marshal function to encode TraceFlags
// as a hex string.
func (tf TraceFlags) MarshalJSON() ([]byte, error) {
return json.Marshal(tf.String())
b := [2 + 2]byte{0: '"', 3: '"'}
h := tf.hexBytes()
copy(b[1:], h[:])
return b[:], nil
}
// String returns the hex string representation form of TraceFlags.
func (tf TraceFlags) String() string {
return hex.EncodeToString([]byte{byte(tf)}[:])
h := tf.hexBytes()
return string(h[:])
}
func (tf TraceFlags) hexBytes() [2]byte {
return [2]byte{hexLU[tf>>4], hexLU[tf&0xf]}
}
// SpanContextConfig contains mutable fields usable for constructing
@@ -201,13 +243,13 @@ type SpanContext struct {
var _ json.Marshaler = SpanContext{}
// IsValid returns if the SpanContext is valid. A valid span context has a
// IsValid reports whether the SpanContext is valid. A valid span context has a
// valid TraceID and SpanID.
func (sc SpanContext) IsValid() bool {
return sc.HasTraceID() && sc.HasSpanID()
}
// IsRemote indicates whether the SpanContext represents a remotely-created Span.
// IsRemote reports whether the SpanContext represents a remotely-created Span.
func (sc SpanContext) IsRemote() bool {
return sc.remote
}
@@ -228,7 +270,7 @@ func (sc SpanContext) TraceID() TraceID {
return sc.traceID
}
// HasTraceID checks if the SpanContext has a valid TraceID.
// HasTraceID reports whether the SpanContext has a valid TraceID.
func (sc SpanContext) HasTraceID() bool {
return sc.traceID.IsValid()
}
@@ -249,7 +291,7 @@ func (sc SpanContext) SpanID() SpanID {
return sc.spanID
}
// HasSpanID checks if the SpanContext has a valid SpanID.
// HasSpanID reports whether the SpanContext has a valid SpanID.
func (sc SpanContext) HasSpanID() bool {
return sc.spanID.IsValid()
}
@@ -270,7 +312,7 @@ func (sc SpanContext) TraceFlags() TraceFlags {
return sc.traceFlags
}
// IsSampled returns if the sampling bit is set in the SpanContext's TraceFlags.
// IsSampled reports whether the sampling bit is set in the SpanContext's TraceFlags.
func (sc SpanContext) IsSampled() bool {
return sc.traceFlags.IsSampled()
}
@@ -302,7 +344,7 @@ func (sc SpanContext) WithTraceState(state TraceState) SpanContext {
}
}
// Equal is a predicate that determines whether two SpanContext values are equal.
// Equal reports whether two SpanContext values are equal.
func (sc SpanContext) Equal(other SpanContext) bool {
return sc.traceID == other.traceID &&
sc.spanID == other.spanID &&

View File

@@ -80,7 +80,7 @@ func checkKeyRemain(key string) bool {
//
// param n is remain part length, should be 255 in simple-key or 13 in system-id.
func checkKeyPart(key string, n int) bool {
if len(key) == 0 {
if key == "" {
return false
}
first := key[0] // key's first char
@@ -102,7 +102,7 @@ func isAlphaNum(c byte) bool {
//
// param n is remain part length, should be 240 exactly.
func checkKeyTenant(key string, n int) bool {
if len(key) == 0 {
if key == "" {
return false
}
return isAlphaNum(key[0]) && len(key[1:]) <= n && checkKeyRemain(key[1:])
@@ -191,7 +191,7 @@ func ParseTraceState(ts string) (TraceState, error) {
for ts != "" {
var memberStr string
memberStr, ts, _ = strings.Cut(ts, listDelimiters)
if len(memberStr) == 0 {
if memberStr == "" {
continue
}

View File

@@ -5,5 +5,5 @@ package otel // import "go.opentelemetry.io/otel"
// Version is the current release version of OpenTelemetry in use.
func Version() string {
return "1.36.0"
return "1.39.0"
}

View File

@@ -3,13 +3,12 @@
module-sets:
stable-v1:
version: v1.36.0
version: v1.39.0
modules:
- go.opentelemetry.io/otel
- go.opentelemetry.io/otel/bridge/opencensus
- go.opentelemetry.io/otel/bridge/opencensus/test
- go.opentelemetry.io/otel/bridge/opentracing
- go.opentelemetry.io/otel/bridge/opentracing/test
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp
- go.opentelemetry.io/otel/exporters/otlp/otlptrace
@@ -23,23 +22,42 @@ module-sets:
- go.opentelemetry.io/otel/sdk/metric
- go.opentelemetry.io/otel/trace
experimental-metrics:
version: v0.58.0
version: v0.61.0
modules:
- go.opentelemetry.io/otel/exporters/prometheus
experimental-logs:
version: v0.12.0
version: v0.15.0
modules:
- go.opentelemetry.io/otel/log
- go.opentelemetry.io/otel/log/logtest
- go.opentelemetry.io/otel/sdk/log
- go.opentelemetry.io/otel/sdk/log/logtest
- go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc
- go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp
- go.opentelemetry.io/otel/exporters/stdout/stdoutlog
experimental-schema:
version: v0.0.12
version: v0.0.14
modules:
- go.opentelemetry.io/otel/schema
excluded-modules:
- go.opentelemetry.io/otel/internal/tools
- go.opentelemetry.io/otel/log/logtest
- go.opentelemetry.io/otel/sdk/log/logtest
- go.opentelemetry.io/otel/trace/internal/telemetry/test
modules:
go.opentelemetry.io/otel/exporters/stdout/stdouttrace:
version-refs:
- ./internal/version.go
go.opentelemetry.io/otel/exporters/prometheus:
version-refs:
- ./internal/version.go
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc:
version-refs:
- ./internal/version.go
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc:
version-refs:
- ./internal/version.go
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp:
version-refs:
- ./internal/version.go
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp:
version-refs:
- ./internal/version.go

View File

@@ -35,6 +35,7 @@ import (
"go.podman.io/image/v5/types"
"go.podman.io/storage/pkg/fileutils"
"go.podman.io/storage/pkg/homedir"
"golang.org/x/sync/semaphore"
)
const (
@@ -86,8 +87,19 @@ type extensionSignatureList struct {
Signatures []extensionSignature `json:"signatures"`
}
// bearerToken records a cached token we can use to authenticate.
// bearerToken records a cached token we can use to authenticate, or a pending process to obtain one.
//
// The goroutine obtaining the token holds lock to block concurrent token requests, and fills the structure (err and possibly the other fields)
// before releasing the lock.
// Other goroutines obtain lock to block on the token request, if any; and then inspect err to see if the token is usable.
// If it is not, they try to get a new one.
type bearerToken struct {
// lock is held while obtaining the token. Potentially nested inside dockerClient.tokenCacheLock.
// This is a counting semaphore only because we need a cancellable lock operation.
lock *semaphore.Weighted
// The following fields can only be accessed with lock held.
err error // nil if the token was successfully obtained (but may be expired); an error if the next lock holder _must_ obtain a new token.
token string
expirationTime time.Time
}
@@ -116,8 +128,9 @@ type dockerClient struct {
challenges []challenge
supportsSignatures bool
// Private state for setupRequestAuth (key: string, value: bearerToken)
tokenCache sync.Map
// Private state for setupRequestAuth
tokenCacheLock sync.Mutex // Protects tokenCache.
tokenCache map[string]*bearerToken
// Private state for detectProperties:
detectPropertiesOnce sync.Once // detectPropertiesOnce is used to execute detectProperties() at most once.
detectPropertiesError error // detectPropertiesError caches the initial error.
@@ -274,6 +287,7 @@ func newDockerClient(sys *types.SystemContext, registry, reference string) (*doc
registry: registry,
userAgent: userAgent,
tlsClientConfig: tlsClientConfig,
tokenCache: map[string]*bearerToken{},
reportedWarnings: set.New[string](),
}, nil
}
@@ -716,50 +730,11 @@ func (c *dockerClient) setupRequestAuth(req *http.Request, extraScope *authScope
req.SetBasicAuth(c.auth.Username, c.auth.Password)
return nil
case "bearer":
registryToken := c.registryToken
if registryToken == "" {
cacheKey := ""
scopes := []authScope{c.scope}
if extraScope != nil {
// Using ':' as a separator here is unambiguous because getBearerToken below
// uses the same separator when formatting a remote request (and because
// repository names that we create can't contain colons, and extraScope values
// coming from a server come from `parseAuthScope`, which also splits on colons).
cacheKey = fmt.Sprintf("%s:%s:%s", extraScope.resourceType, extraScope.remoteName, extraScope.actions)
if colonCount := strings.Count(cacheKey, ":"); colonCount != 2 {
return fmt.Errorf(
"Internal error: there must be exactly 2 colons in the cacheKey ('%s') but got %d",
cacheKey,
colonCount,
)
}
scopes = append(scopes, *extraScope)
}
var token bearerToken
t, inCache := c.tokenCache.Load(cacheKey)
if inCache {
token = t.(bearerToken)
}
if !inCache || time.Now().After(token.expirationTime) {
var (
t *bearerToken
err error
)
if c.auth.IdentityToken != "" {
t, err = c.getBearerTokenOAuth2(req.Context(), challenge, scopes)
} else {
t, err = c.getBearerToken(req.Context(), challenge, scopes)
}
if err != nil {
return err
}
token = *t
c.tokenCache.Store(cacheKey, token)
}
registryToken = token.token
token, err := c.obtainBearerToken(req.Context(), challenge, extraScope)
if err != nil {
return err
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", registryToken))
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
return nil
default:
logrus.Debugf("no handler for %s authentication", challenge.Scheme)
@@ -769,16 +744,94 @@ func (c *dockerClient) setupRequestAuth(req *http.Request, extraScope *authScope
return nil
}
func (c *dockerClient) getBearerTokenOAuth2(ctx context.Context, challenge challenge,
scopes []authScope) (*bearerToken, error) {
// obtainBearerToken gets an "Authorization: Bearer" token if one is available, or obtains a fresh one.
func (c *dockerClient) obtainBearerToken(ctx context.Context, challenge challenge, extraScope *authScope) (string, error) {
if c.registryToken != "" {
return c.registryToken, nil
}
cacheKey := ""
scopes := []authScope{c.scope}
if extraScope != nil {
// Using ':' as a separator here is unambiguous because getBearerToken below
// uses the same separator when formatting a remote request (and because
// repository names that we create can't contain colons, and extraScope values
// coming from a server come from `parseAuthScope`, which also splits on colons).
cacheKey = fmt.Sprintf("%s:%s:%s", extraScope.resourceType, extraScope.remoteName, extraScope.actions)
if colonCount := strings.Count(cacheKey, ":"); colonCount != 2 {
return "", fmt.Errorf(
"Internal error: there must be exactly 2 colons in the cacheKey ('%s') but got %d",
cacheKey,
colonCount,
)
}
scopes = append(scopes, *extraScope)
}
token, newEntry, err := func() (*bearerToken, bool, error) { // A scope for defer
c.tokenCacheLock.Lock()
defer c.tokenCacheLock.Unlock()
token, ok := c.tokenCache[cacheKey]
if ok {
return token, false, nil
} else {
token = &bearerToken{
lock: semaphore.NewWeighted(1),
}
// If this is a new *bearerToken, lock the entry before adding it to the cache, so that any other goroutine that finds
// this entry blocks until we obtain the token for the first time, and does not see an empty object
// (and does not try to obtain the token itself when we are going to do so).
if err := token.lock.Acquire(ctx, 1); err != nil {
// We do not block on this Acquire, so we dont really expect to fail here — but if ctx is canceled,
// there is no point in trying to continue anyway.
return nil, false, err
}
c.tokenCache[cacheKey] = token
return token, true, nil
}
}()
if err != nil {
return "", err
}
if !newEntry {
// If this is an existing *bearerToken, obtain the lock only after releasing c.tokenCacheLock,
// so that users of other cacheKey values are not blocked for the whole duration of our HTTP roundtrip.
if err := token.lock.Acquire(ctx, 1); err != nil {
return "", err
}
}
defer token.lock.Release(1)
if !newEntry && token.err == nil && !time.Now().After(token.expirationTime) {
return token.token, nil // We have a usable token already.
}
if c.auth.IdentityToken != "" {
err = c.getBearerTokenOAuth2(ctx, token, challenge, scopes)
} else {
err = c.getBearerToken(ctx, token, challenge, scopes)
}
token.err = err
if token.err != nil {
return "", token.err
}
return token.token, nil
}
// getBearerTokenOAuth2 obtains an "Authorization: Bearer" token using a pre-existing identity token per
// https://github.com/distribution/distribution/blob/main/docs/spec/auth/oauth.md for challenge and scopes,
// and writes it into dest.
func (c *dockerClient) getBearerTokenOAuth2(ctx context.Context, dest *bearerToken, challenge challenge,
scopes []authScope) error {
realm, ok := challenge.Parameters["realm"]
if !ok {
return nil, errors.New("missing realm in bearer auth challenge")
return errors.New("missing realm in bearer auth challenge")
}
authReq, err := http.NewRequestWithContext(ctx, http.MethodPost, realm, nil)
if err != nil {
return nil, err
return err
}
// Make the form data required against the oauth2 authentication
@@ -803,26 +856,29 @@ func (c *dockerClient) getBearerTokenOAuth2(ctx context.Context, challenge chall
logrus.Debugf("%s %s", authReq.Method, authReq.URL.Redacted())
res, err := c.client.Do(authReq)
if err != nil {
return nil, err
return err
}
defer res.Body.Close()
if err := httpResponseToError(res, "Trying to obtain access token"); err != nil {
return nil, err
return err
}
return newBearerTokenFromHTTPResponseBody(res)
return dest.readFromHTTPResponseBody(res)
}
func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge,
scopes []authScope) (*bearerToken, error) {
// getBearerToken obtains an "Authorization: Bearer" token using a GET request, per
// https://github.com/distribution/distribution/blob/main/docs/spec/auth/token.md for challenge and scopes,
// and writes it into dest.
func (c *dockerClient) getBearerToken(ctx context.Context, dest *bearerToken, challenge challenge,
scopes []authScope) error {
realm, ok := challenge.Parameters["realm"]
if !ok {
return nil, errors.New("missing realm in bearer auth challenge")
return errors.New("missing realm in bearer auth challenge")
}
authReq, err := http.NewRequestWithContext(ctx, http.MethodGet, realm, nil)
if err != nil {
return nil, err
return err
}
params := authReq.URL.Query()
@@ -850,22 +906,22 @@ func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge,
logrus.Debugf("%s %s", authReq.Method, authReq.URL.Redacted())
res, err := c.client.Do(authReq)
if err != nil {
return nil, err
return err
}
defer res.Body.Close()
if err := httpResponseToError(res, "Requesting bearer token"); err != nil {
return nil, err
return err
}
return newBearerTokenFromHTTPResponseBody(res)
return dest.readFromHTTPResponseBody(res)
}
// newBearerTokenFromHTTPResponseBody parses a http.Response to obtain a bearerToken.
// readFromHTTPResponseBody sets token data by parsing a http.Response.
// The caller is still responsible for ensuring res.Body is closed.
func newBearerTokenFromHTTPResponseBody(res *http.Response) (*bearerToken, error) {
func (bt *bearerToken) readFromHTTPResponseBody(res *http.Response) error {
blob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxAuthTokenBodySize)
if err != nil {
return nil, err
return err
}
var token struct {
@@ -881,12 +937,10 @@ func newBearerTokenFromHTTPResponseBody(res *http.Response) (*bearerToken, error
if len(bodySample) > bodySampleLength {
bodySample = bodySample[:bodySampleLength]
}
return nil, fmt.Errorf("decoding bearer token (last URL %q, body start %q): %w", res.Request.URL.Redacted(), string(bodySample), err)
return fmt.Errorf("decoding bearer token (last URL %q, body start %q): %w", res.Request.URL.Redacted(), string(bodySample), err)
}
bt := &bearerToken{
token: token.Token,
}
bt.token = token.Token
if bt.token == "" {
bt.token = token.AccessToken
}
@@ -899,7 +953,7 @@ func newBearerTokenFromHTTPResponseBody(res *http.Response) (*bearerToken, error
token.IssuedAt = time.Now().UTC()
}
bt.expirationTime = token.IssuedAt.Add(time.Duration(token.ExpiresIn) * time.Second)
return bt, nil
return nil
}
// detectPropertiesHelper performs the work of detectProperties which executes

View File

@@ -8,7 +8,7 @@ const (
// VersionMinor is for functionality in a backwards-compatible manner
VersionMinor = 39
// VersionPatch is for backwards-compatible bug fixes
VersionPatch = 1
VersionPatch = 2
// VersionDev indicates development branch. Releases will be empty string.
VersionDev = ""

View File

@@ -53,7 +53,7 @@ func (c *Config) hash() crypto.Hash {
func (c *Config) encodedCount() uint8 {
if c == nil || c.S2KCount == 0 {
return 96 // The common case. Correspoding to 65536
return 96 // The common case. Corresponding to 65536
}
i := c.S2KCount

View File

@@ -1,66 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package sha3 implements the SHA-3 fixed-output-length hash functions and
// the SHAKE variable-output-length hash functions defined by FIPS-202.
//
// All types in this package also implement [encoding.BinaryMarshaler],
// [encoding.BinaryAppender] and [encoding.BinaryUnmarshaler] to marshal and
// unmarshal the internal state of the hash.
//
// Both types of hash function use the "sponge" construction and the Keccak
// permutation. For a detailed specification see http://keccak.noekeon.org/
//
// # Guidance
//
// If you aren't sure what function you need, use SHAKE256 with at least 64
// bytes of output. The SHAKE instances are faster than the SHA3 instances;
// the latter have to allocate memory to conform to the hash.Hash interface.
//
// If you need a secret-key MAC (message authentication code), prepend the
// secret key to the input, hash with SHAKE256 and read at least 32 bytes of
// output.
//
// # Security strengths
//
// The SHA3-x (x equals 224, 256, 384, or 512) functions have a security
// strength against preimage attacks of x bits. Since they only produce "x"
// bits of output, their collision-resistance is only "x/2" bits.
//
// The SHAKE-256 and -128 functions have a generic security strength of 256 and
// 128 bits against all attacks, provided that at least 2x bits of their output
// is used. Requesting more than 64 or 32 bytes of output, respectively, does
// not increase the collision-resistance of the SHAKE functions.
//
// # The sponge construction
//
// A sponge builds a pseudo-random function from a public pseudo-random
// permutation, by applying the permutation to a state of "rate + capacity"
// bytes, but hiding "capacity" of the bytes.
//
// A sponge starts out with a zero state. To hash an input using a sponge, up
// to "rate" bytes of the input are XORed into the sponge's state. The sponge
// is then "full" and the permutation is applied to "empty" it. This process is
// repeated until all the input has been "absorbed". The input is then padded.
// The digest is "squeezed" from the sponge in the same way, except that output
// is copied out instead of input being XORed in.
//
// A sponge is parameterized by its generic security strength, which is equal
// to half its capacity; capacity + rate is equal to the permutation's width.
// Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means
// that the security strength of a sponge instance is equal to (1600 - bitrate) / 2.
//
// # Recommendations
//
// The SHAKE functions are recommended for most new uses. They can produce
// output of arbitrary length. SHAKE256, with an output length of at least
// 64 bytes, provides 256-bit security against all attacks. The Keccak team
// recommends it for most applications upgrading from SHA2-512. (NIST chose a
// much stronger, but much slower, sponge instance for SHA3-512.)
//
// The SHA-3 functions are "drop-in" replacements for the SHA-2 functions.
// They produce output of the same length, with the same security strengths
// against all attacks. This means, in particular, that SHA3-256 only has
// 128-bit collision resistance, because its output length is 32 bytes.
package sha3

View File

@@ -2,127 +2,94 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package sha3 implements the SHA-3 hash algorithms and the SHAKE extendable
// output functions defined in FIPS 202.
//
// Most of this package is a wrapper around the crypto/sha3 package in the
// standard library. The only exception is the legacy Keccak hash functions.
package sha3
// This file provides functions for creating instances of the SHA-3
// and SHAKE hash functions, as well as utility functions for hashing
// bytes.
import (
"crypto"
"crypto/sha3"
"hash"
)
// New224 creates a new SHA3-224 hash.
// Its generic security strength is 224 bits against preimage attacks,
// and 112 bits against collision attacks.
//
// It is a wrapper for the [sha3.New224] function in the standard library.
//
//go:fix inline
func New224() hash.Hash {
return new224()
return sha3.New224()
}
// New256 creates a new SHA3-256 hash.
// Its generic security strength is 256 bits against preimage attacks,
// and 128 bits against collision attacks.
//
// It is a wrapper for the [sha3.New256] function in the standard library.
//
//go:fix inline
func New256() hash.Hash {
return new256()
return sha3.New256()
}
// New384 creates a new SHA3-384 hash.
// Its generic security strength is 384 bits against preimage attacks,
// and 192 bits against collision attacks.
//
// It is a wrapper for the [sha3.New384] function in the standard library.
//
//go:fix inline
func New384() hash.Hash {
return new384()
return sha3.New384()
}
// New512 creates a new SHA3-512 hash.
// Its generic security strength is 512 bits against preimage attacks,
// and 256 bits against collision attacks.
//
// It is a wrapper for the [sha3.New512] function in the standard library.
//
//go:fix inline
func New512() hash.Hash {
return new512()
}
func init() {
crypto.RegisterHash(crypto.SHA3_224, New224)
crypto.RegisterHash(crypto.SHA3_256, New256)
crypto.RegisterHash(crypto.SHA3_384, New384)
crypto.RegisterHash(crypto.SHA3_512, New512)
}
const (
dsbyteSHA3 = 0b00000110
dsbyteKeccak = 0b00000001
dsbyteShake = 0b00011111
dsbyteCShake = 0b00000100
// rateK[c] is the rate in bytes for Keccak[c] where c is the capacity in
// bits. Given the sponge size is 1600 bits, the rate is 1600 - c bits.
rateK256 = (1600 - 256) / 8
rateK448 = (1600 - 448) / 8
rateK512 = (1600 - 512) / 8
rateK768 = (1600 - 768) / 8
rateK1024 = (1600 - 1024) / 8
)
func new224Generic() *state {
return &state{rate: rateK448, outputLen: 28, dsbyte: dsbyteSHA3}
}
func new256Generic() *state {
return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteSHA3}
}
func new384Generic() *state {
return &state{rate: rateK768, outputLen: 48, dsbyte: dsbyteSHA3}
}
func new512Generic() *state {
return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteSHA3}
}
// NewLegacyKeccak256 creates a new Keccak-256 hash.
//
// Only use this function if you require compatibility with an existing cryptosystem
// that uses non-standard padding. All other users should use New256 instead.
func NewLegacyKeccak256() hash.Hash {
return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteKeccak}
}
// NewLegacyKeccak512 creates a new Keccak-512 hash.
//
// Only use this function if you require compatibility with an existing cryptosystem
// that uses non-standard padding. All other users should use New512 instead.
func NewLegacyKeccak512() hash.Hash {
return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteKeccak}
return sha3.New512()
}
// Sum224 returns the SHA3-224 digest of the data.
func Sum224(data []byte) (digest [28]byte) {
h := New224()
h.Write(data)
h.Sum(digest[:0])
return
//
// It is a wrapper for the [sha3.Sum224] function in the standard library.
//
//go:fix inline
func Sum224(data []byte) [28]byte {
return sha3.Sum224(data)
}
// Sum256 returns the SHA3-256 digest of the data.
func Sum256(data []byte) (digest [32]byte) {
h := New256()
h.Write(data)
h.Sum(digest[:0])
return
//
// It is a wrapper for the [sha3.Sum256] function in the standard library.
//
//go:fix inline
func Sum256(data []byte) [32]byte {
return sha3.Sum256(data)
}
// Sum384 returns the SHA3-384 digest of the data.
func Sum384(data []byte) (digest [48]byte) {
h := New384()
h.Write(data)
h.Sum(digest[:0])
return
//
// It is a wrapper for the [sha3.Sum384] function in the standard library.
//
//go:fix inline
func Sum384(data []byte) [48]byte {
return sha3.Sum384(data)
}
// Sum512 returns the SHA3-512 digest of the data.
func Sum512(data []byte) (digest [64]byte) {
h := New512()
h.Write(data)
h.Sum(digest[:0])
return
//
// It is a wrapper for the [sha3.Sum512] function in the standard library.
//
//go:fix inline
func Sum512(data []byte) [64]byte {
return sha3.Sum512(data)
}

View File

@@ -1,23 +0,0 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !gc || purego || !s390x
package sha3
func new224() *state {
return new224Generic()
}
func new256() *state {
return new256Generic()
}
func new384() *state {
return new384Generic()
}
func new512() *state {
return new512Generic()
}

View File

@@ -1,13 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build amd64 && !purego && gc
package sha3
// This function is implemented in keccakf_amd64.s.
//go:noescape
func keccakF1600(a *[25]uint64)

File diff suppressed because it is too large Load Diff

View File

@@ -4,15 +4,46 @@
package sha3
// This implementation is only used for NewLegacyKeccak256 and
// NewLegacyKeccak512, which are not implemented by crypto/sha3.
// All other functions in this package are wrappers around crypto/sha3.
import (
"crypto/subtle"
"encoding/binary"
"errors"
"hash"
"unsafe"
"golang.org/x/sys/cpu"
)
const (
dsbyteKeccak = 0b00000001
// rateK[c] is the rate in bytes for Keccak[c] where c is the capacity in
// bits. Given the sponge size is 1600 bits, the rate is 1600 - c bits.
rateK256 = (1600 - 256) / 8
rateK512 = (1600 - 512) / 8
rateK1024 = (1600 - 1024) / 8
)
// NewLegacyKeccak256 creates a new Keccak-256 hash.
//
// Only use this function if you require compatibility with an existing cryptosystem
// that uses non-standard padding. All other users should use New256 instead.
func NewLegacyKeccak256() hash.Hash {
return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteKeccak}
}
// NewLegacyKeccak512 creates a new Keccak-512 hash.
//
// Only use this function if you require compatibility with an existing cryptosystem
// that uses non-standard padding. All other users should use New512 instead.
func NewLegacyKeccak512() hash.Hash {
return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteKeccak}
}
// spongeDirection indicates the direction bytes are flowing through the sponge.
type spongeDirection int
@@ -173,12 +204,9 @@ func (d *state) Sum(in []byte) []byte {
}
const (
magicSHA3 = "sha\x08"
magicShake = "sha\x09"
magicCShake = "sha\x0a"
magicKeccak = "sha\x0b"
// magic || rate || main state || n || sponge direction
marshaledSize = len(magicSHA3) + 1 + 200 + 1 + 1
marshaledSize = len(magicKeccak) + 1 + 200 + 1 + 1
)
func (d *state) MarshalBinary() ([]byte, error) {
@@ -187,12 +215,6 @@ func (d *state) MarshalBinary() ([]byte, error) {
func (d *state) AppendBinary(b []byte) ([]byte, error) {
switch d.dsbyte {
case dsbyteSHA3:
b = append(b, magicSHA3...)
case dsbyteShake:
b = append(b, magicShake...)
case dsbyteCShake:
b = append(b, magicCShake...)
case dsbyteKeccak:
b = append(b, magicKeccak...)
default:
@@ -210,12 +232,9 @@ func (d *state) UnmarshalBinary(b []byte) error {
return errors.New("sha3: invalid hash state")
}
magic := string(b[:len(magicSHA3)])
b = b[len(magicSHA3):]
magic := string(b[:len(magicKeccak)])
b = b[len(magicKeccak):]
switch {
case magic == magicSHA3 && d.dsbyte == dsbyteSHA3:
case magic == magicShake && d.dsbyte == dsbyteShake:
case magic == magicCShake && d.dsbyte == dsbyteCShake:
case magic == magicKeccak && d.dsbyte == dsbyteKeccak:
default:
return errors.New("sha3: invalid hash state identifier")

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