A container registry that uses the AT Protocol for manifest storage and S3 for blob storage. atcr.io
docker container atproto go
80
fork

Configure Feed

Select the types of activity you want to include in your feed.

implementation of syft/grype scanner as a separate binary

+4913 -1467
+51
Dockerfile.scanner
··· 1 + FROM docker.io/golang:1.25.4-trixie AS builder 2 + 3 + ENV DEBIAN_FRONTEND=noninteractive 4 + 5 + RUN apt-get update && \ 6 + apt-get install -y --no-install-recommends sqlite3 libsqlite3-dev && \ 7 + rm -rf /var/lib/apt/lists/* 8 + 9 + WORKDIR /build 10 + 11 + # Copy go.work and both module definitions first for layer caching 12 + COPY go.work ./ 13 + COPY go.mod go.sum ./ 14 + COPY scanner/go.mod scanner/go.sum ./scanner/ 15 + 16 + RUN cd scanner && go mod download 17 + 18 + # Copy full source 19 + COPY . . 20 + 21 + RUN cd scanner && CGO_ENABLED=1 go build \ 22 + -ldflags="-s -w -linkmode external -extldflags '-static'" \ 23 + -trimpath \ 24 + -o /build/atcr-scanner ./cmd/scanner 25 + 26 + # ========================================== 27 + # Stage 2: Minimal FROM scratch runtime 28 + # ========================================== 29 + FROM scratch 30 + 31 + # Copy CA certificates for HTTPS (presigned URL downloads) 32 + COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ 33 + # Copy timezone data for timestamp formatting 34 + COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo 35 + # Copy binary 36 + COPY --from=builder /build/atcr-scanner /atcr-scanner 37 + 38 + # Expose health endpoint port 39 + EXPOSE 9090 40 + 41 + # OCI image annotations 42 + LABEL org.opencontainers.image.title="ATCR Scanner" \ 43 + org.opencontainers.image.description="ATCR Scanner - container image vulnerability scanner with Syft and Grype" \ 44 + org.opencontainers.image.authors="ATCR Contributors" \ 45 + org.opencontainers.image.source="https://tangled.org/evan.jarrett.net/at-container-registry" \ 46 + org.opencontainers.image.documentation="https://tangled.org/evan.jarrett.net/at-container-registry" \ 47 + org.opencontainers.image.licenses="MIT" \ 48 + org.opencontainers.image.version="0.1.0" 49 + 50 + ENTRYPOINT ["/atcr-scanner"] 51 + CMD ["serve"]
+23 -4
go.mod
··· 3 3 go 1.25.4 4 4 5 5 require ( 6 - github.com/aws/aws-sdk-go v1.55.8 7 - github.com/bluesky-social/indigo v0.0.0-20260202181658-ea3d39eec464 6 + github.com/aws/aws-sdk-go-v2 v1.41.1 7 + github.com/aws/aws-sdk-go-v2/config v1.32.7 8 + github.com/aws/aws-sdk-go-v2/credentials v1.19.7 9 + github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0 10 + github.com/bluesky-social/indigo v0.0.0-20260203235305-a86f3ae1f8ec 8 11 github.com/distribution/distribution/v3 v3.0.0 9 12 github.com/distribution/reference v0.6.0 10 13 github.com/earthboundkid/versioninfo/v2 v2.24.1 ··· 45 48 require ( 46 49 github.com/RussellLuo/slidingwindow v0.0.0-20200528002341-535bb99d338b // indirect 47 50 github.com/ajg/form v1.6.1 // indirect 51 + github.com/aws/aws-sdk-go v1.55.5 // indirect 52 + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect 53 + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect 54 + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect 55 + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect 56 + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect 57 + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 // indirect 58 + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect 59 + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 // indirect 60 + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 // indirect 61 + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 // indirect 62 + github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect 63 + github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 // indirect 64 + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 // indirect 65 + github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect 66 + github.com/aws/smithy-go v1.24.0 // indirect 48 67 github.com/aymerick/douceur v0.2.0 // indirect 49 68 github.com/beorn7/perks v1.0.1 // indirect 50 69 github.com/bshuster-repo/logrus-logstash-hook v1.1.0 // indirect ··· 164 183 golang.org/x/sys v0.40.0 // indirect 165 184 golang.org/x/text v0.33.0 // indirect 166 185 golang.org/x/time v0.14.0 // indirect 167 - google.golang.org/genproto/googleapis/api v0.0.0-20260202165425-ce8ad4cf556b // indirect 168 - google.golang.org/genproto/googleapis/rpc v0.0.0-20260202165425-ce8ad4cf556b // indirect 186 + google.golang.org/genproto/googleapis/api v0.0.0-20260203192932-546029d2fa20 // indirect 187 + google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect 169 188 google.golang.org/grpc v1.78.0 // indirect 170 189 google.golang.org/protobuf v1.36.11 // indirect 171 190 gopkg.in/inf.v0 v0.9.1 // indirect
+46 -10
go.sum
··· 10 10 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 11 11 github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 h1:iW0a5ljuFxkLGPNem5Ui+KBjFJzKg4Fv2fnxe4dvzpM= 12 12 github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5/go.mod h1:Y2QMoi1vgtOIfc+6DhrMOGkLoGzqSV2rKp4Sm+opsyA= 13 - github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ= 14 - github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk= 13 + github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= 14 + github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= 15 + github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU= 16 + github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= 17 + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU= 18 + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4= 19 + github.com/aws/aws-sdk-go-v2/config v1.32.7 h1:vxUyWGUwmkQ2g19n7JY/9YL8MfAIl7bTesIUykECXmY= 20 + github.com/aws/aws-sdk-go-v2/config v1.32.7/go.mod h1:2/Qm5vKUU/r7Y+zUk/Ptt2MDAEKAfUtKc1+3U1Mo3oY= 21 + github.com/aws/aws-sdk-go-v2/credentials v1.19.7 h1:tHK47VqqtJxOymRrNtUXN5SP/zUTvZKeLx4tH6PGQc8= 22 + github.com/aws/aws-sdk-go-v2/credentials v1.19.7/go.mod h1:qOZk8sPDrxhf+4Wf4oT2urYJrYt3RejHSzgAquYeppw= 23 + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 h1:I0GyV8wiYrP8XpA70g1HBcQO1JlQxCMTW9npl5UbDHY= 24 + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17/go.mod h1:tyw7BOl5bBe/oqvoIeECFJjMdzXoa/dfVz3QQ5lgHGA= 25 + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U= 26 + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ= 27 + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik= 28 + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM= 29 + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk= 30 + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= 31 + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 h1:JqcdRG//czea7Ppjb+g/n4o8i/R50aTBHkA7vu0lK+k= 32 + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17/go.mod h1:CO+WeGmIdj/MlPel2KwID9Gt7CNq4M65HUfBW97liM0= 33 + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E= 34 + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow= 35 + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 h1:Z5EiPIzXKewUQK0QTMkutjiaPVeVYXX7KIqhXu/0fXs= 36 + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8/go.mod h1:FsTpJtvC4U1fyDXk7c71XoDv3HlRm8V3NiYLeYLh5YE= 37 + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 h1:RuNSMoozM8oXlgLG/n6WLaFGoea7/CddrCfIiSA+xdY= 38 + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17/go.mod h1:F2xxQ9TZz5gDWsclCtPQscGpP0VUOc8RqgFM3vDENmU= 39 + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 h1:bGeHBsGZx0Dvu/eJC0Lh9adJa3M1xREcndxLNZlve2U= 40 + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17/go.mod h1:dcW24lbU0CzHusTE8LLHhRLI42ejmINN8Lcr22bwh/g= 41 + github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0 h1:oeu8VPlOre74lBA/PMhxa5vewaMIMmILM+RraSyB8KA= 42 + github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0/go.mod h1:5jggDlZ2CLQhwJBiZJb4vfk4f0GxWdEDruWKEJ1xOdo= 43 + github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y= 44 + github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M= 45 + github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 h1:v6EiMvhEYBoHABfbGB4alOYmCIrcgyPPiBE1wZAEbqk= 46 + github.com/aws/aws-sdk-go-v2/service/sso v1.30.9/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw= 47 + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 h1:gd84Omyu9JLriJVCbGApcLzVR3XtmC4ZDPcAI6Ftvds= 48 + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo= 49 + github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/pJ1jOWYlFDJTjRQ= 50 + github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ= 51 + github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= 52 + github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= 15 53 github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= 16 54 github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= 17 55 github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= ··· 22 60 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 23 61 github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= 24 62 github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= 25 - github.com/bluesky-social/indigo v0.0.0-20260202181658-ea3d39eec464 h1:jL6cPOk1CZ8H06sEn+WFGWufHmqkawsGyDRl+BJhQjs= 26 - github.com/bluesky-social/indigo v0.0.0-20260202181658-ea3d39eec464/go.mod h1:VG/LeqLGNI3Ew7lsYixajnZGFfWPv144qbUddh+Oyag= 63 + github.com/bluesky-social/indigo v0.0.0-20260203235305-a86f3ae1f8ec h1:fubriMftMNEmb35sF07gDCsdUSEd0+EIDebt/+5oQRU= 64 + github.com/bluesky-social/indigo v0.0.0-20260203235305-a86f3ae1f8ec/go.mod h1:VG/LeqLGNI3Ew7lsYixajnZGFfWPv144qbUddh+Oyag= 27 65 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= 28 66 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= 29 67 github.com/bshuster-repo/logrus-logstash-hook v1.1.0 h1:o2FzZifLg+z/DN1OFmzTWzZZx/roaqt8IPZCIVco8r4= ··· 403 441 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 404 442 github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= 405 443 github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 406 - github.com/stripe/stripe-go/v84 v84.1.0 h1:9KW8Fm3csWsPNqBJCgdEZBM9pRNaqpESHIw+eXp8A0k= 407 - github.com/stripe/stripe-go/v84 v84.1.0/go.mod h1:kjXh3OrF4PT16qz7z9Q5yqYAZ1mJmu8g8f4Z1sOHBfc= 408 444 github.com/stripe/stripe-go/v84 v84.3.0 h1:77HH+ro7yzmyyF7Xkbkj6y5QtnU1WWHC6t2y4mq0Wvk= 409 445 github.com/stripe/stripe-go/v84 v84.3.0/go.mod h1:Z4gcKw1zl4geDG2+cjpSaJES9jaohGX6n7FP8/kHIqw= 410 446 github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= ··· 564 600 golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= 565 601 gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= 566 602 gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= 567 - google.golang.org/genproto/googleapis/api v0.0.0-20260202165425-ce8ad4cf556b h1:SGYyueaEovpqmWmtTvwtVgo638V/QFE2zlTCnRrR3jg= 568 - google.golang.org/genproto/googleapis/api v0.0.0-20260202165425-ce8ad4cf556b/go.mod h1:ZdbssH/1SOVnjnDlXzxDHK2MCidiqXtbYccJNzNYPEE= 569 - google.golang.org/genproto/googleapis/rpc v0.0.0-20260202165425-ce8ad4cf556b h1:GZxXGdFaHX27ZSMHudWc4FokdD+xl8BC2UJm1OVIEzs= 570 - google.golang.org/genproto/googleapis/rpc v0.0.0-20260202165425-ce8ad4cf556b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= 603 + google.golang.org/genproto/googleapis/api v0.0.0-20260203192932-546029d2fa20 h1:7ei4lp52gK1uSejlA8AZl5AJjeLUOHBQscRQZUgAcu0= 604 + google.golang.org/genproto/googleapis/api v0.0.0-20260203192932-546029d2fa20/go.mod h1:ZdbssH/1SOVnjnDlXzxDHK2MCidiqXtbYccJNzNYPEE= 605 + google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 h1:Jr5R2J6F6qWyzINc+4AM8t5pfUz6beZpHp678GNrMbE= 606 + google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= 571 607 google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= 572 608 google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= 573 609 google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
+6
go.work
··· 1 + go 1.25.4 2 + 3 + use ( 4 + . 5 + ./scanner 6 + )
+492
go.work.sum
··· 1 + cloud.google.com/go/accessapproval v1.8.7/go.mod h1:BFvZOW4GJjJnl6aA/YDEg0TGViFHyusa/bMdcVFmh8A= 2 + cloud.google.com/go/accesscontextmanager v1.9.6/go.mod h1:884XHwy1AQpCX5Cj2VqYse77gfLaq9f8emE2bYriilk= 3 + cloud.google.com/go/aiplatform v1.102.0/go.mod h1:4rwKOMdubQOND81AlO3EckcskvEFCYSzXKfn42GMm8k= 4 + cloud.google.com/go/analytics v0.30.0/go.mod h1:dneJtsGmmK6EkEPg59vRlncKFWt3xzmKNOc9aKXCTrI= 5 + cloud.google.com/go/apigateway v1.7.7/go.mod h1:j1bCmrUK1BzVHpiIyTApxB7cRyhivKzltqLmp6j6i7U= 6 + cloud.google.com/go/apigeeconnect v1.7.7/go.mod h1:ftGK3nca0JePiVLl0A6alaMjKdOc5C+sAkFMyH2RH8U= 7 + cloud.google.com/go/apigeeregistry v0.9.6/go.mod h1:AFEepJBKPtGDfgabG2HWaLH453VVWWFFs3P4W00jbPs= 8 + cloud.google.com/go/appengine v1.9.7/go.mod h1:y1XpGVeAhbsNzHida79cHbr3pFRsym0ob8xnC8yphbo= 9 + cloud.google.com/go/area120 v0.9.7/go.mod h1:5nJ0yksmjOMfc4Zpk+okWfJ3A1004FvB82rfia+ZLaY= 10 + cloud.google.com/go/artifactregistry v1.17.1/go.mod h1:06gLv5QwQPWtaudI2fWO37gfwwRUHwxm3gA8Fe568Hc= 11 + cloud.google.com/go/asset v1.21.1/go.mod h1:7AzY1GCC+s1O73yzLM1IpHFLHz3ws2OigmCpOQHwebk= 12 + cloud.google.com/go/assuredworkloads v1.12.6/go.mod h1:QyZHd7nH08fmZ+G4ElihV1zoZ7H0FQCpgS0YWtwjCKo= 13 + cloud.google.com/go/automl v1.14.7/go.mod h1:8a4XbIH5pdvrReOU72oB+H3pOw2JBxo9XTk39oljObE= 14 + cloud.google.com/go/baremetalsolution v1.3.6/go.mod h1:7/CS0LzpLccRGO0HL3q2Rofxas2JwjREKut414sE9iM= 15 + cloud.google.com/go/batch v1.12.2/go.mod h1:tbnuTN/Iw59/n1yjAYKV2aZUjvMM2VJqAgvUgft6UEU= 16 + cloud.google.com/go/beyondcorp v1.1.6/go.mod h1:V1PigSWPGh5L/vRRmyutfnjAbkxLI2aWqJDdxKbwvsQ= 17 + cloud.google.com/go/bigquery v1.70.0/go.mod h1:6lEAkgTJN+H2JcaX1eKiuEHTKyqBaJq5U3SpLGbSvwI= 18 + cloud.google.com/go/bigtable v1.39.0/go.mod h1:zgL2Vxux9Bx+TcARDJDUxVyE+BCUfP2u4Zm9qeHF+g0= 19 + cloud.google.com/go/billing v1.20.4/go.mod h1:hBm7iUmGKGCnBm6Wp439YgEdt+OnefEq/Ib9SlJYxIU= 20 + cloud.google.com/go/binaryauthorization v1.9.5/go.mod h1:CV5GkS2eiY461Bzv+OH3r5/AsuB6zny+MruRju3ccB8= 21 + cloud.google.com/go/certificatemanager v1.9.5/go.mod h1:kn7gxT/80oVGhjL8rurMUYD36AOimgtzSBPadtAeffs= 22 + cloud.google.com/go/channel v1.20.0/go.mod h1:nBR1Lz+/1TjSA16HTllvW9Y+QULODj3o3jEKrNNeOp4= 23 + cloud.google.com/go/cloudbuild v1.23.0/go.mod h1:BkxnZUIHUHkl+oNpEbwc7n9id4pZRDQRVKIa6sDCuJI= 24 + cloud.google.com/go/clouddms v1.8.8/go.mod h1:QtCyw+a73dlkDb2q20aTAPvfaTZCepDDi6Gb1AKq0a4= 25 + cloud.google.com/go/cloudtasks v1.13.6/go.mod h1:/IDaQqGKMixD+ayM43CfsvWF2k36GeomEuy9gL4gLmU= 26 + cloud.google.com/go/compute v1.47.0 h1:SG1vwa2xaAzz6XN/qytL3Z8hzKeZzWxV1o5wYLc+TEk= 27 + cloud.google.com/go/compute v1.47.0/go.mod h1:1uoZvP8Avyfhe3Y4he7sMOR16ZiAm2Q+Rc2P5rrJM28= 28 + cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= 29 + cloud.google.com/go/contactcenterinsights v1.17.4/go.mod h1:kZe6yOnKDfpPz2GphDHynxk/Spx+53UX/pGf+SmWAKM= 30 + cloud.google.com/go/container v1.44.0/go.mod h1:tVK2o4UZUTkg9WpBcgj4qRzwGA1dSFdWA3mil3YkLIQ= 31 + cloud.google.com/go/containeranalysis v0.14.1/go.mod h1:28e+tlZgauWGHmEbnI5UfIsjMmrkoR1tFN0K2i71jBI= 32 + cloud.google.com/go/datacatalog v1.26.1/go.mod h1:2Qcq8vsHNxMDgjgadRFmFG47Y+uuIVsyEGUrlrKEdrg= 33 + cloud.google.com/go/dataflow v0.11.0/go.mod h1:gNHC9fUjlV9miu0hd4oQaXibIuVYTQvZhMdPievKsPk= 34 + cloud.google.com/go/dataform v0.12.1/go.mod h1:atGS8ReRjfNDUQib0X/o/7Gi2bqHI2G7/J86LKiGimE= 35 + cloud.google.com/go/datafusion v1.8.7/go.mod h1:4dkFb1la41qCEXh1AzYtFwl842bu2ikTUXyKhjvFCb0= 36 + cloud.google.com/go/datalabeling v0.9.7/go.mod h1:EEUVn+wNn3jl19P2S13FqE1s9LsKzRsPuuMRq2CMsOk= 37 + cloud.google.com/go/dataplex v1.27.1/go.mod h1:VB+xlYJiJ5kreonXsa2cHPj0A3CfPh/mgiHG4JFhbUA= 38 + cloud.google.com/go/dataproc/v2 v2.14.1/go.mod h1:tSdkodShfzrrUNPDVEL6MdH9/mIEvp/Z9s9PBdbsZg8= 39 + cloud.google.com/go/dataqna v0.9.7/go.mod h1:4ac3r7zm7Wqm8NAc8sDIDM0v7Dz7d1e/1Ka1yMFanUM= 40 + cloud.google.com/go/datastore v1.20.0/go.mod h1:uFo3e+aEpRfHgtp5pp0+6M0o147KoPaYNaPAKpfh8Ew= 41 + cloud.google.com/go/datastream v1.15.1/go.mod h1:aV1Grr9LFon0YvqryE5/gF1XAhcau2uxN2OvQJPpqRw= 42 + cloud.google.com/go/deploy v1.27.3/go.mod h1:7LFIYYTSSdljYRqY3n+JSmIFdD4lv6aMD5xg0crB5iw= 43 + cloud.google.com/go/dialogflow v1.69.1/go.mod h1:mP4XrpgDvPYBP+cdLxFC1WJJlkwuy0H8L1Lada9No/M= 44 + cloud.google.com/go/dlp v1.25.0/go.mod h1:PY4DMzV7lqRC5JvpxL05fXNeL8dknxYpFp4WjxmE22M= 45 + cloud.google.com/go/documentai v1.38.1/go.mod h1:KmlLO93F7GRU8dENXRxvt+7V8o7eCG6Y6WDitKbcYJs= 46 + cloud.google.com/go/domains v0.10.7/go.mod h1:T3WG/QUAO/52z4tUPooKS8AY7yXaFxPYn1V3F0/JbNQ= 47 + cloud.google.com/go/edgecontainer v1.4.4/go.mod h1:yyNVHsCKtsX/0mqFdbljQw0Uo660q2dlMPaiqYiC2Tg= 48 + cloud.google.com/go/errorreporting v0.3.2/go.mod h1:s5kjs5r3l6A8UUyIsgvAhGq6tkqyBCUss0FRpsoVTww= 49 + cloud.google.com/go/essentialcontacts v1.7.7/go.mod h1:ytycWAEn/aKUMRKQPMVgMrAtphEMgjbzL8vFwM3tqXs= 50 + cloud.google.com/go/eventarc v1.16.1/go.mod h1:wB3NTIQ+l4QPirJiTMeU+YpSc5+iyoDYWV4n2/Vmh78= 51 + cloud.google.com/go/filestore v1.10.3/go.mod h1:94ZGyLTx9j+aWKozPQ6Wbq1DuImie/L/HIdGMshtwac= 52 + cloud.google.com/go/firestore v1.18.0/go.mod h1:5ye0v48PhseZBdcl0qbl3uttu7FIEwEYVaWm0UIEOEU= 53 + cloud.google.com/go/functions v1.19.7/go.mod h1:xbcKfS7GoIcaXr2FSwmtn9NXal1JR4TV6iYZlgXffwA= 54 + cloud.google.com/go/gkebackup v1.8.1/go.mod h1:GAaAl+O5D9uISH5MnClUop2esQW4pDa2qe/95A4l7YQ= 55 + cloud.google.com/go/gkeconnect v0.12.5/go.mod h1:wMD2RXcsAWlkREZWJDVeDV70PYka1iEb9stFmgpw+5o= 56 + cloud.google.com/go/gkehub v0.16.0/go.mod h1:ADp27Ucor8v81wY+x/5pOxTorxkPj/xswH3AUpN62GU= 57 + cloud.google.com/go/gkemulticloud v1.5.4/go.mod h1:7l9+6Tp4jySSGj4PStO8CE6RrHFdcRARK4ScReHX1bU= 58 + cloud.google.com/go/gsuiteaddons v1.7.8/go.mod h1:DBKNHH4YXAdd/rd6zVvtOGAJNGo0ekOh+nIjTUDEJ5U= 59 + cloud.google.com/go/iap v1.11.3/go.mod h1:+gXO0ClH62k2LVlfhHzrpiHQNyINlEVmGAE3+DB4ShU= 60 + cloud.google.com/go/ids v1.5.7/go.mod h1:N3ZQOIgIBwwOu2tzyhmh3JDT+kt8PcoKkn2BRT9Qe4A= 61 + cloud.google.com/go/iot v1.8.7/go.mod h1:HvVcypV8LPv1yTXSLCNK+YCtqGHhq+p0F3BXETfpN+U= 62 + cloud.google.com/go/kms v1.23.0/go.mod h1:rZ5kK0I7Kn9W4erhYVoIRPtpizjunlrfU4fUkumUp8g= 63 + cloud.google.com/go/language v1.14.5/go.mod h1:nl2cyAVjcBct1Hk73tzxuKebk0t2eULFCaruhetdZIA= 64 + cloud.google.com/go/lifesciences v0.10.7/go.mod h1:v3AbTki9iWttEls/Wf4ag3EqeLRHofploOcpsLnu7iY= 65 + cloud.google.com/go/managedidentities v1.7.7/go.mod h1:nwNlMxtBo2YJMvsKXRtAD1bL41qiCI9npS7cbqrsJUs= 66 + cloud.google.com/go/maps v1.23.0/go.mod h1:8tjxLplMV7FEoR9FIwqoY7siDnaOdE7FBWnjaXK/xts= 67 + cloud.google.com/go/mediatranslation v0.9.7/go.mod h1:mz3v6PR7+Fd/1bYrRxNFGnd+p4wqdc/fyutqC5QHctw= 68 + cloud.google.com/go/memcache v1.11.7/go.mod h1:AU1jYlUqCihxapcJ1GGMtlMWDVhzjbfUWBXqsXa4rBg= 69 + cloud.google.com/go/metastore v1.14.8/go.mod h1:h1XI2LpD4ohJhQYn9TwXqKb5sVt6KSo47ft96SiFF1s= 70 + cloud.google.com/go/networkconnectivity v1.19.1/go.mod h1:Q5v6uNNNz8BP232uuXM66XgWML9m379xhwv58Y+8Kb0= 71 + cloud.google.com/go/networkmanagement v1.20.1/go.mod h1:clG/5Yt0wQ57qSH6Yh7oehQYlobHw3F6nb3Pn4ig5hU= 72 + cloud.google.com/go/networksecurity v0.10.7/go.mod h1:FgoictpfaJkeBlM1o2m+ngPZi8mgJetbFDH4ws1i2fQ= 73 + cloud.google.com/go/notebooks v1.12.7/go.mod h1:uR9pxAkKmlNloibMr9Q1t8WhIu4P2JeqJs7c064/0Mo= 74 + cloud.google.com/go/optimization v1.7.7/go.mod h1:OY2IAlX23o52qwMAZ0w65wibKuV12a4x6IHDTCq6kcU= 75 + cloud.google.com/go/orchestration v1.11.10/go.mod h1:tz7m1s4wNEvhNNIM3JOMH0lYxBssu9+7si5MCPw/4/0= 76 + cloud.google.com/go/orgpolicy v1.15.1/go.mod h1:bpvi9YIyU7wCW9WiXL/ZKT7pd2Ovegyr2xENIeRX5q0= 77 + cloud.google.com/go/osconfig v1.15.1/go.mod h1:NegylQQl0+5m+I+4Ey/g3HGeQxKkncQ1q+Il4DZ8PME= 78 + cloud.google.com/go/oslogin v1.14.7/go.mod h1:NB6NqBHfDMwznePdBVX+ILllc1oPCdNSGp5u/WIyndY= 79 + cloud.google.com/go/phishingprotection v0.9.7/go.mod h1:JTI4HNGyAbWolBoNOoCyCF0e3cqPNrYnlievHU49EwE= 80 + cloud.google.com/go/policytroubleshooter v1.11.7/go.mod h1:JP/aQ+bUkt4Gz6lQXBi/+A/6nyNRZ0Pvxui5Xl9ieyk= 81 + cloud.google.com/go/privatecatalog v0.10.8/go.mod h1:BkLHi+rtAGYBt5DocXLytHhF0n6F03Tegxgty40Y7aA= 82 + cloud.google.com/go/pubsub v1.50.1/go.mod h1:6YVJv3MzWJUVdvQXG081sFvS0dWQOdnV+oTo++q/xFk= 83 + cloud.google.com/go/pubsub/v2 v2.0.0/go.mod h1:0aztFxNzVQIRSZ8vUr79uH2bS3jwLebwK6q1sgEub+E= 84 + cloud.google.com/go/pubsublite v1.8.2/go.mod h1:4r8GSa9NznExjuLPEJlF1VjOPOpgf3IT6k8x/YgaOPI= 85 + cloud.google.com/go/recaptchaenterprise/v2 v2.20.4/go.mod h1:3H8nb8j8N7Ss2eJ+zr+/H7gyorfzcxiDEtVBDvDjwDQ= 86 + cloud.google.com/go/recommendationengine v0.9.6/go.mod h1:nZnjKJu1vvoxbmuRvLB5NwGuh6cDMMQdOLXTnkukUOE= 87 + cloud.google.com/go/recommender v1.13.5/go.mod h1:v7x/fzk38oC62TsN5Qkdpn0eoMBh610UgArJtDIgH/E= 88 + cloud.google.com/go/redis v1.18.2/go.mod h1:q6mPRhLiR2uLf584Lcl4tsiRn0xiFlu6fnJLwCORMtY= 89 + cloud.google.com/go/resourcemanager v1.10.6/go.mod h1:VqMoDQ03W4yZmxzLPrB+RuAoVkHDS5tFUUQUhOtnRTg= 90 + cloud.google.com/go/resourcesettings v1.8.3/go.mod h1:BzgfXFHIWOOmHe6ZV9+r3OWfpHJgnqXy8jqwx4zTMLw= 91 + cloud.google.com/go/retail v1.25.0/go.mod h1:J75G8pd+DH0SHueL9IJw7Y5d2VhTsjFsk+F1t9f8jXc= 92 + cloud.google.com/go/run v1.12.0/go.mod h1:/APJ89UqgGdIdaD1yaTiSYXozx3fNoqKR/cueDFRueI= 93 + cloud.google.com/go/scheduler v1.11.7/go.mod h1:gqYs8ndLx2M5D0oMJh48aGS630YYvC432tHCnVWN13s= 94 + cloud.google.com/go/secretmanager v1.15.0/go.mod h1:1hQSAhKK7FldiYw//wbR/XPfPc08eQ81oBsnRUHEvUc= 95 + cloud.google.com/go/security v1.19.1/go.mod h1:+T4yyeDXqBYESnCzswqbq/Oip+IYkIrTfRF4UmeT4Bk= 96 + cloud.google.com/go/securitycenter v1.38.0/go.mod h1:Ge2D/SlG2lP1FrQD7wXHy8qyeloRenvKXeB4e7zO6z0= 97 + cloud.google.com/go/servicedirectory v1.12.6/go.mod h1:OojC1KhOMDYC45oyTn3Mup08FY/S0Kj7I58dxUMMTpg= 98 + cloud.google.com/go/shell v1.8.6/go.mod h1:GNbTWf1QA/eEtYa+kWSr+ef/XTCDkUzRpV3JPw0LqSk= 99 + cloud.google.com/go/spanner v1.85.1/go.mod h1:bbwCXbM+zljwSPLZ44wZOdzcdmy89hbUGmM/r9sD0ws= 100 + cloud.google.com/go/speech v1.28.0/go.mod h1:hJf6oa+1rzCW/CeDE/qCXedV20B2TXEUje5iaGwW+JI= 101 + cloud.google.com/go/storagetransfer v1.13.0/go.mod h1:+aov7guRxXBYgR3WCqedkyibbTICdQOiXOdpPcJCKl8= 102 + cloud.google.com/go/talent v1.8.3/go.mod h1:oD3/BilJpJX8/ad8ZUAxlXHCslTg2YBbafFH3ciZSLQ= 103 + cloud.google.com/go/texttospeech v1.14.0/go.mod h1:l25ywjIgXS+mSE2f5LQdXdU7r3MOLwVOGaYZQMiYIWE= 104 + cloud.google.com/go/tpu v1.8.3/go.mod h1:Do6Gq+/Jx6Xs3LcY2WhHyGwKDKVw++9jIJp+X+0rxRE= 105 + cloud.google.com/go/translate v1.12.6/go.mod h1:nB3AXuX+iHbV8ZURmElcW85qkEDWZw68sf4kqMT/E5o= 106 + cloud.google.com/go/video v1.26.0/go.mod h1:iqsrblPUfkxvyH31rnS02Z0dp9p5lySdq7+I0XzozQI= 107 + cloud.google.com/go/videointelligence v1.12.6/go.mod h1:/l34WMndN5/bt04lHodxiYchLVuWPQjCU6SaiTswrIw= 108 + cloud.google.com/go/vision/v2 v2.9.5/go.mod h1:1SiNZPpypqZDbOzU052ZYRiyKjwOcyqgGgqQCI/nlx8= 109 + cloud.google.com/go/vmmigration v1.9.0/go.mod h1:jI3lBlhQn9+BKIWE/MmMsOzGekCXCc34b1M0CihL3zY= 110 + cloud.google.com/go/vmwareengine v1.3.5/go.mod h1:QuVu2/b/eo8zcIkxBYY5QSwiyEcAy6dInI7N+keI+Jg= 111 + cloud.google.com/go/vpcaccess v1.8.6/go.mod h1:61yymNplV1hAbo8+kBOFO7Vs+4ZHYI244rSFgmsHC6E= 112 + cloud.google.com/go/webrisk v1.11.1/go.mod h1:+9SaepGg2lcp1p0pXuHyz3R2Yi2fHKKb4c1Q9y0qbtA= 113 + cloud.google.com/go/websecurityscanner v1.7.6/go.mod h1:ucaaTO5JESFn5f2pjdX01wGbQ8D6h79KHrmO2uGZeiY= 114 + cloud.google.com/go/workflows v1.14.2/go.mod h1:5nqKjMD+MsJs41sJhdVrETgvD5cOK3hUcAs8ygqYvXQ= 115 + codeberg.org/go-fonts/dejavu v0.4.0/go.mod h1:abni088lmhQJvso2Lsb7azCKzwkfcnttl6tL1UTWKzg= 116 + codeberg.org/go-fonts/latin-modern v0.4.0/go.mod h1:BF68mZznJ9QHn+hic9ks2DaFl4sR5YhfM6xTYaP9vNw= 117 + codeberg.org/go-fonts/liberation v0.5.0/go.mod h1:zS/2e1354/mJ4pGzIIaEtm/59VFCFnYC7YV6YdGl5GU= 118 + codeberg.org/go-fonts/stix v0.3.0/go.mod h1:1OSJSnA/PoHqbW2tjkkqTmNPp5xTtJQN2GRXJjO/+WA= 119 + codeberg.org/go-latex/latex v0.1.0/go.mod h1:LA0q/AyWIYrqVd+A9Upkgsb+IqPcmSTKc9Dny04MHMw= 120 + codeberg.org/go-pdf/fpdf v0.10.0/go.mod h1:Y0DGRAdZ0OmnZPvjbMp/1bYxmIPxm0ws4tfoPOc4LjU= 121 + gioui.org v0.2.0/go.mod h1:1H72sKEk/fNFV+l0JNeM2Dt3co3Y4uaQcD+I+/GQ0e4= 122 + gioui.org/cpu v0.0.0-20220412190645-f1e9e8c3b1f7/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ= 123 + gioui.org/shader v1.0.6/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM= 124 + gioui.org/x v0.2.0/go.mod h1:rCGN2nZ8ZHqrtseJoQxCMZpt2xrZUrdZ2WuMRLBJmYs= 125 + git.sr.ht/~sbinet/cmpimg v0.1.0/go.mod h1:FU12psLbF4TfNXkKH2ZZQ29crIqoiqTZmeQ7dkp/pxE= 126 + git.sr.ht/~sbinet/gg v0.6.0/go.mod h1:uucygbfC9wVPQIfrmwM2et0imr8L7KQWywX0xpFMm94= 127 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1/go.mod h1:zGqV2R4Cr/k8Uye5w+dgQ06WJtEcbQG/8J7BB6hnCr4= 128 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE= 129 + github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= 130 + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0/go.mod h1:cTvi54pg19DoT07ekoeMgE/taAwNtCShVeZqA+Iv2xI= 131 + github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= 132 + github.com/GoogleCloudPlatform/docker-credential-gcr v2.0.5+incompatible/go.mod h1:BB1eHdMLYEFuFdBlRMb0N7YGVdM5s6Pt0njxgvfbGGs= 133 + github.com/Jorropo/jsync v1.0.1/go.mod h1:jCOZj3vrBCri3bSU3ErUYvevKlnbssrXeCivybS5ABQ= 134 + github.com/Microsoft/cosesign1go v1.4.0/go.mod h1:1La/HcGw19rRLhPW0S6u55K6LKfti+GQSgGCtrfhVe8= 135 + github.com/Microsoft/didx509go v0.0.3/go.mod h1:wWt+iQsLzn3011+VfESzznLIp/Owhuj7rLF7yLglYbk= 136 + github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw= 137 + github.com/ProtonMail/gopenpgp/v2 v2.9.0/go.mod h1:IldDyh9Hv1ZCCYatTuuEt1XZJ0OPjxLpTarDfglih7s= 138 + github.com/PuerkitoBio/goquery v1.11.0/go.mod h1:wQHgxUOU3JGuj3oD/QFfxUdlzW6xPHfqyHre6VMY4DQ= 139 + github.com/PuerkitoBio/purell v1.2.1/go.mod h1:ZwHcC/82TOaovDi//J/804umJFFmbOHPngi8iYYv/Eo= 140 + github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= 141 + github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= 142 + github.com/agnivade/levenshtein v1.2.0/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= 143 + github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= 144 + github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= 145 + github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= 146 + github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= 147 + github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= 148 + github.com/alecthomas/kong v0.5.0/go.mod h1:uzxf/HUh0tj43x1AyJROl3JT7SgsZ5m+icOv1csRhc0= 149 + github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= 150 + github.com/anchore/bubbly v0.0.0-20250717181826-8a411f9d8cbf/go.mod h1:w8Br1ZKk1Nk82YRSh10pcD7LO7avPyFmNnaY1TRPgs0= 151 + github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA= 152 + github.com/andybalholm/stroke v0.0.0-20221221101821-bd29b49d73f0/go.mod h1:ccdDYaY5+gO+cbnQdFxEXqfy0RkoV25H3jLXUDNM3wg= 153 + github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw= 154 + github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= 155 + github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= 156 + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.53.5/go.mod h1:eEuD0vTf9mIzsSjGBFWIaNQwtH5/mzViJOVQfnMY5DE= 157 + github.com/aws/aws-sdk-go-v2/service/ecr v1.51.2/go.mod h1:1NVD1KuMjH2GqnPwMotPndQaT/MreKkWpjkF12d6oKU= 158 + github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.2/go.mod h1:x7gU4CAyAz4BsM9hlRkhHiYw2GIr1QCmN45uwQw9l/E= 159 + github.com/aws/aws-sdk-go-v2/service/iam v1.53.1/go.mod h1:GNQZL4JRSGH6L0/SNGOtffaB1vmlToYp3KtcUIB0NhI= 160 + github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.16/go.mod h1:5a78jwLMs7BaesU0UIhLfVy2ZmOEgOy6ewYQXKTD37Q= 161 + github.com/aws/aws-sdk-go-v2/service/sns v1.39.8/go.mod h1:3aOzyhwa/mXPZYLwGaALfl88GFRXHQKXdyQSq2L/Y4g= 162 + github.com/aws/aws-sdk-go-v2/service/sqs v1.42.20/go.mod h1:OG0Y3TgC+IeM++ngh+IcEkN24ruGsmRiAP8GUsOhMW8= 163 + github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.11.0/go.mod h1:a2HN6+p7k0JLDO8514sMr0l4cnrR52z4sWoZ/Uc82ho= 164 + github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= 165 + github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= 166 + github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= 167 + github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= 168 + github.com/bluesky-social/indigo v0.0.0-20260203235305-a86f3ae1f8ec h1:fubriMftMNEmb35sF07gDCsdUSEd0+EIDebt/+5oQRU= 169 + github.com/bluesky-social/indigo v0.0.0-20260203235305-a86f3ae1f8ec/go.mod h1:VG/LeqLGNI3Ew7lsYixajnZGFfWPv144qbUddh+Oyag= 170 + github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= 171 + github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= 172 + github.com/brianvoe/gofakeit/v6 v6.25.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= 173 + github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= 174 + github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= 175 + github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= 176 + github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= 177 + github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= 178 + github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= 179 + github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= 180 + github.com/checkpoint-restore/checkpointctl v1.4.0/go.mod h1:ynQ52zQBazgcTZuxpwTFzRinIcAf0haDTC1X1LA/FKA= 181 + github.com/checkpoint-restore/go-criu/v7 v7.2.0/go.mod h1:u0LCWLg0w4yqqu14aXhiB4YD3a1qd8EcCEg7vda5dwo= 182 + github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= 183 + github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE= 184 + github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= 185 + github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= 186 + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= 187 + github.com/cockroachdb/pebble v1.1.2/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= 188 + github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= 189 + github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= 190 + github.com/containerd/btrfs/v2 v2.0.0/go.mod h1:swkD/7j9HApWpzl8OHfrHNxppPd9l44DFZdF94BUj9k= 191 + github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= 192 + github.com/containerd/go-cni v1.1.13/go.mod h1:nTieub0XDRmvCZ9VI/SBG6PyqT95N4FIhxsauF1vSBI= 193 + github.com/containerd/go-runc v1.1.0/go.mod h1:xJv2hFF7GvHtTJd9JqTS2UVxMkULUYw4JN5XAUZqH5U= 194 + github.com/containerd/imgcrypt/v2 v2.0.1/go.mod h1:/qIJL8nxzdzMA2n5iYyyuIY36KfoVQWmgTWdfVtyebM= 195 + github.com/containerd/nri v0.11.0/go.mod h1:bjGTLdUA58WgghKHg8azFMGXr05n1wDHrt3NSVBHiGI= 196 + github.com/containerd/otelttrpc v0.1.0/go.mod h1:XhoA2VvaGPW1clB2ULwrBZfXVuEWuyOd2NUD1IM0yTg= 197 + github.com/containerd/protobuild v0.3.0/go.mod h1:5mNMFKKAwCIAkFBPiOdtRx2KiQlyEJeMXnL5R1DsWu8= 198 + github.com/containerd/zfs/v2 v2.0.0/go.mod h1:fnUDKF98iYuQqLvNdoXs9MXjtfhRWp1nxSgRf7VZH8s= 199 + github.com/containernetworking/cni v1.3.0/go.mod h1:Bs8glZjjFfGPHMw6hQu82RUgEPNGEaBb9KS5KtNMnJ4= 200 + github.com/containernetworking/plugins v1.9.0/go.mod h1:JG3BxoJifxxHBhG3hFyxyhid7JgRVBu/wtooGEvWf1c= 201 + github.com/containers/ocicrypt v1.2.1/go.mod h1:aD0AAqfMp0MtwqWgHM1bUwe1anx0VazI108CRrSKINQ= 202 + github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 203 + github.com/crackcomm/go-gitignore v0.0.0-20241020182519-7843d2ba8fdf/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= 204 + github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 205 + github.com/danieljoos/wincred v1.2.3/go.mod h1:6qqX0WNrS4RzPZ1tnroDzq9kY3fu1KwE7MRLQK4X0bs= 206 + github.com/dave/jennifer v1.7.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc= 207 + github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= 208 + github.com/dgraph-io/badger/v3 v3.2103.2/go.mod h1:RHo4/GmYcKKh5Lxu63wLEMHJ70Pac2JqZRYGhlyAo2M= 209 + github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= 210 + github.com/dunglas/httpsfv v1.1.0/go.mod h1:zID2mqw9mFsnt7YC3vYQ9/cjq30q41W+1AnDwH8TiMg= 211 + github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= 212 + github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= 213 + github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= 214 + github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= 215 + github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= 216 + github.com/gkampitakis/go-snaps v0.5.19/go.mod h1:gC3YqxQTPyIXvQrw/Vpt3a8VqR1MO8sVpZFWN4DGwNs= 217 + github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= 218 + github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 219 + github.com/go-redis/cache/v9 v9.0.0/go.mod h1:cMwi1N8ASBOufbIvk7cdXe2PbPjK/WMRL95FFHWsSgI= 220 + github.com/go-text/typesetting v0.0.0-20230803102845-24e03d8b5372/go.mod h1:evDBbvNR/KaVFZ2ZlDSOWWXIUKq0wCOEtzLxRM8SG3k= 221 + github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 222 + github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= 223 + github.com/goccmack/gocc v1.0.2/go.mod h1:LXX2tFVUggS/Zgx/ICPOr3MLyusuM7EcbfkPvNsjdO8= 224 + github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 225 + github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 226 + github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= 227 + github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= 228 + github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= 229 + github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 230 + github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= 231 + github.com/google/certtostore v1.0.6/go.mod h1:2N0ZPLkGvQWhYvXaiBGq02r71fnSLfq78VKIWQHr1wo= 232 + github.com/google/deck v0.0.0-20230104221208-105ad94aa8ae/go.mod h1:DoDv8G58DuLNZF0KysYn0bA/6ZWhmRW3fZE2VnGEH0w= 233 + github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= 234 + github.com/google/go-cmdtest v0.4.0/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o= 235 + github.com/google/go-pkcs11 v0.3.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= 236 + github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= 237 + github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= 238 + github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= 239 + github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20= 240 + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= 241 + github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 242 + github.com/hashicorp/terraform-plugin-log v0.10.0/go.mod h1:/9RR5Cv2aAbrqcTSdNmY1NRHP4E3ekrXRGjqORpXyB0= 243 + github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= 244 + github.com/in-toto/in-toto-golang v0.9.0/go.mod h1:xsBVrVsHNsB61++S6Dy2vWosKhuA3lUTQd+eF9HdeMo= 245 + github.com/intel/goresctrl v0.10.0/go.mod h1:1S8GDqL46GuKb525bxNhIEEkhf4rhVcbSf9DuKhp7mw= 246 + github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= 247 + github.com/ipfs/go-blockservice v0.5.2/go.mod h1:VpMblFEqG67A/H2sHKAemeH9vlURVavlysbdUI632yk= 248 + github.com/ipfs/go-fetcher v1.6.1/go.mod h1:27d/xMV8bodjVs9pugh/RCjjK2OZ68UgAMspMdingNo= 249 + github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= 250 + github.com/ipfs/go-ipfs-exchange-interface v0.2.1/go.mod h1:MUsYn6rKbG6CTtsDp+lKJPmVt3ZrCViNyH3rfPGsZ2E= 251 + github.com/ipfs/go-ipfs-exchange-offline v0.3.0/go.mod h1:MOdJ9DChbb5u37M1IcbrRB02e++Z7521fMxqCNRrz9s= 252 + github.com/ipfs/go-ipfs-files v0.3.0/go.mod h1:xAUtYMwB+iu/dtf6+muHNSFQCJG2dSiStR2P6sn9tIM= 253 + github.com/ipfs/go-ipfs-redirects-file v0.1.2/go.mod h1:yIiTlLcDEM/8lS6T3FlCEXZktPPqSOyuY6dEzVqw7Fw= 254 + github.com/ipfs/go-ipfs-routing v0.3.0/go.mod h1:dKqtTFIql7e1zYsEuWLyuOU+E0WJWW8JjbTPLParDWo= 255 + github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= 256 + github.com/ipfs/go-merkledag v0.11.0/go.mod h1:Q4f/1ezvBiJV0YCIXvt51W/9/kqJGH4I1LsA7+djsM4= 257 + github.com/ipfs/go-namesys v0.7.0/go.mod h1:KYSZBVZG3VJC34EfqqJPG7T48aWgxseoMPAPA5gLyyQ= 258 + github.com/ipfs/go-path v0.3.1/go.mod h1:eNLsxJEEMxn/CDzUJ6wuNl+6No6tEUhOZcPKsZsYX0E= 259 + github.com/ipfs/go-unixfs v0.3.1/go.mod h1:h4qfQYzghiIc8ZNFKiLMFWOTzrWIAtzYQ59W/pCFf1o= 260 + github.com/ipfs/go-verifcid v0.0.3/go.mod h1:gcCtGniVzelKrbk9ooUSX/pM3xlH73fZZJDzQJRvOUw= 261 + github.com/ipfs/interface-go-ipfs-core v0.10.0/go.mod h1:F3EcmDy53GFkF0H3iEJpfJC320fZ/4G60eftnItrrJ0= 262 + github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= 263 + github.com/jedib0t/go-pretty/v6 v6.7.8/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU= 264 + github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc= 265 + github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 266 + github.com/josephspurrier/goversioninfo v1.5.0/go.mod h1:6MoTvFZ6GKJkzcdLnU5T/RGYUbHQbKpYeNP0AgQLd2o= 267 + github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= 268 + github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= 269 + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= 270 + github.com/keybase/dbus v0.0.0-20220506165403-5aa21ea2c23a/go.mod h1:YPNKjjE7Ubp9dTbnWvsP3HT+hYnY6TfXzubYTBeUxc8= 271 + github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= 272 + github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE= 273 + github.com/knqyf263/go-plugin v0.9.0/go.mod h1:2z5lCO1/pez6qGo8CvCxSlBFSEat4MEp1DrnA+f7w8Q= 274 + github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 275 + github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 276 + github.com/labstack/echo-contrib v0.15.0/go.mod h1:lei+qt5CLB4oa7VHTE0yEfQSEB9XTJI1LUqko9UWvo4= 277 + github.com/labstack/echo/v4 v4.11.3/go.mod h1:UcGuQ8V6ZNRmSweBIJkPvGfwCMIlFmiqrPqiEBfPYws= 278 + github.com/labstack/gommon v0.4.1/go.mod h1:TyTrpPqxR5KMk8LKVtLmfMjeQ5FEkBYdxLYPw/WfrOM= 279 + github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= 280 + github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= 281 + github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= 282 + github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= 283 + github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= 284 + github.com/lestrrat-go/jwx v1.2.29/go.mod h1:hU8k2l6WF0ncx20uQdOmik/Gjg6E3/wIRtXSNFeZuB8= 285 + github.com/lestrrat-go/jwx/v2 v2.0.12/go.mod h1:Mq4KN1mM7bp+5z/W5HS8aCNs5RKZ911G/0y2qUjAQuQ= 286 + github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= 287 + github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec/go.mod h1:TmwEoGCwIti7BCeJ9hescZgRtatxRE+A72pCoPfmcfk= 288 + github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= 289 + github.com/libp2p/go-doh-resolver v0.5.0/go.mod h1:aPDxfiD2hNURgd13+hfo29z9IC22fv30ee5iM31RzxU= 290 + github.com/libp2p/go-libp2p-kad-dht v0.37.1/go.mod h1:Uwokdh232k9Y1uMy2yJOK5zb7hpMHn4P8uWS4s9i05Q= 291 + github.com/libp2p/go-libp2p-kbucket v0.8.0/go.mod h1:JMlxqcEyKwO6ox716eyC0hmiduSWZZl6JY93mGaaqc4= 292 + github.com/libp2p/go-libp2p-routing-helpers v0.7.5/go.mod h1:3YaxrwP0OBPDD7my3D0KxfR89FlcX/IEbxDEDfAmj98= 293 + github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM= 294 + github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= 295 + github.com/libp2p/go-yamux/v5 v5.0.1/go.mod h1:en+3cdX51U0ZslwRdRLrvQsdayFt3TSUKvBGErzpWbU= 296 + github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= 297 + github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= 298 + github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= 299 + github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= 300 + github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= 301 + github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= 302 + github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= 303 + github.com/mattn/goveralls v0.0.5/go.mod h1:Xg2LHi51faXLyKXwsndxiW6uxEEQT9+3sjGzzwU4xy0= 304 + github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= 305 + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= 306 + github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= 307 + github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE= 308 + github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= 309 + github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= 310 + github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= 311 + github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= 312 + github.com/mistifyio/go-zfs/v3 v3.0.1/go.mod h1:CzVgeB0RvF2EGzQnytKVvVSDwmKJXxkOTUGbNrTja/k= 313 + github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= 314 + github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 315 + github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= 316 + github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I= 317 + github.com/moby/sys/symlink v0.3.0/go.mod h1:3eNdhduHmYPcgsJtZXW1W4XUJdZGBIkttZ8xKqPUJq0= 318 + github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 319 + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= 320 + github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0/go.mod h1:F/7q8/HZz+TXjlsoZQQKVYvXTZaFH4QRa3y+j1p7MS0= 321 + github.com/open-policy-agent/opa v0.70.0/go.mod h1:Y/nm5NY0BX0BqjBriKUiV81sCl8XOjjvqQG7dXrggtI= 322 + github.com/opencontainers/runc v1.2.3/go.mod h1:nSxcWUydXrsBZVYNSkTjoQ/N6rcyTtn+1SD5D4+kRIM= 323 + github.com/opencontainers/runtime-tools v0.9.1-0.20251114084447-edf4cb3d2116/go.mod h1:DKDEfzxvRkoQ6n9TGhxQgg2IM1lY4aM0eaQP4e3oElw= 324 + github.com/opensearch-project/opensearch-go/v2 v2.3.0/go.mod h1:8LDr9FCgUTVoT+5ESjc2+iaZuldqE+23Iq0r1XeNue8= 325 + github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= 326 + github.com/orandin/slog-gorm v1.3.2/go.mod h1:MoZ51+b7xE9lwGNPYEhxcUtRNrYzjdcKvA8QXQQGEPA= 327 + github.com/owenrumney/go-sarif v1.1.2-0.20231003122901-1000f5e05554/go.mod h1:n73K/hcuJ50MiVznXyN4rde6fZY7naGKWBXOLFTyc94= 328 + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= 329 + github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= 330 + github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= 331 + github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M= 332 + github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= 333 + github.com/pion/dtls/v3 v3.0.6/go.mod h1:iJxNQ3Uhn1NZWOMWlLxEEHAN5yX7GyPvvKw04v9bzYU= 334 + github.com/pion/ice/v4 v4.0.10/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= 335 + github.com/pion/interceptor v0.1.40/go.mod h1:Z6kqH7M/FYirg3frjGJ21VLSRJGBXB/KqaTIrdqnOic= 336 + github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90= 337 + github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA= 338 + github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= 339 + github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= 340 + github.com/pion/rtp v1.8.19/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk= 341 + github.com/pion/sctp v1.8.39/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= 342 + github.com/pion/sdp/v3 v3.0.13/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= 343 + github.com/pion/srtp/v3 v3.0.6/go.mod h1:BxvziG3v/armJHAaJ87euvkhHqWe9I7iiOy50K2QkhY= 344 + github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= 345 + github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU= 346 + github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= 347 + github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= 348 + github.com/pion/turn/v4 v4.0.2/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7IToA1zs= 349 + github.com/pion/webrtc/v4 v4.1.2/go.mod h1:xsCXiNAmMEjIdFxAYU0MbB3RwRieJsegSB2JZsGN+8U= 350 + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= 351 + github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 352 + github.com/puzpuzpuz/xsync/v3 v3.0.2/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= 353 + github.com/puzpuzpuz/xsync/v4 v4.2.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo= 354 + github.com/quasilyte/go-ruleguard/dsl v0.3.23/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= 355 + github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= 356 + github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= 357 + github.com/quic-go/webtransport-go v0.10.0/go.mod h1:LeGIXr5BQKE3UsynwVBeQrU1TPrbh73MGoC6jd+V7ow= 358 + github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= 359 + github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 360 + github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 361 + github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= 362 + github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= 363 + github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= 364 + github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= 365 + github.com/samber/slog-echo v1.8.0/go.mod h1:0ab2AwcciQXNAXEcjkHwD9okOh9vEHEYn8xP97ocuhM= 366 + github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= 367 + github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= 368 + github.com/secure-systems-lab/go-securesystemslib v0.9.0/go.mod h1:DVHKMcZ+V4/woA/peqr+L0joiRXbPpQ042GgJckkFgw= 369 + github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= 370 + github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE= 371 + github.com/sigstore/protobuf-specs v0.4.1/go.mod h1:+gXR+38nIa2oEupqDdzg4qSBT0Os+sP7oYv6alWewWc= 372 + github.com/sigstore/sigstore v1.9.5/go.mod h1:VtxgvGqCmEZN9X2zhFSOkfXxvKUjpy8RpUW39oCtoII= 373 + github.com/slok/go-http-metrics v0.13.0/go.mod h1:HIr7t/HbN2sJaunvnt9wKP9xoBBVZFo1/KiHU3b0w+4= 374 + github.com/smallstep/pkcs7 v0.1.1/go.mod h1:dL6j5AIz9GHjVEBTXtW+QliALcgM19RtXaTeyxI+AfA= 375 + github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= 376 + github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6/go.mod h1:39R/xuhNgVhi+K0/zst4TLrJrVmbm6LVgl4A0+ZFS5M= 377 + github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 378 + github.com/tchap/go-patricia/v2 v2.3.3/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= 379 + github.com/tetratelabs/wazero v1.10.1/go.mod h1:DRm5twOQ5Gr1AoEdSi0CLjDQF1J9ZAuyqFIjl1KKfQU= 380 + github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= 381 + github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= 382 + github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= 383 + github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= 384 + github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= 385 + github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb/go.mod h1:ikPs9bRWicNw3S7XpJ8sK/smGwU9WcSVU3dy9qahYBM= 386 + github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po= 387 + github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= 388 + github.com/urfave/cli/v3 v3.4.1/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo= 389 + github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 390 + github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 391 + github.com/veraison/go-cose v1.1.0/go.mod h1:7ziE85vSq4ScFTg6wyoMXjucIGOf4JkFEZi/an96Ct4= 392 + github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4= 393 + github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= 394 + github.com/vmihailenco/go-tinylfu v0.2.2/go.mod h1:CutYi2Q9puTxfcolkliPq4npPuofg9N9t8JVrjzwa3Q= 395 + github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= 396 + github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= 397 + github.com/wagoodman/go-presenter v0.0.0-20211015174752-f9c01afc824b/go.mod h1:ewlIKbKV8l+jCj8rkdXIs361ocR5x3qGyoCSca47Gx8= 398 + github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM= 399 + github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8= 400 + github.com/whyrusleeping/go-did v0.0.0-20230824162731-404d1707d5d6/go.mod h1:39U9RRVr4CKbXpXYopWn+FSH5s+vWu6+RmguSPWAq5s= 401 + github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= 402 + github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= 403 + github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= 404 + github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= 405 + github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= 406 + github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= 407 + github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= 408 + github.com/yashtewari/glob-intersection v0.2.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok= 409 + github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= 410 + github.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1/go.mod h1:ly2RBz4mnz1yeuVbQA/VFwGjK3mnHGRj1JuoG336Bis= 411 + go.etcd.io/gofail v0.2.0/go.mod h1:nL3ILMGfkXTekKI3clMBNazKnjUZjYLKmBHzsVAnC1o= 412 + go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.64.0/go.mod h1:LgtjWWXo7OpbSMkXnTlT2jrGtdI6Fmipn8UJCIgbqzg= 413 + go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.45.0/go.mod h1:Px9kH7SJ+NhsgWRtD/eMcs15Tyt4uL3rM7X54qv6pfA= 414 + go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= 415 + go.opentelemetry.io/otel/exporters/jaeger v1.14.0/go.mod h1:4Ay9kk5vELRrbg5z4cpP9EtmQRFap2Wb0woPG4lujZA= 416 + go.opentelemetry.io/otel/exporters/zipkin v1.38.0/go.mod h1:Su/nq/K5zRjDKKC3Il0xbViE3juWgG3JDoqLumFx5G0= 417 + go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= 418 + go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= 419 + go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= 420 + go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 421 + go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= 422 + go.uber.org/dig v1.19.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= 423 + go.uber.org/fx v1.24.0/go.mod h1:AmDeGyS+ZARGKM4tlH4FY2Jr63VjbEDJHtqXTGP5hbo= 424 + go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= 425 + golang.org/x/exp/shiny v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:3F+MieQB7dRYLTmnncoFbb1crS5lfQoTfDgQy6K4N0o= 426 + golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs= 427 + golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 428 + golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 429 + golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= 430 + golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= 431 + golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= 432 + golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= 433 + golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= 434 + golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= 435 + golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= 436 + golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 437 + golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 438 + golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 439 + golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 440 + golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 441 + golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 442 + golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 443 + golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 444 + golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 445 + golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2/go.mod h1:b7fPSJ0pKZ3ccUh8gnTONJxhn3c/PS6tyzQvyqw4iA8= 446 + golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= 447 + golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= 448 + golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= 449 + golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 450 + golang.org/x/tools v0.0.0-20200317205521-2944c61d58b4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 451 + golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= 452 + golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= 453 + golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 454 + golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= 455 + golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8= 456 + gonum.org/v1/plot v0.15.2/go.mod h1:DX+x+DWso3LTha+AdkJEv5Txvi+Tql3KAGkehP0/Ubg= 457 + gonum.org/v1/tools v0.0.0-20200318103217-c168b003ce8c/go.mod h1:fy6Otjqbk477ELp8IXTpw1cObQtLbRCBVonY+bTTfcM= 458 + google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= 459 + google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= 460 + google.golang.org/genproto/googleapis/api v0.0.0-20260203192932-546029d2fa20 h1:7ei4lp52gK1uSejlA8AZl5AJjeLUOHBQscRQZUgAcu0= 461 + google.golang.org/genproto/googleapis/api v0.0.0-20260203192932-546029d2fa20/go.mod h1:ZdbssH/1SOVnjnDlXzxDHK2MCidiqXtbYccJNzNYPEE= 462 + google.golang.org/genproto/googleapis/bytestream v0.0.0-20251103181224-f26f9409b101/go.mod h1:ejCb7yLmK6GCVHp5qpeKbm4KZew/ldg+9b8kq5MONgk= 463 + google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= 464 + google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= 465 + google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 h1:Jr5R2J6F6qWyzINc+4AM8t5pfUz6beZpHp678GNrMbE= 466 + google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= 467 + google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= 468 + google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA= 469 + google.golang.org/grpc/examples v0.0.0-20250407062114-b368379ef8f6/go.mod h1:6ytKWczdvnpnO+m+JiG9NjEDzR1FJfsnmJdG7B8QVZ8= 470 + google.golang.org/grpc/stats/opentelemetry v0.0.0-20240907200651-3ffb98b2c93a h1:UIpYSuWdWHSzjwcAFRLjKcPXFZVVLXGEM23W+NWqipw= 471 + google.golang.org/grpc/stats/opentelemetry v0.0.0-20240907200651-3ffb98b2c93a/go.mod h1:9i1T9n4ZinTUZGgzENMi8MDDgbGC5mqTS75JAv6xN3A= 472 + google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 473 + gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= 474 + gorm.io/plugin/opentelemetry v0.1.3/go.mod h1:tndJHOdvPT0pyGhOb8E2209eXJCUxhC5UpKw7bGVWeI= 475 + honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= 476 + k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk= 477 + k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= 478 + k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8= 479 + k8s.io/cri-api v0.34.1/go.mod h1:4qVUjidMg7/Z9YGZpqIDygbkPWkg3mkS1PvOx/kpHTE= 480 + k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= 481 + k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= 482 + lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= 483 + modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y= 484 + modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI= 485 + rsc.io/goversion v1.2.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo= 486 + rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 487 + sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= 488 + sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= 489 + sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= 490 + sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= 491 + tags.cncf.io/container-device-interface v1.1.0/go.mod h1:76Oj0Yqp9FwTx/pySDc8Bxjpg+VqXfDb50cKAXVJ34Q= 492 + tags.cncf.io/container-device-interface/specs-go v1.1.0/go.mod h1:u86hoFWqnh3hWz3esofRFKbI261bUlvUfLKGrDhJkgQ=
+1 -1
pkg/appview/jetstream/processor.go
··· 38 38 db: database, 39 39 useCache: useCache, 40 40 statsCache: statsCache, 41 - catalog: &catalog, 41 + catalog: catalog, 42 42 } 43 43 44 44 if useCache {
+1 -1
pkg/atproto/directory.go
··· 55 55 // - errTTL: 2 minutes 56 56 // - invalidHandleTTL: 5 minutes 57 57 cached := identity.NewCacheDirectory(&base, 250_000, time.Hour*24, time.Minute*2, time.Minute*5) 58 - sharedDirectory = &cached 58 + sharedDirectory = cached 59 59 }) 60 60 return sharedDirectory 61 61 }
+7
pkg/atproto/endpoints.go
··· 75 75 // Response: {"status": "pending"|"approved"} 76 76 HoldRequestCrew = "/xrpc/io.atcr.hold.requestCrew" 77 77 78 + // HoldSubscribeScanJobs subscribes to scan jobs via WebSocket (scanner → hold). 79 + // Method: GET (WebSocket upgrade) 80 + // Query: cursor={lastSeq} 81 + // Auth: Shared secret (query param or header) 82 + // Response: Stream of scan job events (JSON) 83 + HoldSubscribeScanJobs = "/xrpc/io.atcr.hold.subscribeScanJobs" 84 + 78 85 // Future: HoldDelegateAccess = "/xrpc/io.atcr.hold.delegateAccess" 79 86 ) 80 87
+10
pkg/hold/config.go
··· 34 34 Database DatabaseConfig `yaml:"database" comment:"Embedded PDS database settings."` 35 35 Admin AdminConfig `yaml:"admin" comment:"Admin panel settings."` 36 36 Quota quota.Config `yaml:"quota" comment:"Storage quota tiers. Empty disables quota enforcement."` 37 + Scanner ScannerConfig `yaml:"scanner" comment:"Vulnerability scanner settings. Empty disables scanning."` 37 38 configPath string `yaml:"-"` // internal: path to YAML file for subsystem config loading 38 39 } 39 40 ··· 125 126 WriteTimeout time.Duration `yaml:"write_timeout" comment:"Write timeout for HTTP requests."` 126 127 } 127 128 129 + // ScannerConfig defines vulnerability scanner settings 130 + type ScannerConfig struct { 131 + // Shared secret for scanner WebSocket authentication. Empty disables scanning. 132 + Secret string `yaml:"secret" comment:"Shared secret for scanner WebSocket auth. Empty disables scanning."` 133 + } 134 + 128 135 // DatabaseConfig defines embedded PDS database settings 129 136 type DatabaseConfig struct { 130 137 // Directory for the embedded PDS database. ··· 167 174 v.SetDefault("storage.region", "us-east-1") 168 175 v.SetDefault("storage.bucket", "") 169 176 v.SetDefault("storage.endpoint", "") 177 + 178 + // Scanner defaults 179 + v.SetDefault("scanner.secret", "") 170 180 171 181 // Log shipper defaults 172 182 v.SetDefault("log_shipper.batch_size", 100)
+12 -13
pkg/hold/oci/multipart.go
··· 10 10 "time" 11 11 12 12 "atcr.io/pkg/s3" 13 - awss3 "github.com/aws/aws-sdk-go/service/s3" 13 + awss3 "github.com/aws/aws-sdk-go-v2/service/s3" 14 + s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" 14 15 "github.com/google/uuid" 15 16 ) 16 17 ··· 143 144 s3Key = h.s3Service.PathPrefix + "/" + s3Key 144 145 } 145 146 146 - result, err := h.s3Service.Client.CreateMultipartUploadWithContext(ctx, &awss3.CreateMultipartUploadInput{ 147 + result, err := h.s3Service.Client.CreateMultipartUpload(ctx, &awss3.CreateMultipartUploadInput{ 147 148 Bucket: &h.s3Service.Bucket, 148 149 Key: &s3Key, 149 150 }) ··· 176 177 if h.s3Service.PathPrefix != "" { 177 178 s3Key = h.s3Service.PathPrefix + "/" + s3Key 178 179 } 179 - pnum := int64(partNumber) 180 - req := h.s3Service.Client.UploadPartPresignable(&awss3.UploadPartInput{ 180 + pnum := int32(partNumber) 181 + url, err := h.s3Service.Client.PresignUploadPart(ctx, &awss3.UploadPartInput{ 181 182 Bucket: &h.s3Service.Bucket, 182 183 Key: &s3Key, 183 184 UploadId: &session.S3UploadID, 184 185 PartNumber: &pnum, 185 - }) 186 - 187 - url, err := req.Presign(15 * time.Minute) 186 + }, 15*time.Minute) 188 187 if err != nil { 189 188 return nil, err 190 189 } ··· 220 219 221 220 // Convert to S3 CompletedPart format 222 221 // IMPORTANT: S3 requires ETags to be quoted in the CompleteMultipartUpload XML 223 - s3Parts := make([]*awss3.CompletedPart, len(parts)) 222 + s3Parts := make([]s3types.CompletedPart, len(parts)) 224 223 for i, p := range parts { 225 224 etag := normalizeETag(p.ETag) 226 - pnum := int64(p.PartNumber) 227 - s3Parts[i] = &awss3.CompletedPart{ 225 + pnum := int32(p.PartNumber) 226 + s3Parts[i] = s3types.CompletedPart{ 228 227 PartNumber: &pnum, 229 228 ETag: &etag, 230 229 } ··· 235 234 s3Key = h.s3Service.PathPrefix + "/" + s3Key 236 235 } 237 236 238 - _, err = h.s3Service.Client.CompleteMultipartUploadWithContext(ctx, &awss3.CompleteMultipartUploadInput{ 237 + _, err = h.s3Service.Client.CompleteMultipartUpload(ctx, &awss3.CompleteMultipartUploadInput{ 239 238 Bucket: &h.s3Service.Bucket, 240 239 Key: &s3Key, 241 240 UploadId: &session.S3UploadID, 242 - MultipartUpload: &awss3.CompletedMultipartUpload{ 241 + MultipartUpload: &s3types.CompletedMultipartUpload{ 243 242 Parts: s3Parts, 244 243 }, 245 244 }) ··· 301 300 s3Key = h.s3Service.PathPrefix + "/" + s3Key 302 301 } 303 302 304 - _, err = h.s3Service.Client.AbortMultipartUploadWithContext(ctx, &awss3.AbortMultipartUploadInput{ 303 + _, err = h.s3Service.Client.AbortMultipartUpload(ctx, &awss3.AbortMultipartUploadInput{ 305 304 Bucket: &h.s3Service.Bucket, 306 305 Key: &s3Key, 307 306 UploadId: &session.S3UploadID,
+40 -1
pkg/hold/oci/xrpc.go
··· 2 2 package oci 3 3 4 4 import ( 5 + "encoding/json" 5 6 "fmt" 6 7 "log/slog" 7 8 "net/http" ··· 24 25 pds *pds.HoldPDS 25 26 httpClient pds.HTTPClient 26 27 enableBlueskyPosts bool 27 - quotaMgr *quota.Manager // Quota manager for tier-based limits 28 + quotaMgr *quota.Manager // Quota manager for tier-based limits 29 + scanBroadcaster *pds.ScanBroadcaster // Scan job dispatcher (nil = scanning disabled) 28 30 } 29 31 30 32 // NewXRPCHandler creates a new OCI XRPC handler ··· 38 40 enableBlueskyPosts: enableBlueskyPosts, 39 41 quotaMgr: quotaMgr, 40 42 } 43 + } 44 + 45 + // SetScanBroadcaster sets the scan broadcaster for triggering scans on push 46 + func (h *XRPCHandler) SetScanBroadcaster(sb *pds.ScanBroadcaster) { 47 + h.scanBroadcaster = sb 41 48 } 42 49 43 50 // RegisterHandlers registers all OCI XRPC endpoints with the chi router ··· 373 380 slog.Error("Failed to create manifest post", "error", err) 374 381 } else { 375 382 postCreated = true 383 + } 384 + } 385 + 386 + // Enqueue scan job if scanner is connected 387 + if h.scanBroadcaster != nil { 388 + tier := "deckhand" 389 + if stats != nil && stats.Tier != "" { 390 + tier = stats.Tier 391 + } 392 + 393 + configJSON, _ := json.Marshal(req.Manifest.Config) 394 + layersJSON, _ := json.Marshal(req.Manifest.Layers) 395 + 396 + // Resolve handle for scanner context 397 + _, userHandle, _, resolveErr := atproto.ResolveIdentity(ctx, req.UserDID) 398 + if resolveErr != nil { 399 + userHandle = req.UserDID 400 + } 401 + 402 + if err := h.scanBroadcaster.Enqueue(&pds.ScanJobEvent{ 403 + ManifestDigest: req.ManifestDigest, 404 + Repository: req.Repository, 405 + Tag: req.Tag, 406 + UserDID: req.UserDID, 407 + UserHandle: userHandle, 408 + Tier: tier, 409 + Config: configJSON, 410 + Layers: layersJSON, 411 + }); err != nil { 412 + slog.Error("Failed to enqueue scan job", 413 + "repository", req.Repository, 414 + "error", err) 376 415 } 377 416 } 378 417 }
+3 -1
pkg/hold/pds/events.go
··· 328 328 } 329 329 330 330 // Subscribe adds a new WebSocket subscriber 331 - func (b *EventBroadcaster) Subscribe(conn *websocket.Conn, cursor int64) *Subscriber { 331 + func (b *EventBroadcaster) Subscribe(conn *websocket.Conn, cursor int64, userAgent string) *Subscriber { 332 332 sub := &Subscriber{ 333 333 conn: conn, 334 334 send: make(chan *RepoCommitEvent, 10), // Buffer 10 events ··· 339 339 b.subscribers[sub] = true 340 340 currentSeq := b.eventSeq 341 341 b.mu.Unlock() 342 + 343 + slog.Info("New firehose subscriber", "remote", conn.RemoteAddr(), "cursor", cursor, "currentSeq", currentSeq, "userAgent", userAgent) 342 344 343 345 // Handle cursor-based backfill: 344 346 // - cursor < 0: No backfill, stream new events only
+1 -1
pkg/hold/pds/repomgr.go
··· 62 62 kmgr: kmgr, 63 63 log: slog.Default().With("system", "repomgr"), 64 64 noArchive: noArchive, 65 - clk: &clk, 65 + clk: clk, 66 66 } 67 67 } 68 68
+684
pkg/hold/pds/scan_broadcaster.go
··· 1 + package pds 2 + 3 + import ( 4 + "context" 5 + "crypto/rand" 6 + "crypto/sha256" 7 + "database/sql" 8 + "encoding/hex" 9 + "encoding/json" 10 + "fmt" 11 + "log/slog" 12 + "sync" 13 + "time" 14 + 15 + storagedriver "github.com/distribution/distribution/v3/registry/storage/driver" 16 + "github.com/gorilla/websocket" 17 + ) 18 + 19 + // ScanBroadcaster manages scanner WebSocket connections and dispatches scan jobs 20 + // using a competing-consumer pattern. Jobs are persisted in SQLite and dispatched 21 + // round-robin to connected scanners. 22 + type ScanBroadcaster struct { 23 + mu sync.RWMutex 24 + subscribers []*ScanSubscriber 25 + nextIdx int // Round-robin index for dispatch 26 + db *sql.DB 27 + holdDID string 28 + holdEndpoint string 29 + driver storagedriver.StorageDriver 30 + pds *HoldPDS 31 + ackTimeout time.Duration 32 + secret string // Shared secret for scanner authentication 33 + } 34 + 35 + // ScanSubscriber represents a connected scanner WebSocket client 36 + type ScanSubscriber struct { 37 + conn *websocket.Conn 38 + send chan *ScanJobEvent 39 + id string // Unique subscriber ID 40 + done chan struct{} 41 + } 42 + 43 + // ScanJobEvent is the message sent from hold to scanner over WebSocket 44 + type ScanJobEvent struct { 45 + Type string `json:"type"` // Always "job" 46 + Seq int64 `json:"seq"` 47 + ManifestDigest string `json:"manifestDigest"` 48 + Repository string `json:"repository"` 49 + Tag string `json:"tag"` 50 + UserDID string `json:"userDid"` 51 + UserHandle string `json:"userHandle"` 52 + HoldDID string `json:"holdDid"` 53 + HoldEndpoint string `json:"holdEndpoint"` 54 + Tier string `json:"tier"` 55 + Config json.RawMessage `json:"config"` 56 + Layers json.RawMessage `json:"layers"` 57 + } 58 + 59 + // ScannerMessage is a message received from scanner over WebSocket 60 + type ScannerMessage struct { 61 + Type string `json:"type"` // "ack", "result", "error" 62 + Seq int64 `json:"seq"` // Job sequence number 63 + SBOM string `json:"sbom,omitempty"` 64 + VulnReport string `json:"vulnReport,omitempty"` 65 + Summary *VulnerabilitySummary `json:"summary,omitempty"` 66 + Error string `json:"error,omitempty"` 67 + } 68 + 69 + // VulnerabilitySummary contains counts of vulnerabilities by severity 70 + type VulnerabilitySummary struct { 71 + Critical int `json:"critical"` 72 + High int `json:"high"` 73 + Medium int `json:"medium"` 74 + Low int `json:"low"` 75 + Total int `json:"total"` 76 + } 77 + 78 + // NewScanBroadcaster creates a new scan job broadcaster 79 + // dbPath should point to a SQLite database file (e.g., "/path/to/pds/db.sqlite3") 80 + func NewScanBroadcaster(holdDID, holdEndpoint, secret, dbPath string, driver storagedriver.StorageDriver, holdPDS *HoldPDS) (*ScanBroadcaster, error) { 81 + db, err := sql.Open("sqlite3", dbPath) 82 + if err != nil { 83 + return nil, fmt.Errorf("failed to open scan jobs database: %w", err) 84 + } 85 + if err := db.Ping(); err != nil { 86 + db.Close() 87 + return nil, fmt.Errorf("failed to ping scan jobs database: %w", err) 88 + } 89 + 90 + sb := &ScanBroadcaster{ 91 + subscribers: make([]*ScanSubscriber, 0), 92 + db: db, 93 + holdDID: holdDID, 94 + holdEndpoint: holdEndpoint, 95 + driver: driver, 96 + pds: holdPDS, 97 + ackTimeout: 5 * time.Minute, 98 + secret: secret, 99 + } 100 + 101 + if err := sb.initSchema(); err != nil { 102 + db.Close() 103 + return nil, fmt.Errorf("failed to initialize scan_jobs schema: %w", err) 104 + } 105 + 106 + // Start re-dispatch loop for timed-out jobs 107 + go sb.reDispatchLoop() 108 + 109 + return sb, nil 110 + } 111 + 112 + // initSchema creates the scan_jobs table if it doesn't exist 113 + func (sb *ScanBroadcaster) initSchema() error { 114 + schema := ` 115 + CREATE TABLE IF NOT EXISTS scan_jobs ( 116 + seq INTEGER PRIMARY KEY AUTOINCREMENT, 117 + manifest_digest TEXT NOT NULL, 118 + repository TEXT NOT NULL, 119 + tag TEXT, 120 + user_did TEXT NOT NULL, 121 + user_handle TEXT, 122 + hold_did TEXT NOT NULL, 123 + hold_endpoint TEXT NOT NULL, 124 + tier TEXT NOT NULL DEFAULT 'deckhand', 125 + config_json TEXT NOT NULL, 126 + layers_json TEXT NOT NULL, 127 + status TEXT NOT NULL DEFAULT 'pending', 128 + assigned_to TEXT, 129 + assigned_at TIMESTAMP, 130 + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, 131 + completed_at TIMESTAMP 132 + ); 133 + CREATE INDEX IF NOT EXISTS idx_scan_jobs_status ON scan_jobs(status); 134 + CREATE INDEX IF NOT EXISTS idx_scan_jobs_assigned ON scan_jobs(assigned_to, status); 135 + ` 136 + _, err := sb.db.Exec(schema) 137 + return err 138 + } 139 + 140 + // Enqueue inserts a scan job into SQLite and dispatches to the next available scanner 141 + func (sb *ScanBroadcaster) Enqueue(job *ScanJobEvent) error { 142 + job.Type = "job" 143 + job.HoldDID = sb.holdDID 144 + job.HoldEndpoint = sb.holdEndpoint 145 + 146 + // Insert into database 147 + result, err := sb.db.Exec(` 148 + INSERT INTO scan_jobs (manifest_digest, repository, tag, user_did, user_handle, hold_did, hold_endpoint, tier, config_json, layers_json, status) 149 + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending') 150 + `, job.ManifestDigest, job.Repository, job.Tag, job.UserDID, job.UserHandle, job.HoldDID, job.HoldEndpoint, job.Tier, string(job.Config), string(job.Layers)) 151 + if err != nil { 152 + return fmt.Errorf("failed to insert scan job: %w", err) 153 + } 154 + 155 + seq, err := result.LastInsertId() 156 + if err != nil { 157 + return fmt.Errorf("failed to get job seq: %w", err) 158 + } 159 + job.Seq = seq 160 + 161 + slog.Info("Scan job enqueued", 162 + "seq", seq, 163 + "repository", job.Repository, 164 + "tag", job.Tag, 165 + "tier", job.Tier) 166 + 167 + // Try to dispatch immediately 168 + sb.dispatchJob(job) 169 + 170 + return nil 171 + } 172 + 173 + // Subscribe adds a new scanner WebSocket subscriber and drains pending jobs to it 174 + func (sb *ScanBroadcaster) Subscribe(conn *websocket.Conn, cursor int64) *ScanSubscriber { 175 + id := generateSubscriberID() 176 + sub := &ScanSubscriber{ 177 + conn: conn, 178 + send: make(chan *ScanJobEvent, 20), 179 + id: id, 180 + done: make(chan struct{}), 181 + } 182 + 183 + sb.mu.Lock() 184 + sb.subscribers = append(sb.subscribers, sub) 185 + sb.mu.Unlock() 186 + 187 + slog.Info("Scanner subscribed", 188 + "id", id, 189 + "remote", conn.RemoteAddr(), 190 + "cursor", cursor, 191 + "totalSubscribers", len(sb.subscribers)) 192 + 193 + // Start writer goroutine (sends jobs to scanner) 194 + go sb.handleWriter(sub) 195 + 196 + // Start reader goroutine (receives acks/results/errors from scanner) 197 + go sb.handleReader(sub) 198 + 199 + // Drain pending and timed-out jobs from database 200 + go sb.drainPendingJobs(sub, cursor) 201 + 202 + return sub 203 + } 204 + 205 + // Unsubscribe removes a scanner subscriber and makes its jobs re-dispatchable 206 + func (sb *ScanBroadcaster) Unsubscribe(sub *ScanSubscriber) { 207 + sb.mu.Lock() 208 + defer sb.mu.Unlock() 209 + 210 + for i, s := range sb.subscribers { 211 + if s == sub { 212 + sb.subscribers = append(sb.subscribers[:i], sb.subscribers[i+1:]...) 213 + break 214 + } 215 + } 216 + 217 + // Mark assigned jobs as pending again so they can be re-dispatched 218 + _, err := sb.db.Exec(` 219 + UPDATE scan_jobs SET status = 'pending', assigned_to = NULL, assigned_at = NULL 220 + WHERE assigned_to = ? AND status IN ('pending', 'assigned') 221 + `, sub.id) 222 + if err != nil { 223 + slog.Error("Failed to unassign jobs from disconnected scanner", 224 + "subscriberId", sub.id, 225 + "error", err) 226 + } 227 + 228 + close(sub.send) 229 + 230 + slog.Info("Scanner unsubscribed", 231 + "id", sub.id, 232 + "totalSubscribers", len(sb.subscribers)) 233 + } 234 + 235 + // dispatchJob sends a job to the next available scanner via round-robin 236 + func (sb *ScanBroadcaster) dispatchJob(job *ScanJobEvent) { 237 + sb.mu.Lock() 238 + defer sb.mu.Unlock() 239 + 240 + if len(sb.subscribers) == 0 { 241 + slog.Debug("No scanners connected, job will wait in queue", "seq", job.Seq) 242 + return 243 + } 244 + 245 + // Round-robin dispatch 246 + sub := sb.subscribers[sb.nextIdx%len(sb.subscribers)] 247 + sb.nextIdx++ 248 + 249 + // Mark as assigned in database 250 + _, err := sb.db.Exec(` 251 + UPDATE scan_jobs SET status = 'assigned', assigned_to = ?, assigned_at = ? 252 + WHERE seq = ? AND status = 'pending' 253 + `, sub.id, time.Now(), job.Seq) 254 + if err != nil { 255 + slog.Error("Failed to assign scan job", "seq", job.Seq, "error", err) 256 + return 257 + } 258 + 259 + // Send to subscriber 260 + select { 261 + case sub.send <- job: 262 + slog.Info("Scan job dispatched", 263 + "seq", job.Seq, 264 + "repository", job.Repository, 265 + "subscriberId", sub.id) 266 + default: 267 + slog.Warn("Scanner buffer full, re-marking job as pending", 268 + "seq", job.Seq, 269 + "subscriberId", sub.id) 270 + sb.db.Exec(`UPDATE scan_jobs SET status = 'pending', assigned_to = NULL, assigned_at = NULL WHERE seq = ?`, job.Seq) 271 + } 272 + } 273 + 274 + // handleWriter sends jobs to a scanner over its WebSocket connection 275 + func (sb *ScanBroadcaster) handleWriter(sub *ScanSubscriber) { 276 + defer func() { 277 + sub.conn.Close() 278 + close(sub.done) 279 + }() 280 + 281 + for job := range sub.send { 282 + data, err := json.Marshal(job) 283 + if err != nil { 284 + slog.Error("Failed to marshal scan job", "seq", job.Seq, "error", err) 285 + continue 286 + } 287 + 288 + if err := sub.conn.WriteMessage(websocket.TextMessage, data); err != nil { 289 + slog.Error("Failed to write scan job to WebSocket", 290 + "seq", job.Seq, 291 + "subscriberId", sub.id, 292 + "error", err) 293 + sb.Unsubscribe(sub) 294 + return 295 + } 296 + } 297 + } 298 + 299 + // handleReader receives ack/result/error messages from a scanner 300 + func (sb *ScanBroadcaster) handleReader(sub *ScanSubscriber) { 301 + defer sb.Unsubscribe(sub) 302 + 303 + for { 304 + _, data, err := sub.conn.ReadMessage() 305 + if err != nil { 306 + if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseNormalClosure) { 307 + slog.Error("Scanner WebSocket read error", 308 + "subscriberId", sub.id, 309 + "error", err) 310 + } 311 + return 312 + } 313 + 314 + var msg ScannerMessage 315 + if err := json.Unmarshal(data, &msg); err != nil { 316 + slog.Error("Failed to unmarshal scanner message", 317 + "subscriberId", sub.id, 318 + "error", err) 319 + continue 320 + } 321 + 322 + switch msg.Type { 323 + case "ack": 324 + sb.handleAck(sub, msg.Seq) 325 + case "result": 326 + sb.handleResult(sub, msg) 327 + case "error": 328 + sb.handleError(sub, msg) 329 + default: 330 + slog.Warn("Unknown scanner message type", 331 + "type", msg.Type, 332 + "subscriberId", sub.id) 333 + } 334 + } 335 + } 336 + 337 + // handleAck marks a job as processing (scanner received and queued it) 338 + func (sb *ScanBroadcaster) handleAck(sub *ScanSubscriber, seq int64) { 339 + _, err := sb.db.Exec(` 340 + UPDATE scan_jobs SET status = 'processing' 341 + WHERE seq = ? AND assigned_to = ? AND status = 'assigned' 342 + `, seq, sub.id) 343 + if err != nil { 344 + slog.Error("Failed to update job status to processing", 345 + "seq", seq, 346 + "subscriberId", sub.id, 347 + "error", err) 348 + return 349 + } 350 + 351 + slog.Info("Scan job acknowledged", 352 + "seq", seq, 353 + "subscriberId", sub.id) 354 + } 355 + 356 + // handleResult processes a completed scan result: stores ORAS manifest + marks completed 357 + func (sb *ScanBroadcaster) handleResult(sub *ScanSubscriber, msg ScannerMessage) { 358 + ctx := context.Background() 359 + 360 + slog.Info("Scan result received", 361 + "seq", msg.Seq, 362 + "subscriberId", sub.id, 363 + "hasSBOM", msg.SBOM != "", 364 + "hasVulnReport", msg.VulnReport != "", 365 + "summary", msg.Summary) 366 + 367 + // Get job details from database 368 + var ( 369 + manifestDigest string 370 + repository string 371 + tag string 372 + userDID string 373 + ) 374 + err := sb.db.QueryRow(` 375 + SELECT manifest_digest, repository, tag, user_did 376 + FROM scan_jobs WHERE seq = ? 377 + `, msg.Seq).Scan(&manifestDigest, &repository, &tag, &userDID) 378 + if err != nil { 379 + slog.Error("Failed to get job details for result storage", 380 + "seq", msg.Seq, 381 + "error", err) 382 + return 383 + } 384 + 385 + // Store vulnerability report blob in S3 386 + if msg.VulnReport != "" { 387 + vulnJSON := []byte(msg.VulnReport) 388 + vulnDigest := fmt.Sprintf("sha256:%x", sha256.Sum256(vulnJSON)) 389 + 390 + if err := sb.uploadBlob(ctx, vulnDigest, vulnJSON); err != nil { 391 + slog.Error("Failed to upload vulnerability report blob", 392 + "seq", msg.Seq, 393 + "error", err) 394 + } 395 + 396 + // Build and store ORAS manifest 397 + if msg.Summary != nil { 398 + if err := sb.storeORASManifest(ctx, manifestDigest, repository, userDID, vulnDigest, vulnJSON, *msg.Summary); err != nil { 399 + slog.Error("Failed to store ORAS manifest", 400 + "seq", msg.Seq, 401 + "error", err) 402 + } 403 + } 404 + } 405 + 406 + // Store SBOM blob if provided 407 + if msg.SBOM != "" { 408 + sbomJSON := []byte(msg.SBOM) 409 + sbomDigest := fmt.Sprintf("sha256:%x", sha256.Sum256(sbomJSON)) 410 + 411 + if err := sb.uploadBlob(ctx, sbomDigest, sbomJSON); err != nil { 412 + slog.Error("Failed to upload SBOM blob", 413 + "seq", msg.Seq, 414 + "error", err) 415 + } 416 + } 417 + 418 + // Mark job as completed 419 + _, err = sb.db.Exec(` 420 + UPDATE scan_jobs SET status = 'completed', completed_at = ? 421 + WHERE seq = ? 422 + `, time.Now(), msg.Seq) 423 + if err != nil { 424 + slog.Error("Failed to mark scan job as completed", 425 + "seq", msg.Seq, 426 + "error", err) 427 + } 428 + 429 + slog.Info("Scan job completed", 430 + "seq", msg.Seq, 431 + "repository", repository, 432 + "tag", tag, 433 + "critical", msg.Summary.Critical, 434 + "high", msg.Summary.High, 435 + "total", msg.Summary.Total) 436 + } 437 + 438 + // handleError marks a job as failed 439 + func (sb *ScanBroadcaster) handleError(sub *ScanSubscriber, msg ScannerMessage) { 440 + _, err := sb.db.Exec(` 441 + UPDATE scan_jobs SET status = 'failed', completed_at = ? 442 + WHERE seq = ? 443 + `, time.Now(), msg.Seq) 444 + if err != nil { 445 + slog.Error("Failed to mark scan job as failed", 446 + "seq", msg.Seq, 447 + "error", err) 448 + } 449 + 450 + slog.Warn("Scan job failed", 451 + "seq", msg.Seq, 452 + "subscriberId", sub.id, 453 + "error", msg.Error) 454 + } 455 + 456 + // drainPendingJobs sends pending/timed-out jobs to a newly connected scanner 457 + func (sb *ScanBroadcaster) drainPendingJobs(sub *ScanSubscriber, cursor int64) { 458 + rows, err := sb.db.Query(` 459 + SELECT seq, manifest_digest, repository, tag, user_did, user_handle, hold_did, hold_endpoint, tier, config_json, layers_json 460 + FROM scan_jobs 461 + WHERE status = 'pending' AND seq > ? 462 + ORDER BY seq ASC 463 + `, cursor) 464 + if err != nil { 465 + slog.Error("Failed to drain pending scan jobs", "error", err) 466 + return 467 + } 468 + defer rows.Close() 469 + 470 + count := 0 471 + for rows.Next() { 472 + job := &ScanJobEvent{Type: "job"} 473 + var configJSON, layersJSON string 474 + 475 + err := rows.Scan( 476 + &job.Seq, &job.ManifestDigest, &job.Repository, &job.Tag, 477 + &job.UserDID, &job.UserHandle, &job.HoldDID, &job.HoldEndpoint, 478 + &job.Tier, &configJSON, &layersJSON, 479 + ) 480 + if err != nil { 481 + slog.Error("Failed to scan pending job row", "error", err) 482 + continue 483 + } 484 + 485 + job.Config = json.RawMessage(configJSON) 486 + job.Layers = json.RawMessage(layersJSON) 487 + 488 + // Assign and dispatch 489 + _, err = sb.db.Exec(` 490 + UPDATE scan_jobs SET status = 'assigned', assigned_to = ?, assigned_at = ? 491 + WHERE seq = ? AND status = 'pending' 492 + `, sub.id, time.Now(), job.Seq) 493 + if err != nil { 494 + continue 495 + } 496 + 497 + select { 498 + case sub.send <- job: 499 + count++ 500 + case <-sub.done: 501 + return 502 + case <-time.After(5 * time.Second): 503 + slog.Warn("Drain timeout for scanner", "subscriberId", sub.id) 504 + return 505 + } 506 + } 507 + 508 + if count > 0 { 509 + slog.Info("Drained pending jobs to scanner", 510 + "subscriberId", sub.id, 511 + "jobsDrained", count) 512 + } 513 + } 514 + 515 + // reDispatchLoop periodically checks for timed-out jobs and re-dispatches them 516 + func (sb *ScanBroadcaster) reDispatchLoop() { 517 + ticker := time.NewTicker(30 * time.Second) 518 + defer ticker.Stop() 519 + 520 + for range ticker.C { 521 + sb.reDispatchTimedOut() 522 + } 523 + } 524 + 525 + // reDispatchTimedOut finds jobs that were assigned but not acked/completed within timeout 526 + func (sb *ScanBroadcaster) reDispatchTimedOut() { 527 + timeout := time.Now().Add(-sb.ackTimeout) 528 + 529 + rows, err := sb.db.Query(` 530 + SELECT seq, manifest_digest, repository, tag, user_did, user_handle, hold_did, hold_endpoint, tier, config_json, layers_json 531 + FROM scan_jobs 532 + WHERE status = 'assigned' AND assigned_at < ? 533 + ORDER BY seq ASC 534 + `, timeout) 535 + if err != nil { 536 + slog.Error("Failed to query timed-out scan jobs", "error", err) 537 + return 538 + } 539 + defer rows.Close() 540 + 541 + for rows.Next() { 542 + job := &ScanJobEvent{Type: "job"} 543 + var configJSON, layersJSON string 544 + 545 + err := rows.Scan( 546 + &job.Seq, &job.ManifestDigest, &job.Repository, &job.Tag, 547 + &job.UserDID, &job.UserHandle, &job.HoldDID, &job.HoldEndpoint, 548 + &job.Tier, &configJSON, &layersJSON, 549 + ) 550 + if err != nil { 551 + continue 552 + } 553 + 554 + job.Config = json.RawMessage(configJSON) 555 + job.Layers = json.RawMessage(layersJSON) 556 + 557 + // Reset to pending and re-dispatch 558 + _, err = sb.db.Exec(` 559 + UPDATE scan_jobs SET status = 'pending', assigned_to = NULL, assigned_at = NULL 560 + WHERE seq = ? 561 + `, job.Seq) 562 + if err != nil { 563 + continue 564 + } 565 + 566 + slog.Info("Re-dispatching timed-out scan job", 567 + "seq", job.Seq, 568 + "repository", job.Repository) 569 + 570 + sb.dispatchJob(job) 571 + } 572 + } 573 + 574 + // Close closes the scan broadcaster's database connection 575 + func (sb *ScanBroadcaster) Close() error { 576 + if sb.db != nil { 577 + return sb.db.Close() 578 + } 579 + return nil 580 + } 581 + 582 + // ValidateScannerSecret checks if the provided secret matches 583 + func (sb *ScanBroadcaster) ValidateScannerSecret(secret string) bool { 584 + return sb.secret != "" && secret == sb.secret 585 + } 586 + 587 + // storeORASManifest creates an ORAS vulnerability manifest as a blob in S3 588 + // The ORAS manifest's "subject" field references the original manifest by digest, 589 + // enabling OCI referrers API discovery. 590 + func (sb *ScanBroadcaster) storeORASManifest(ctx context.Context, manifestDigest, repository, userDID, vulnDigest string, vulnJSON []byte, summary VulnerabilitySummary) error { 591 + scannerVersion := "atcr-scanner-v1.0.0" 592 + 593 + // Create ORAS manifest 594 + orasManifest := map[string]interface{}{ 595 + "schemaVersion": 2, 596 + "mediaType": "application/vnd.oci.image.manifest.v1+json", 597 + "artifactType": "application/vnd.atcr.vulnerabilities+json", 598 + "config": map[string]interface{}{ 599 + "mediaType": "application/vnd.oci.empty.v1+json", 600 + "digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a", 601 + "size": 2, 602 + }, 603 + "subject": map[string]interface{}{ 604 + "mediaType": "application/vnd.oci.image.manifest.v1+json", 605 + "digest": manifestDigest, 606 + "size": 0, 607 + }, 608 + "layers": []map[string]interface{}{ 609 + { 610 + "mediaType": "application/json", 611 + "digest": vulnDigest, 612 + "size": len(vulnJSON), 613 + "annotations": map[string]string{ 614 + "org.opencontainers.image.title": "vulnerability-report.json", 615 + }, 616 + }, 617 + }, 618 + "annotations": map[string]string{ 619 + "io.atcr.vuln.critical": fmt.Sprintf("%d", summary.Critical), 620 + "io.atcr.vuln.high": fmt.Sprintf("%d", summary.High), 621 + "io.atcr.vuln.medium": fmt.Sprintf("%d", summary.Medium), 622 + "io.atcr.vuln.low": fmt.Sprintf("%d", summary.Low), 623 + "io.atcr.vuln.total": fmt.Sprintf("%d", summary.Total), 624 + "io.atcr.vuln.scannedAt": time.Now().Format(time.RFC3339), 625 + "io.atcr.vuln.scannerVersion": scannerVersion, 626 + "io.atcr.vuln.repository": repository, 627 + "io.atcr.vuln.ownerDid": userDID, 628 + "io.atcr.vuln.holdDid": sb.holdDID, 629 + }, 630 + } 631 + 632 + orasManifestJSON, err := json.Marshal(orasManifest) 633 + if err != nil { 634 + return fmt.Errorf("failed to encode ORAS manifest: %w", err) 635 + } 636 + 637 + orasHash := sha256.Sum256(orasManifestJSON) 638 + orasDigest := fmt.Sprintf("sha256:%x", orasHash) 639 + 640 + // Upload ORAS manifest blob to S3 641 + if err := sb.uploadBlob(ctx, orasDigest, orasManifestJSON); err != nil { 642 + return fmt.Errorf("failed to upload ORAS manifest blob: %w", err) 643 + } 644 + 645 + slog.Info("ORAS manifest stored", 646 + "digest", orasDigest, 647 + "repository", repository, 648 + "userDid", userDID, 649 + "critical", summary.Critical, 650 + "high", summary.High, 651 + "total", summary.Total) 652 + 653 + return nil 654 + } 655 + 656 + // uploadBlob uploads a blob to S3 storage 657 + func (sb *ScanBroadcaster) uploadBlob(ctx context.Context, digest string, data []byte) error { 658 + digestHex := digest[len("sha256:"):] 659 + if len(digestHex) < 2 { 660 + return fmt.Errorf("invalid digest: %s", digest) 661 + } 662 + 663 + blobPath := fmt.Sprintf("/docker/registry/v2/blobs/sha256/%s/%s/data", 664 + digestHex[:2], digestHex) 665 + 666 + writer, err := sb.driver.Writer(ctx, blobPath, false) 667 + if err != nil { 668 + return fmt.Errorf("failed to create storage writer: %w", err) 669 + } 670 + defer writer.Close() 671 + 672 + if _, err := writer.Write(data); err != nil { 673 + writer.Cancel(ctx) 674 + return fmt.Errorf("failed to write blob data: %w", err) 675 + } 676 + 677 + return writer.Commit(ctx) 678 + } 679 + 680 + func generateSubscriberID() string { 681 + b := make([]byte, 8) 682 + rand.Read(b) 683 + return hex.EncodeToString(b) 684 + }
+70 -20
pkg/hold/pds/xrpc.go
··· 30 30 31 31 "github.com/multiformats/go-multihash" 32 32 33 - awss3 "github.com/aws/aws-sdk-go/service/s3" 33 + awss3 "github.com/aws/aws-sdk-go-v2/service/s3" 34 34 ) 35 35 36 36 // XRPC handler for ATProto endpoints ··· 44 44 45 45 // XRPCHandler handles XRPC requests for the embedded PDS 46 46 type XRPCHandler struct { 47 - pds *HoldPDS 48 - s3Service s3.S3Service 49 - storageDriver driver.StorageDriver 50 - broadcaster *EventBroadcaster 51 - httpClient HTTPClient // For testing - allows injecting mock HTTP client 52 - quotaMgr *quota.Manager // Quota manager for tier-based limits 47 + pds *HoldPDS 48 + s3Service s3.S3Service 49 + storageDriver driver.StorageDriver 50 + broadcaster *EventBroadcaster 51 + scanBroadcaster *ScanBroadcaster // Scan job dispatcher for connected scanners 52 + httpClient HTTPClient // For testing - allows injecting mock HTTP client 53 + quotaMgr *quota.Manager // Quota manager for tier-based limits 53 54 } 54 55 55 56 // PartInfo represents a completed part in a multipart upload ··· 76 77 httpClient: httpClient, 77 78 quotaMgr: quotaMgr, 78 79 } 80 + } 81 + 82 + // SetScanBroadcaster sets the scan broadcaster for dispatching scan jobs to scanners 83 + func (h *XRPCHandler) SetScanBroadcaster(sb *ScanBroadcaster) { 84 + h.scanBroadcaster = sb 79 85 } 80 86 81 87 // CORSMiddleware returns a simple CORS middleware configured for ATProto ··· 203 209 204 210 // Public quota endpoint (no auth - quota is per-user, just needs userDid param) 205 211 r.Get(atproto.HoldGetQuota, h.HandleGetQuota) 212 + 213 + // Scanner WebSocket endpoint (shared secret auth) 214 + r.Get(atproto.HoldSubscribeScanJobs, h.HandleSubscribeScanJobs) 206 215 } 207 216 208 217 // HandleHealth returns health check information ··· 953 962 // Subscribe to events 954 963 // The broadcaster's handleSubscriber goroutine will manage this connection 955 964 // and handle cleanup when the client disconnects 956 - h.broadcaster.Subscribe(conn, cursor) 965 + h.broadcaster.Subscribe(conn, cursor, r.UserAgent()) 966 + } 967 + 968 + // HandleSubscribeScanJobs handles WebSocket connections from scanners 969 + // Scanners connect here to receive scan jobs and send back results 970 + func (h *XRPCHandler) HandleSubscribeScanJobs(w http.ResponseWriter, r *http.Request) { 971 + if h.scanBroadcaster == nil { 972 + http.Error(w, "scanning not enabled", http.StatusNotImplemented) 973 + return 974 + } 975 + 976 + // Authenticate via shared secret (query param or header) 977 + secret := r.URL.Query().Get("secret") 978 + if secret == "" { 979 + secret = r.Header.Get("X-Scanner-Secret") 980 + } 981 + if !h.scanBroadcaster.ValidateScannerSecret(secret) { 982 + http.Error(w, "invalid scanner secret", http.StatusUnauthorized) 983 + return 984 + } 985 + 986 + // Get optional cursor for backfill 987 + var cursor int64 = -1 988 + if cursorStr := r.URL.Query().Get("cursor"); cursorStr != "" { 989 + var err error 990 + cursor, err = strconv.ParseInt(cursorStr, 10, 64) 991 + if err != nil { 992 + http.Error(w, "invalid cursor parameter", http.StatusBadRequest) 993 + return 994 + } 995 + } 996 + 997 + // Upgrade to WebSocket 998 + conn, err := upgrader.Upgrade(w, r, nil) 999 + if err != nil { 1000 + slog.Error("Scanner WebSocket upgrade failed", "error", err) 1001 + return 1002 + } 1003 + 1004 + h.scanBroadcaster.Subscribe(conn, cursor) 1005 + } 1006 + 1007 + // ScanBroadcasterRef returns the scan broadcaster (used by OCI handler to enqueue jobs) 1008 + func (h *XRPCHandler) ScanBroadcasterRef() *ScanBroadcaster { 1009 + return h.scanBroadcaster 957 1010 } 958 1011 959 1012 // HandleUploadBlob handles blob uploads with support for multipart operations ··· 1387 1440 s3Key = h.s3Service.PathPrefix + "/" + s3Key 1388 1441 } 1389 1442 1390 - // Create appropriate S3 request based on operation 1391 - var req interface { 1392 - Presign(time.Duration) (string, error) 1393 - } 1443 + // Generate presigned URL with 15 minute expiry 1444 + var url string 1445 + var err error 1394 1446 contentType := "application/octet-stream" 1395 1447 switch operation { 1396 1448 case http.MethodGet: 1397 1449 // Note: Don't use ResponseContentType - not supported by all S3-compatible services 1398 - req = h.s3Service.Client.GetObjectPresignable(&awss3.GetObjectInput{ 1450 + url, err = h.s3Service.Client.PresignGetObject(ctx, &awss3.GetObjectInput{ 1399 1451 Bucket: &h.s3Service.Bucket, 1400 1452 Key: &s3Key, 1401 - }) 1453 + }, 15*time.Minute) 1402 1454 1403 1455 case http.MethodHead: 1404 - req = h.s3Service.Client.HeadObjectPresignable(&awss3.HeadObjectInput{ 1456 + url, err = h.s3Service.Client.PresignHeadObject(ctx, &awss3.HeadObjectInput{ 1405 1457 Bucket: &h.s3Service.Bucket, 1406 1458 Key: &s3Key, 1407 - }) 1459 + }, 15*time.Minute) 1408 1460 1409 1461 case http.MethodPut: 1410 - req = h.s3Service.Client.PutObjectPresignable(&awss3.PutObjectInput{ 1462 + url, err = h.s3Service.Client.PresignPutObject(ctx, &awss3.PutObjectInput{ 1411 1463 Bucket: &h.s3Service.Bucket, 1412 1464 Key: &s3Key, 1413 1465 ContentType: &contentType, 1414 - }) 1466 + }, 15*time.Minute) 1415 1467 1416 1468 default: 1417 1469 return "", fmt.Errorf("unsupported operation: %s", operation) 1418 1470 } 1419 1471 1420 - // Generate presigned URL with 15 minute expiry 1421 - url, err := req.Presign(15 * time.Minute) 1422 1472 if err != nil { 1423 1473 slog.Warn("Presign failed, falling back to XRPC endpoint", 1424 1474 "error", err,
-270
pkg/hold/scanner/extractor.go
··· 1 - package scanner 2 - 3 - import ( 4 - "archive/tar" 5 - "compress/gzip" 6 - "context" 7 - "encoding/json" 8 - "fmt" 9 - "io" 10 - "log/slog" 11 - "os" 12 - "path/filepath" 13 - "strings" 14 - ) 15 - 16 - // extractLayers extracts all image layers from storage to a temporary directory 17 - // Returns the directory path and a cleanup function 18 - func (w *Worker) extractLayers(ctx context.Context, job *ScanJob) (string, func(), error) { 19 - // Create temp directory for extraction 20 - // Use the database directory as the base (since we're in a scratch container with no /tmp) 21 - scanTmpBase := filepath.Join(w.config.Database.Path, "scanner-tmp") 22 - if err := os.MkdirAll(scanTmpBase, 0755); err != nil { 23 - return "", nil, fmt.Errorf("failed to create scanner temp base: %w", err) 24 - } 25 - 26 - tmpDir, err := os.MkdirTemp(scanTmpBase, "scan-*") 27 - if err != nil { 28 - return "", nil, fmt.Errorf("failed to create temp directory: %w", err) 29 - } 30 - 31 - cleanup := func() { 32 - if err := os.RemoveAll(tmpDir); err != nil { 33 - slog.Warn("Failed to clean up temp directory", "dir", tmpDir, "error", err) 34 - } 35 - } 36 - 37 - // Create image directory structure 38 - imageDir := filepath.Join(tmpDir, "image") 39 - if err := os.MkdirAll(imageDir, 0755); err != nil { 40 - cleanup() 41 - return "", nil, fmt.Errorf("failed to create image directory: %w", err) 42 - } 43 - 44 - // Download and extract config blob 45 - slog.Info("Downloading config blob", "digest", job.Config.Digest) 46 - configPath := filepath.Join(imageDir, "config.json") 47 - if err := w.downloadBlob(ctx, job.Config.Digest, configPath); err != nil { 48 - cleanup() 49 - return "", nil, fmt.Errorf("failed to download config blob: %w", err) 50 - } 51 - 52 - // Validate config is valid JSON 53 - configData, err := os.ReadFile(configPath) 54 - if err != nil { 55 - cleanup() 56 - return "", nil, fmt.Errorf("failed to read config: %w", err) 57 - } 58 - var configObj map[string]interface{} 59 - if err := json.Unmarshal(configData, &configObj); err != nil { 60 - cleanup() 61 - return "", nil, fmt.Errorf("invalid config JSON: %w", err) 62 - } 63 - 64 - // Create layers directory for extracted content 65 - layersDir := filepath.Join(imageDir, "layers") 66 - if err := os.MkdirAll(layersDir, 0755); err != nil { 67 - cleanup() 68 - return "", nil, fmt.Errorf("failed to create layers directory: %w", err) 69 - } 70 - 71 - // Download and extract each layer in order (creating overlayfs-style filesystem) 72 - rootfsDir := filepath.Join(imageDir, "rootfs") 73 - if err := os.MkdirAll(rootfsDir, 0755); err != nil { 74 - cleanup() 75 - return "", nil, fmt.Errorf("failed to create rootfs directory: %w", err) 76 - } 77 - 78 - for i, layer := range job.Layers { 79 - slog.Info("Extracting layer", "index", i, "digest", layer.Digest, "size", layer.Size) 80 - 81 - // Download layer blob to temp file 82 - layerPath := filepath.Join(layersDir, fmt.Sprintf("layer-%d.tar.gz", i)) 83 - if err := w.downloadBlob(ctx, layer.Digest, layerPath); err != nil { 84 - cleanup() 85 - return "", nil, fmt.Errorf("failed to download layer %d: %w", i, err) 86 - } 87 - 88 - // Extract layer on top of rootfs (overlayfs style) 89 - if err := w.extractTarGz(layerPath, rootfsDir); err != nil { 90 - cleanup() 91 - return "", nil, fmt.Errorf("failed to extract layer %d: %w", i, err) 92 - } 93 - 94 - // Remove layer tar.gz to save space 95 - os.Remove(layerPath) 96 - } 97 - 98 - // Check what was extracted 99 - entries, err := os.ReadDir(rootfsDir) 100 - if err != nil { 101 - slog.Warn("Failed to read rootfs directory", "error", err) 102 - } else { 103 - slog.Info("Successfully extracted image", 104 - "layers", len(job.Layers), 105 - "rootfs", rootfsDir, 106 - "topLevelEntries", len(entries), 107 - "sampleEntries", func() []string { 108 - var samples []string 109 - for i, e := range entries { 110 - if i >= 10 { 111 - break 112 - } 113 - samples = append(samples, e.Name()) 114 - } 115 - return samples 116 - }()) 117 - } 118 - 119 - return rootfsDir, cleanup, nil 120 - } 121 - 122 - // downloadBlob downloads a blob from storage to a local file 123 - func (w *Worker) downloadBlob(ctx context.Context, digest, destPath string) error { 124 - // Convert digest to storage path using distribution's sharding scheme 125 - // Format: /docker/registry/v2/blobs/sha256/47/4734bc89.../data 126 - // where 47 is the first 2 characters of the hash for directory sharding 127 - blobPath := blobPathForDigest(digest) 128 - 129 - // Open blob from storage driver 130 - reader, err := w.driver.Reader(ctx, blobPath, 0) 131 - if err != nil { 132 - return fmt.Errorf("failed to open blob %s: %w", digest, err) 133 - } 134 - defer reader.Close() 135 - 136 - // Create destination file 137 - dest, err := os.Create(destPath) 138 - if err != nil { 139 - return fmt.Errorf("failed to create destination file: %w", err) 140 - } 141 - defer dest.Close() 142 - 143 - // Copy blob data to file 144 - if _, err := io.Copy(dest, reader); err != nil { 145 - return fmt.Errorf("failed to copy blob data: %w", err) 146 - } 147 - 148 - return nil 149 - } 150 - 151 - // extractTarGz extracts a tar.gz file to a destination directory (overlayfs style) 152 - func (w *Worker) extractTarGz(tarGzPath, destDir string) error { 153 - // Open tar.gz file 154 - file, err := os.Open(tarGzPath) 155 - if err != nil { 156 - return fmt.Errorf("failed to open tar.gz: %w", err) 157 - } 158 - defer file.Close() 159 - 160 - // Create gzip reader 161 - gzr, err := gzip.NewReader(file) 162 - if err != nil { 163 - return fmt.Errorf("failed to create gzip reader: %w", err) 164 - } 165 - defer gzr.Close() 166 - 167 - // Create tar reader 168 - tr := tar.NewReader(gzr) 169 - 170 - // Extract each file 171 - for { 172 - header, err := tr.Next() 173 - if err == io.EOF { 174 - break 175 - } 176 - if err != nil { 177 - return fmt.Errorf("failed to read tar header: %w", err) 178 - } 179 - 180 - // Build target path (clean to prevent path traversal) 181 - target := filepath.Join(destDir, filepath.Clean(header.Name)) 182 - 183 - // Ensure target is within destDir (security check) 184 - if !strings.HasPrefix(target, filepath.Clean(destDir)+string(os.PathSeparator)) { 185 - slog.Warn("Skipping path outside destination", "path", header.Name) 186 - continue 187 - } 188 - 189 - switch header.Typeflag { 190 - case tar.TypeDir: 191 - // Create directory 192 - if err := os.MkdirAll(target, os.FileMode(header.Mode)); err != nil { 193 - return fmt.Errorf("failed to create directory %s: %w", target, err) 194 - } 195 - 196 - case tar.TypeReg: 197 - // Create parent directory 198 - if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil { 199 - return fmt.Errorf("failed to create parent directory: %w", err) 200 - } 201 - 202 - // Create file 203 - outFile, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.FileMode(header.Mode)) 204 - if err != nil { 205 - return fmt.Errorf("failed to create file %s: %w", target, err) 206 - } 207 - 208 - // Copy file contents 209 - if _, err := io.Copy(outFile, tr); err != nil { 210 - outFile.Close() 211 - return fmt.Errorf("failed to write file %s: %w", target, err) 212 - } 213 - outFile.Close() 214 - 215 - case tar.TypeSymlink: 216 - // Create symlink 217 - if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil { 218 - return fmt.Errorf("failed to create parent directory for symlink: %w", err) 219 - } 220 - 221 - // Remove existing file/symlink if it exists 222 - os.Remove(target) 223 - 224 - if err := os.Symlink(header.Linkname, target); err != nil { 225 - slog.Warn("Failed to create symlink", "target", target, "link", header.Linkname, "error", err) 226 - } 227 - 228 - case tar.TypeLink: 229 - // Create hard link 230 - linkTarget := filepath.Join(destDir, filepath.Clean(header.Linkname)) 231 - if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil { 232 - return fmt.Errorf("failed to create parent directory for hardlink: %w", err) 233 - } 234 - 235 - // Remove existing file if it exists 236 - os.Remove(target) 237 - 238 - if err := os.Link(linkTarget, target); err != nil { 239 - slog.Warn("Failed to create hardlink", "target", target, "link", linkTarget, "error", err) 240 - } 241 - 242 - default: 243 - slog.Debug("Skipping unsupported tar entry type", "type", header.Typeflag, "name", header.Name) 244 - } 245 - } 246 - 247 - return nil 248 - } 249 - 250 - // blobPathForDigest converts a digest to a storage path using distribution's sharding scheme 251 - // Format: /docker/registry/v2/blobs/sha256/47/4734bc89.../data 252 - // where 47 is the first 2 characters of the hash for directory sharding 253 - func blobPathForDigest(digest string) string { 254 - // Split digest into algorithm and hash 255 - parts := strings.SplitN(digest, ":", 2) 256 - if len(parts) != 2 { 257 - // Fallback for malformed digest 258 - return fmt.Sprintf("/docker/registry/v2/blobs/%s/data", digest) 259 - } 260 - 261 - algorithm := parts[0] 262 - hash := parts[1] 263 - 264 - // Use first 2 characters for sharding 265 - if len(hash) < 2 { 266 - return fmt.Sprintf("/docker/registry/v2/blobs/%s/%s/data", algorithm, hash) 267 - } 268 - 269 - return fmt.Sprintf("/docker/registry/v2/blobs/%s/%s/%s/data", algorithm, hash[:2], hash) 270 - }
-351
pkg/hold/scanner/grype.go
··· 1 - package scanner 2 - 3 - import ( 4 - "context" 5 - "crypto/sha256" 6 - "encoding/json" 7 - "fmt" 8 - "log/slog" 9 - "os" 10 - "path/filepath" 11 - "sync" 12 - 13 - "github.com/anchore/grype/grype" 14 - "github.com/anchore/grype/grype/db/v6/distribution" 15 - "github.com/anchore/grype/grype/db/v6/installation" 16 - "github.com/anchore/grype/grype/distro" 17 - "github.com/anchore/grype/grype/match" 18 - "github.com/anchore/grype/grype/matcher" 19 - "github.com/anchore/grype/grype/matcher/dotnet" 20 - "github.com/anchore/grype/grype/matcher/golang" 21 - "github.com/anchore/grype/grype/matcher/java" 22 - "github.com/anchore/grype/grype/matcher/javascript" 23 - "github.com/anchore/grype/grype/matcher/python" 24 - "github.com/anchore/grype/grype/matcher/ruby" 25 - "github.com/anchore/grype/grype/matcher/stock" 26 - grypePkg "github.com/anchore/grype/grype/pkg" 27 - "github.com/anchore/grype/grype/vulnerability" 28 - "github.com/anchore/syft/syft/sbom" 29 - ) 30 - 31 - // Global vulnerability database (shared across workers) 32 - var ( 33 - vulnDB vulnerability.Provider 34 - vulnDBLock sync.RWMutex 35 - ) 36 - 37 - // scanVulnerabilities scans an SBOM for vulnerabilities using Grype 38 - // Returns vulnerability report JSON, digest, summary, and any error 39 - func (w *Worker) scanVulnerabilities(ctx context.Context, s *sbom.SBOM) ([]byte, string, VulnerabilitySummary, error) { 40 - slog.Info("Scanning for vulnerabilities with Grype") 41 - 42 - // Load vulnerability database (cached globally) 43 - store, err := w.loadVulnDatabase(ctx) 44 - if err != nil { 45 - return nil, "", VulnerabilitySummary{}, fmt.Errorf("failed to load vulnerability database: %w", err) 46 - } 47 - 48 - // Create package context from SBOM (need distro for synthesis) 49 - var grypeDistro *distro.Distro 50 - if s.Artifacts.LinuxDistribution != nil { 51 - grypeDistro = distro.FromRelease(s.Artifacts.LinuxDistribution, nil) 52 - if grypeDistro != nil { 53 - slog.Info("Using distro for package synthesis", 54 - "name", grypeDistro.Name(), 55 - "version", grypeDistro.Version, 56 - "type", grypeDistro.Type, 57 - "codename", grypeDistro.Codename) 58 - } 59 - } 60 - 61 - // Convert Syft packages to Grype packages WITH distro info 62 - synthesisConfig := grypePkg.SynthesisConfig{ 63 - GenerateMissingCPEs: true, 64 - Distro: grypePkg.DistroConfig{ 65 - Override: grypeDistro, 66 - }, 67 - } 68 - grypePackages := grypePkg.FromCollection(s.Artifacts.Packages, synthesisConfig) 69 - 70 - slog.Info("Converted packages for vulnerability scanning", 71 - "syftPackages", s.Artifacts.Packages.PackageCount(), 72 - "grypePackages", len(grypePackages), 73 - "distro", func() string { 74 - if s.Artifacts.LinuxDistribution != nil { 75 - return fmt.Sprintf("%s %s", s.Artifacts.LinuxDistribution.Name, s.Artifacts.LinuxDistribution.Version) 76 - } 77 - return "none" 78 - }()) 79 - 80 - // Create matchers 81 - matchers := matcher.NewDefaultMatchers(matcher.Config{ 82 - Java: java.MatcherConfig{}, 83 - Ruby: ruby.MatcherConfig{}, 84 - Python: python.MatcherConfig{}, 85 - Dotnet: dotnet.MatcherConfig{}, 86 - Javascript: javascript.MatcherConfig{}, 87 - Golang: golang.MatcherConfig{}, 88 - Stock: stock.MatcherConfig{}, 89 - }) 90 - 91 - // Create package context with the same distro we used for synthesis 92 - pkgContext := grypePkg.Context{ 93 - Source: &s.Source, 94 - Distro: grypeDistro, 95 - } 96 - 97 - // Create vulnerability matcher 98 - vulnerabilityMatcher := &grype.VulnerabilityMatcher{ 99 - VulnerabilityProvider: store, 100 - Matchers: matchers, 101 - NormalizeByCVE: true, 102 - } 103 - 104 - // Find vulnerabilities 105 - slog.Info("Matching vulnerabilities", 106 - "packages", len(grypePackages), 107 - "distro", func() string { 108 - if grypeDistro != nil { 109 - return fmt.Sprintf("%s %s", grypeDistro.Name(), grypeDistro.Version) 110 - } 111 - return "none" 112 - }()) 113 - allMatches, _, err := vulnerabilityMatcher.FindMatches(grypePackages, pkgContext) 114 - if err != nil { 115 - return nil, "", VulnerabilitySummary{}, fmt.Errorf("failed to find vulnerabilities: %w", err) 116 - } 117 - 118 - slog.Info("Vulnerability matching complete", 119 - "totalMatches", allMatches.Count()) 120 - 121 - // If we found 0 matches, log some diagnostic info 122 - if allMatches.Count() == 0 { 123 - slog.Warn("No vulnerability matches found - this may indicate an issue", 124 - "distro", func() string { 125 - if grypeDistro != nil { 126 - return fmt.Sprintf("%s %s", grypeDistro.Name(), grypeDistro.Version) 127 - } 128 - return "none" 129 - }(), 130 - "packages", len(grypePackages), 131 - "databaseBuilt", func() string { 132 - vulnDBLock.RLock() 133 - defer vulnDBLock.RUnlock() 134 - if vulnDB == nil { 135 - return "not loaded" 136 - } 137 - // We can't easily get the build date here without exposing internal state 138 - return "loaded" 139 - }()) 140 - } 141 - 142 - // Count vulnerabilities by severity 143 - summary := w.countVulnerabilitiesBySeverity(*allMatches) 144 - 145 - slog.Info("Vulnerability scan complete", 146 - "critical", summary.Critical, 147 - "high", summary.High, 148 - "medium", summary.Medium, 149 - "low", summary.Low, 150 - "total", summary.Total) 151 - 152 - // Create vulnerability report JSON 153 - report := map[string]interface{}{ 154 - "matches": allMatches.Sorted(), 155 - "source": s.Source, 156 - "distro": s.Artifacts.LinuxDistribution, 157 - "descriptor": map[string]interface{}{ 158 - "name": "grype", 159 - "version": "v0.102.0", // TODO: Get actual Grype version 160 - }, 161 - "summary": summary, 162 - } 163 - 164 - // Encode report to JSON 165 - reportJSON, err := json.MarshalIndent(report, "", " ") 166 - if err != nil { 167 - return nil, "", VulnerabilitySummary{}, fmt.Errorf("failed to encode vulnerability report: %w", err) 168 - } 169 - 170 - // Calculate digest 171 - hash := sha256.Sum256(reportJSON) 172 - digest := fmt.Sprintf("sha256:%x", hash) 173 - 174 - slog.Info("Vulnerability report generated", "size", len(reportJSON), "digest", digest) 175 - 176 - // Upload report blob to storage 177 - if err := w.uploadBlob(ctx, digest, reportJSON); err != nil { 178 - return nil, "", VulnerabilitySummary{}, fmt.Errorf("failed to upload vulnerability report: %w", err) 179 - } 180 - 181 - return reportJSON, digest, summary, nil 182 - } 183 - 184 - // loadVulnDatabase loads the Grype vulnerability database (with caching) 185 - func (w *Worker) loadVulnDatabase(ctx context.Context) (vulnerability.Provider, error) { 186 - // Check if database is already loaded 187 - vulnDBLock.RLock() 188 - if vulnDB != nil { 189 - vulnDBLock.RUnlock() 190 - return vulnDB, nil 191 - } 192 - vulnDBLock.RUnlock() 193 - 194 - // Acquire write lock to load database 195 - vulnDBLock.Lock() 196 - defer vulnDBLock.Unlock() 197 - 198 - // Check again (another goroutine might have loaded it) 199 - if vulnDB != nil { 200 - return vulnDB, nil 201 - } 202 - 203 - slog.Info("Loading Grype vulnerability database", "path", w.config.Scanner.VulnDBPath) 204 - 205 - // Ensure database directory exists 206 - if err := ensureDir(w.config.Scanner.VulnDBPath); err != nil { 207 - return nil, fmt.Errorf("failed to create vulnerability database directory: %w", err) 208 - } 209 - 210 - // Configure database distribution 211 - distConfig := distribution.DefaultConfig() 212 - 213 - // Configure database installation 214 - installConfig := installation.Config{ 215 - DBRootDir: w.config.Scanner.VulnDBPath, 216 - ValidateAge: true, 217 - ValidateChecksum: true, 218 - MaxAllowedBuiltAge: w.config.Scanner.VulnDBUpdateInterval, 219 - } 220 - 221 - // Load database (should already be downloaded by initializeVulnDatabase) 222 - store, status, err := grype.LoadVulnerabilityDB(distConfig, installConfig, false) 223 - if err != nil { 224 - return nil, fmt.Errorf("failed to load vulnerability database (status=%v): %w (hint: database may still be downloading)", status, err) 225 - } 226 - 227 - slog.Info("Vulnerability database loaded", 228 - "status", status, 229 - "built", status.Built, 230 - "location", status.Path, 231 - "schemaVersion", status.SchemaVersion) 232 - 233 - // Check database file size to verify it has content 234 - if stat, err := os.Stat(status.Path); err == nil { 235 - slog.Info("Vulnerability database file stats", 236 - "size", stat.Size(), 237 - "sizeMB", stat.Size()/1024/1024) 238 - } 239 - 240 - // Cache database globally 241 - vulnDB = store 242 - 243 - slog.Info("Vulnerability database loaded successfully") 244 - return vulnDB, nil 245 - } 246 - 247 - // countVulnerabilitiesBySeverity counts vulnerabilities by severity level 248 - func (w *Worker) countVulnerabilitiesBySeverity(matches match.Matches) VulnerabilitySummary { 249 - summary := VulnerabilitySummary{} 250 - 251 - for m := range matches.Enumerate() { 252 - summary.Total++ 253 - 254 - // Get severity from vulnerability metadata 255 - if m.Vulnerability.Metadata != nil { 256 - severity := m.Vulnerability.Metadata.Severity 257 - switch severity { 258 - case "Critical": 259 - summary.Critical++ 260 - case "High": 261 - summary.High++ 262 - case "Medium": 263 - summary.Medium++ 264 - case "Low": 265 - summary.Low++ 266 - } 267 - } 268 - } 269 - 270 - return summary 271 - } 272 - 273 - // initializeVulnDatabase downloads and initializes the vulnerability database on startup 274 - func (w *Worker) initializeVulnDatabase(ctx context.Context) error { 275 - slog.Info("Initializing vulnerability database", "path", w.config.Scanner.VulnDBPath) 276 - 277 - // Ensure database directory exists 278 - if err := ensureDir(w.config.Scanner.VulnDBPath); err != nil { 279 - return fmt.Errorf("failed to create vulnerability database directory: %w", err) 280 - } 281 - 282 - // Create temp directory for Grype downloads (scratch container has no /tmp) 283 - tmpDir := filepath.Join(w.config.Database.Path, "tmp") 284 - if err := ensureDir(tmpDir); err != nil { 285 - return fmt.Errorf("failed to create temp directory: %w", err) 286 - } 287 - 288 - // Set TMPDIR environment variable so Grype uses our temp directory 289 - oldTmpDir := os.Getenv("TMPDIR") 290 - os.Setenv("TMPDIR", tmpDir) 291 - defer func() { 292 - if oldTmpDir != "" { 293 - os.Setenv("TMPDIR", oldTmpDir) 294 - } else { 295 - os.Unsetenv("TMPDIR") 296 - } 297 - }() 298 - 299 - // Configure database distribution 300 - distConfig := distribution.DefaultConfig() 301 - 302 - // Configure database installation 303 - installConfig := installation.Config{ 304 - DBRootDir: w.config.Scanner.VulnDBPath, 305 - ValidateAge: true, 306 - ValidateChecksum: true, 307 - MaxAllowedBuiltAge: w.config.Scanner.VulnDBUpdateInterval, 308 - } 309 - 310 - // Create distribution client for downloading 311 - downloader, err := distribution.NewClient(distConfig) 312 - if err != nil { 313 - return fmt.Errorf("failed to create database downloader: %w", err) 314 - } 315 - 316 - // Create curator to manage database 317 - curator, err := installation.NewCurator(installConfig, downloader) 318 - if err != nil { 319 - return fmt.Errorf("failed to create database curator: %w", err) 320 - } 321 - 322 - // Check if database already exists 323 - status := curator.Status() 324 - if !status.Built.IsZero() && status.Error == nil { 325 - slog.Info("Vulnerability database already exists", "built", status.Built, "schema", status.SchemaVersion) 326 - return nil 327 - } 328 - 329 - // Download database (this may take several minutes) 330 - slog.Info("Downloading vulnerability database (this may take 5-10 minutes)...") 331 - updated, err := curator.Update() 332 - if err != nil { 333 - return fmt.Errorf("failed to download vulnerability database: %w", err) 334 - } 335 - 336 - if updated { 337 - slog.Info("Vulnerability database downloaded successfully") 338 - } else { 339 - slog.Info("Vulnerability database is up to date") 340 - } 341 - 342 - return nil 343 - } 344 - 345 - // ensureDir creates a directory if it doesn't exist 346 - func ensureDir(path string) error { 347 - if err := os.MkdirAll(path, 0755); err != nil { 348 - return fmt.Errorf("failed to create directory %s: %w", path, err) 349 - } 350 - return nil 351 - }
-67
pkg/hold/scanner/job.go
··· 1 - package scanner 2 - 3 - import ( 4 - "time" 5 - 6 - "atcr.io/pkg/atproto" 7 - ) 8 - 9 - // ScanJob represents a vulnerability scanning job for a container image 10 - type ScanJob struct { 11 - // ManifestDigest is the digest of the manifest to scan 12 - ManifestDigest string 13 - 14 - // Repository is the repository name (e.g., "alice/myapp") 15 - Repository string 16 - 17 - // Tag is the tag name (e.g., "latest") 18 - Tag string 19 - 20 - // UserDID is the DID of the user who owns this image 21 - UserDID string 22 - 23 - // UserHandle is the handle of the user (for display) 24 - UserHandle string 25 - 26 - // Config is the image config blob descriptor 27 - Config atproto.BlobReference 28 - 29 - // Layers are the image layer blob descriptors (in order) 30 - Layers []atproto.BlobReference 31 - 32 - // EnqueuedAt is when this job was enqueued 33 - EnqueuedAt time.Time 34 - } 35 - 36 - // ScanResult represents the result of a vulnerability scan 37 - type ScanResult struct { 38 - // Job is the original scan job 39 - Job *ScanJob 40 - 41 - // VulnerabilitiesJSON is the raw Grype JSON output 42 - VulnerabilitiesJSON []byte 43 - 44 - // Summary contains vulnerability counts by severity 45 - Summary VulnerabilitySummary 46 - 47 - // SBOMDigest is the digest of the SBOM blob (if SBOM was generated) 48 - SBOMDigest string 49 - 50 - // VulnDigest is the digest of the vulnerability report blob 51 - VulnDigest string 52 - 53 - // ScannedAt is when the scan completed 54 - ScannedAt time.Time 55 - 56 - // ScannerVersion is the version of the scanner used 57 - ScannerVersion string 58 - } 59 - 60 - // VulnerabilitySummary contains counts of vulnerabilities by severity 61 - type VulnerabilitySummary struct { 62 - Critical int `json:"critical"` 63 - High int `json:"high"` 64 - Medium int `json:"medium"` 65 - Low int `json:"low"` 66 - Total int `json:"total"` 67 - }
-226
pkg/hold/scanner/queue.go
··· 1 - package scanner 2 - 3 - import ( 4 - "context" 5 - "fmt" 6 - "log/slog" 7 - "sync" 8 - 9 - "atcr.io/pkg/atproto" 10 - ) 11 - 12 - // Queue manages a pool of workers for scanning container images 13 - type Queue struct { 14 - jobs chan *ScanJob 15 - results chan *ScanResult 16 - workers int 17 - wg sync.WaitGroup 18 - ctx context.Context 19 - cancel context.CancelFunc 20 - } 21 - 22 - // NewQueue creates a new scanner queue with the specified number of workers 23 - func NewQueue(workers int, bufferSize int) *Queue { 24 - ctx, cancel := context.WithCancel(context.Background()) 25 - 26 - return &Queue{ 27 - jobs: make(chan *ScanJob, bufferSize), 28 - results: make(chan *ScanResult, bufferSize), 29 - workers: workers, 30 - ctx: ctx, 31 - cancel: cancel, 32 - } 33 - } 34 - 35 - // Start starts the worker pool 36 - // The workerFunc is called for each job to perform the actual scanning 37 - func (q *Queue) Start(workerFunc func(context.Context, *ScanJob) (*ScanResult, error)) { 38 - slog.Info("Starting scanner worker pool", "workers", q.workers) 39 - 40 - for i := 0; i < q.workers; i++ { 41 - q.wg.Add(1) 42 - go q.worker(i, workerFunc) 43 - } 44 - 45 - // Start result handler goroutine 46 - q.wg.Add(1) 47 - go q.resultHandler() 48 - } 49 - 50 - // worker processes jobs from the queue 51 - func (q *Queue) worker(id int, workerFunc func(context.Context, *ScanJob) (*ScanResult, error)) { 52 - defer q.wg.Done() 53 - 54 - slog.Info("Scanner worker started", "worker_id", id) 55 - 56 - for { 57 - select { 58 - case <-q.ctx.Done(): 59 - slog.Info("Scanner worker shutting down", "worker_id", id) 60 - return 61 - 62 - case job, ok := <-q.jobs: 63 - if !ok { 64 - slog.Info("Scanner worker: jobs channel closed", "worker_id", id) 65 - return 66 - } 67 - 68 - slog.Info("Scanner worker processing job", 69 - "worker_id", id, 70 - "repository", job.Repository, 71 - "tag", job.Tag, 72 - "digest", job.ManifestDigest) 73 - 74 - result, err := workerFunc(q.ctx, job) 75 - if err != nil { 76 - slog.Error("Scanner worker failed to process job", 77 - "worker_id", id, 78 - "repository", job.Repository, 79 - "tag", job.Tag, 80 - "error", err) 81 - continue 82 - } 83 - 84 - // Send result to results channel 85 - select { 86 - case q.results <- result: 87 - slog.Info("Scanner worker completed job", 88 - "worker_id", id, 89 - "repository", job.Repository, 90 - "tag", job.Tag, 91 - "vulnerabilities", result.Summary.Total) 92 - case <-q.ctx.Done(): 93 - return 94 - } 95 - } 96 - } 97 - } 98 - 99 - // resultHandler processes scan results (for logging and metrics) 100 - func (q *Queue) resultHandler() { 101 - defer q.wg.Done() 102 - 103 - for { 104 - select { 105 - case <-q.ctx.Done(): 106 - return 107 - 108 - case result, ok := <-q.results: 109 - if !ok { 110 - return 111 - } 112 - 113 - // Log the result 114 - slog.Info("Scan completed", 115 - "repository", result.Job.Repository, 116 - "tag", result.Job.Tag, 117 - "digest", result.Job.ManifestDigest, 118 - "critical", result.Summary.Critical, 119 - "high", result.Summary.High, 120 - "medium", result.Summary.Medium, 121 - "low", result.Summary.Low, 122 - "total", result.Summary.Total, 123 - "scanner", result.ScannerVersion) 124 - } 125 - } 126 - } 127 - 128 - // Enqueue adds a job to the queue 129 - func (q *Queue) Enqueue(jobAny any) error { 130 - // Type assert to ScanJob (can be map or struct from HandleNotifyManifest) 131 - var job *ScanJob 132 - 133 - switch v := jobAny.(type) { 134 - case *ScanJob: 135 - job = v 136 - case map[string]interface{}: 137 - // Convert map to ScanJob (from HandleNotifyManifest) 138 - job = &ScanJob{ 139 - ManifestDigest: v["manifestDigest"].(string), 140 - Repository: v["repository"].(string), 141 - Tag: v["tag"].(string), 142 - UserDID: v["userDID"].(string), 143 - UserHandle: v["userHandle"].(string), 144 - } 145 - 146 - // Parse config blob reference 147 - if configMap, ok := v["config"].(map[string]interface{}); ok { 148 - job.Config = atproto.BlobReference{ 149 - Digest: configMap["digest"].(string), 150 - Size: convertToInt64(configMap["size"]), 151 - MediaType: configMap["mediaType"].(string), 152 - } 153 - } 154 - 155 - // Parse layers 156 - if layersSlice, ok := v["layers"].([]interface{}); ok { 157 - slog.Info("Parsing layers from scan job", 158 - "layersFound", len(layersSlice)) 159 - job.Layers = make([]atproto.BlobReference, len(layersSlice)) 160 - for i, layerAny := range layersSlice { 161 - if layerMap, ok := layerAny.(map[string]interface{}); ok { 162 - job.Layers[i] = atproto.BlobReference{ 163 - Digest: layerMap["digest"].(string), 164 - Size: convertToInt64(layerMap["size"]), 165 - MediaType: layerMap["mediaType"].(string), 166 - } 167 - } 168 - } 169 - } else { 170 - slog.Warn("No layers found in scan job map", 171 - "layersType", fmt.Sprintf("%T", v["layers"]), 172 - "layersValue", v["layers"]) 173 - } 174 - default: 175 - return fmt.Errorf("invalid job type: %T", jobAny) 176 - } 177 - 178 - select { 179 - case q.jobs <- job: 180 - slog.Info("Enqueued scan job", 181 - "repository", job.Repository, 182 - "tag", job.Tag, 183 - "digest", job.ManifestDigest) 184 - return nil 185 - case <-q.ctx.Done(): 186 - return q.ctx.Err() 187 - } 188 - } 189 - 190 - // Shutdown gracefully shuts down the queue, waiting for all workers to finish 191 - func (q *Queue) Shutdown() { 192 - slog.Info("Shutting down scanner queue") 193 - 194 - // Close the jobs channel to signal no more jobs 195 - close(q.jobs) 196 - 197 - // Wait for all workers to finish 198 - q.wg.Wait() 199 - 200 - // Close results channel 201 - close(q.results) 202 - 203 - // Cancel context 204 - q.cancel() 205 - 206 - slog.Info("Scanner queue shut down complete") 207 - } 208 - 209 - // Len returns the number of jobs currently in the queue 210 - func (q *Queue) Len() int { 211 - return len(q.jobs) 212 - } 213 - 214 - // convertToInt64 converts an interface{} number to int64, handling both float64 and int64 215 - func convertToInt64(v interface{}) int64 { 216 - switch n := v.(type) { 217 - case float64: 218 - return int64(n) 219 - case int64: 220 - return n 221 - case int: 222 - return int64(n) 223 - default: 224 - return 0 225 - } 226 - }
-123
pkg/hold/scanner/storage.go
··· 1 - package scanner 2 - 3 - import ( 4 - "context" 5 - "crypto/sha256" 6 - "encoding/json" 7 - "fmt" 8 - "log/slog" 9 - "time" 10 - 11 - "atcr.io/pkg/atproto" 12 - ) 13 - 14 - // storeResults uploads scan results and creates ORAS manifest records in the hold's PDS 15 - func (w *Worker) storeResults(ctx context.Context, job *ScanJob, sbomDigest, vulnDigest string, vulnJSON []byte, summary VulnerabilitySummary) error { 16 - if !w.config.Scanner.VulnEnabled { 17 - slog.Info("Vulnerability scanning disabled, skipping result storage") 18 - return nil 19 - } 20 - 21 - slog.Info("Storing scan results as ORAS artifact", 22 - "repository", job.Repository, 23 - "subjectDigest", job.ManifestDigest, 24 - "vulnDigest", vulnDigest) 25 - 26 - // Create ORAS manifest for vulnerability report 27 - orasManifest := map[string]interface{}{ 28 - "schemaVersion": 2, 29 - "mediaType": "application/vnd.oci.image.manifest.v1+json", 30 - "artifactType": "application/vnd.atcr.vulnerabilities+json", 31 - "config": map[string]interface{}{ 32 - "mediaType": "application/vnd.oci.empty.v1+json", 33 - "digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a", // Empty JSON object 34 - "size": 2, 35 - }, 36 - "subject": map[string]interface{}{ 37 - "mediaType": "application/vnd.oci.image.manifest.v1+json", 38 - "digest": job.ManifestDigest, 39 - "size": 0, // We don't have the size, but it's optional 40 - }, 41 - "layers": []map[string]interface{}{ 42 - { 43 - "mediaType": "application/json", 44 - "digest": vulnDigest, 45 - "size": len(vulnJSON), 46 - "annotations": map[string]string{ 47 - "org.opencontainers.image.title": "vulnerability-report.json", 48 - }, 49 - }, 50 - }, 51 - "annotations": map[string]string{ 52 - "io.atcr.vuln.critical": fmt.Sprintf("%d", summary.Critical), 53 - "io.atcr.vuln.high": fmt.Sprintf("%d", summary.High), 54 - "io.atcr.vuln.medium": fmt.Sprintf("%d", summary.Medium), 55 - "io.atcr.vuln.low": fmt.Sprintf("%d", summary.Low), 56 - "io.atcr.vuln.total": fmt.Sprintf("%d", summary.Total), 57 - "io.atcr.vuln.scannedAt": time.Now().Format(time.RFC3339), 58 - "io.atcr.vuln.scannerVersion": w.getScannerVersion(), 59 - }, 60 - } 61 - 62 - // Encode ORAS manifest to JSON 63 - orasManifestJSON, err := json.Marshal(orasManifest) 64 - if err != nil { 65 - return fmt.Errorf("failed to encode ORAS manifest: %w", err) 66 - } 67 - 68 - // Calculate ORAS manifest digest 69 - orasDigest := fmt.Sprintf("sha256:%x", sha256Bytes(orasManifestJSON)) 70 - 71 - // Upload ORAS manifest blob to storage 72 - if err := w.uploadBlob(ctx, orasDigest, orasManifestJSON); err != nil { 73 - return fmt.Errorf("failed to upload ORAS manifest blob: %w", err) 74 - } 75 - 76 - // Create manifest record in hold's PDS 77 - if err := w.createManifestRecord(ctx, job, orasDigest, orasManifestJSON, summary); err != nil { 78 - return fmt.Errorf("failed to create manifest record: %w", err) 79 - } 80 - 81 - slog.Info("Successfully stored scan results", "orasDigest", orasDigest) 82 - return nil 83 - } 84 - 85 - // createManifestRecord creates an ORAS manifest record in the hold's PDS 86 - func (w *Worker) createManifestRecord(ctx context.Context, job *ScanJob, orasDigest string, orasManifestJSON []byte, summary VulnerabilitySummary) error { 87 - // Create ManifestRecord from ORAS manifest 88 - record, err := atproto.NewManifestRecord(job.Repository, orasDigest, orasManifestJSON) 89 - if err != nil { 90 - return fmt.Errorf("failed to create manifest record: %w", err) 91 - } 92 - 93 - // Set SBOM/vulnerability specific fields 94 - record.OwnerDID = job.UserDID 95 - record.ScannedAt = time.Now().Format(time.RFC3339) 96 - record.ScannerVersion = w.getScannerVersion() 97 - 98 - // Add hold DID (this ORAS artifact is stored in the hold's PDS) 99 - record.HoldDID = w.pds.DID() 100 - 101 - // Convert digest to record key (remove "sha256:" prefix) 102 - rkey := orasDigest[len("sha256:"):] 103 - 104 - // Store record in hold's PDS 105 - slog.Info("Creating manifest record in hold's PDS", 106 - "collection", atproto.ManifestCollection, 107 - "rkey", rkey, 108 - "ownerDid", job.UserDID) 109 - 110 - _, _, err = w.pds.CreateManifestRecord(ctx, record, rkey) 111 - if err != nil { 112 - return fmt.Errorf("failed to put record in PDS: %w", err) 113 - } 114 - 115 - slog.Info("Manifest record created successfully", "uri", fmt.Sprintf("at://%s/%s/%s", w.pds.DID(), atproto.ManifestCollection, rkey)) 116 - return nil 117 - } 118 - 119 - // sha256Bytes calculates SHA256 hash of byte slice 120 - func sha256Bytes(data []byte) []byte { 121 - hash := sha256.Sum256(data) 122 - return hash[:] 123 - }
-128
pkg/hold/scanner/syft.go
··· 1 - package scanner 2 - 3 - import ( 4 - "context" 5 - "crypto/sha256" 6 - "fmt" 7 - "log/slog" 8 - "os" 9 - 10 - "github.com/anchore/syft/syft" 11 - "github.com/anchore/syft/syft/format" 12 - "github.com/anchore/syft/syft/format/spdxjson" 13 - "github.com/anchore/syft/syft/sbom" 14 - "github.com/anchore/syft/syft/source/directorysource" 15 - ) 16 - 17 - // generateSBOM generates an SBOM using Syft from an extracted image directory 18 - // Returns the SBOM object, SBOM JSON, its digest, and any error 19 - func (w *Worker) generateSBOM(ctx context.Context, imageDir string) (*sbom.SBOM, []byte, string, error) { 20 - slog.Info("Generating SBOM with Syft", "imageDir", imageDir) 21 - 22 - // Check if directory exists and is accessible 23 - entries, err := os.ReadDir(imageDir) 24 - if err != nil { 25 - return nil, nil, "", fmt.Errorf("failed to read image directory: %w", err) 26 - } 27 - slog.Info("Image directory contents", 28 - "path", imageDir, 29 - "entries", len(entries), 30 - "sampleFiles", func() []string { 31 - var samples []string 32 - for i, e := range entries { 33 - if i >= 20 { 34 - break 35 - } 36 - samples = append(samples, e.Name()) 37 - } 38 - return samples 39 - }()) 40 - 41 - // Create Syft source from directory 42 - src, err := directorysource.NewFromPath(imageDir) 43 - if err != nil { 44 - return nil, nil, "", fmt.Errorf("failed to create Syft source: %w", err) 45 - } 46 - defer src.Close() 47 - 48 - // Generate SBOM 49 - slog.Info("Running Syft cataloging") 50 - sbomResult, err := syft.CreateSBOM(ctx, src, nil) 51 - if err != nil { 52 - return nil, nil, "", fmt.Errorf("failed to generate SBOM: %w", err) 53 - } 54 - 55 - if sbomResult == nil { 56 - return nil, nil, "", fmt.Errorf("Syft returned nil SBOM") 57 - } 58 - 59 - slog.Info("SBOM generated", 60 - "packages", sbomResult.Artifacts.Packages.PackageCount(), 61 - "distro", func() string { 62 - if sbomResult.Artifacts.LinuxDistribution != nil { 63 - return fmt.Sprintf("%s %s", sbomResult.Artifacts.LinuxDistribution.Name, sbomResult.Artifacts.LinuxDistribution.Version) 64 - } 65 - return "none" 66 - }()) 67 - 68 - // Encode SBOM to SPDX JSON format 69 - encoder, err := spdxjson.NewFormatEncoderWithConfig(spdxjson.DefaultEncoderConfig()) 70 - if err != nil { 71 - return nil, nil, "", fmt.Errorf("failed to create SPDX encoder: %w", err) 72 - } 73 - 74 - sbomJSON, err := format.Encode(*sbomResult, encoder) 75 - if err != nil { 76 - return nil, nil, "", fmt.Errorf("failed to encode SBOM to SPDX JSON: %w", err) 77 - } 78 - 79 - // Calculate digest 80 - hash := sha256.Sum256(sbomJSON) 81 - digest := fmt.Sprintf("sha256:%x", hash) 82 - 83 - slog.Info("SBOM encoded", "format", "spdx-json", "size", len(sbomJSON), "digest", digest) 84 - 85 - // Upload SBOM blob to storage 86 - if err := w.uploadBlob(ctx, digest, sbomJSON); err != nil { 87 - return nil, nil, "", fmt.Errorf("failed to upload SBOM blob: %w", err) 88 - } 89 - 90 - return sbomResult, sbomJSON, digest, nil 91 - } 92 - 93 - // uploadBlob uploads a blob to storage 94 - func (w *Worker) uploadBlob(ctx context.Context, digest string, data []byte) error { 95 - // Convert digest to storage path (same format as distribution uses) 96 - // Path format: /docker/registry/v2/blobs/sha256/ab/abcd1234.../data 97 - algorithm := "sha256" 98 - digestHex := digest[len("sha256:"):] 99 - if len(digestHex) < 2 { 100 - return fmt.Errorf("invalid digest: %s", digest) 101 - } 102 - 103 - blobPath := fmt.Sprintf("/docker/registry/v2/blobs/%s/%s/%s/data", 104 - algorithm, 105 - digestHex[:2], 106 - digestHex) 107 - 108 - slog.Info("Uploading blob to storage", "digest", digest, "size", len(data), "path", blobPath) 109 - 110 - // Write blob to storage 111 - writer, err := w.driver.Writer(ctx, blobPath, false) 112 - if err != nil { 113 - return fmt.Errorf("failed to create storage writer: %w", err) 114 - } 115 - defer writer.Close() 116 - 117 - if _, err := writer.Write(data); err != nil { 118 - writer.Cancel(ctx) 119 - return fmt.Errorf("failed to write blob data: %w", err) 120 - } 121 - 122 - if err := writer.Commit(ctx); err != nil { 123 - return fmt.Errorf("failed to commit blob: %w", err) 124 - } 125 - 126 - slog.Info("Successfully uploaded blob", "digest", digest) 127 - return nil 128 - }
-116
pkg/hold/scanner/worker.go
··· 1 - package scanner 2 - 3 - import ( 4 - "context" 5 - "fmt" 6 - "log/slog" 7 - "time" 8 - 9 - "atcr.io/pkg/hold" 10 - "atcr.io/pkg/hold/pds" 11 - "github.com/distribution/distribution/v3/registry/storage/driver" 12 - ) 13 - 14 - // Worker performs vulnerability scanning on container images 15 - type Worker struct { 16 - config *hold.Config 17 - driver driver.StorageDriver 18 - pds *pds.HoldPDS 19 - queue *Queue 20 - } 21 - 22 - // NewWorker creates a new scanner worker 23 - func NewWorker(config *hold.Config, driver driver.StorageDriver, pds *pds.HoldPDS) *Worker { 24 - return &Worker{ 25 - config: config, 26 - driver: driver, 27 - pds: pds, 28 - } 29 - } 30 - 31 - // Start starts the worker pool and initializes vulnerability database 32 - func (w *Worker) Start(queue *Queue) { 33 - w.queue = queue 34 - 35 - // Initialize vulnerability database on startup if scanning is enabled 36 - if w.config.Scanner.VulnEnabled { 37 - go func() { 38 - ctx := context.Background() 39 - if err := w.initializeVulnDatabase(ctx); err != nil { 40 - slog.Error("Failed to initialize vulnerability database", "error", err) 41 - slog.Warn("Vulnerability scanning will be disabled until database is available") 42 - } 43 - }() 44 - } 45 - 46 - queue.Start(w.processJob) 47 - } 48 - 49 - // processJob processes a single scan job 50 - func (w *Worker) processJob(ctx context.Context, job *ScanJob) (*ScanResult, error) { 51 - slog.Info("Processing scan job", 52 - "repository", job.Repository, 53 - "tag", job.Tag, 54 - "digest", job.ManifestDigest, 55 - "layers", len(job.Layers)) 56 - 57 - startTime := time.Now() 58 - 59 - // Step 1: Extract image layers from storage 60 - slog.Info("Extracting image layers", "repository", job.Repository) 61 - imageDir, cleanup, err := w.extractLayers(ctx, job) 62 - if err != nil { 63 - return nil, fmt.Errorf("failed to extract layers: %w", err) 64 - } 65 - defer cleanup() 66 - 67 - // Step 2: Generate SBOM with Syft 68 - slog.Info("Generating SBOM", "repository", job.Repository) 69 - sbomResult, _, sbomDigest, err := w.generateSBOM(ctx, imageDir) 70 - if err != nil { 71 - return nil, fmt.Errorf("failed to generate SBOM: %w", err) 72 - } 73 - 74 - // Step 3: Scan SBOM with Grype (if enabled) 75 - var vulnJSON []byte 76 - var vulnDigest string 77 - var summary VulnerabilitySummary 78 - 79 - if w.config.Scanner.VulnEnabled { 80 - slog.Info("Scanning for vulnerabilities", "repository", job.Repository) 81 - vulnJSON, vulnDigest, summary, err = w.scanVulnerabilities(ctx, sbomResult) 82 - if err != nil { 83 - return nil, fmt.Errorf("failed to scan vulnerabilities: %w", err) 84 - } 85 - } 86 - 87 - // Step 4: Upload results to storage and create ORAS manifests 88 - slog.Info("Storing scan results", "repository", job.Repository) 89 - err = w.storeResults(ctx, job, sbomDigest, vulnDigest, vulnJSON, summary) 90 - if err != nil { 91 - return nil, fmt.Errorf("failed to store results: %w", err) 92 - } 93 - 94 - duration := time.Since(startTime) 95 - slog.Info("Scan job completed", 96 - "repository", job.Repository, 97 - "tag", job.Tag, 98 - "duration", duration, 99 - "vulnerabilities", summary.Total) 100 - 101 - return &ScanResult{ 102 - Job: job, 103 - VulnerabilitiesJSON: vulnJSON, 104 - Summary: summary, 105 - SBOMDigest: sbomDigest, 106 - VulnDigest: vulnDigest, 107 - ScannedAt: time.Now(), 108 - ScannerVersion: w.getScannerVersion(), 109 - }, nil 110 - } 111 - 112 - // getScannerVersion returns the version string for the scanner 113 - func (w *Worker) getScannerVersion() string { 114 - // TODO: Get actual Syft and Grype versions dynamically 115 - return "syft-v1.36.0/grype-v0.102.0" 116 - }
+24
pkg/hold/server.go
··· 44 44 // internal fields for shutdown 45 45 httpServer *http.Server 46 46 broadcaster *pds.EventBroadcaster 47 + scanBroadcaster *pds.ScanBroadcaster 47 48 garbageCollector *gc.GarbageCollector 48 49 adminUI *admin.AdminUI 49 50 } ··· 146 147 147 148 xrpcHandler = pds.NewXRPCHandler(s.PDS, *s3Service, driver, s.broadcaster, nil, s.QuotaManager) 148 149 ociHandler = oci.NewXRPCHandler(s.PDS, *s3Service, driver, cfg.Registration.EnableBlueskyPosts, nil, s.QuotaManager) 150 + 151 + // Initialize scan broadcaster if scanner secret is configured 152 + if cfg.Scanner.Secret != "" { 153 + holdDID := pds.GenerateDIDFromURL(cfg.Server.PublicURL) 154 + scanDBPath := cfg.Database.Path + "/db.sqlite3" 155 + sb, err := pds.NewScanBroadcaster(holdDID, cfg.Server.PublicURL, cfg.Scanner.Secret, scanDBPath, driver, s.PDS) 156 + if err != nil { 157 + return nil, fmt.Errorf("failed to initialize scan broadcaster: %w", err) 158 + } 159 + s.scanBroadcaster = sb 160 + xrpcHandler.SetScanBroadcaster(sb) 161 + ociHandler.SetScanBroadcaster(sb) 162 + slog.Info("Scan broadcaster initialized (scanner WebSocket enabled)") 163 + } 149 164 150 165 // Initialize garbage collector 151 166 gcConfig := gc.LoadConfigFromEnv() ··· 295 310 if s.garbageCollector != nil { 296 311 s.garbageCollector.Stop() 297 312 slog.Info("Garbage collector stopped") 313 + } 314 + 315 + // Close scan broadcaster database connection 316 + if s.scanBroadcaster != nil { 317 + if err := s.scanBroadcaster.Close(); err != nil { 318 + slog.Warn("Failed to close scan broadcaster database", "error", err) 319 + } else { 320 + slog.Info("Scan broadcaster database closed") 321 + } 298 322 } 299 323 300 324 // Close broadcaster database connection
+58 -69
pkg/s3/mock.go
··· 1 1 package s3 2 2 3 3 import ( 4 + "context" 4 5 "fmt" 5 6 "sync" 6 7 "time" 7 8 8 - "github.com/aws/aws-sdk-go/aws" 9 - "github.com/aws/aws-sdk-go/aws/request" 10 - "github.com/aws/aws-sdk-go/service/s3" 9 + "github.com/aws/aws-sdk-go-v2/aws" 10 + awss3 "github.com/aws/aws-sdk-go-v2/service/s3" 11 11 "github.com/google/uuid" 12 12 ) 13 - 14 - // mockPresignable implements Presignable for testing 15 - type mockPresignable struct { 16 - url string 17 - } 18 - 19 - // Presign returns the pre-configured mock URL 20 - func (m *mockPresignable) Presign(expire time.Duration) (string, error) { 21 - return m.url, nil 22 - } 23 13 24 14 // MockS3Client implements S3Client for testing without real S3 credentials. 25 15 // It generates fake presigned URLs that point to a test server. ··· 28 18 // Requests to these URLs should be handled by a test server (httptest.Server). 29 19 TestServerURL string 30 20 31 - // UploadID is returned by CreateMultipartUploadWithContext. 21 + // UploadID is returned by CreateMultipartUpload. 32 22 // If empty, a UUID is generated. 33 23 UploadID string 34 24 ··· 48 38 AbortError error 49 39 } 50 40 51 - // CreateMultipartCall records a CreateMultipartUploadWithContext call 41 + // CreateMultipartCall records a CreateMultipartUpload call 52 42 type CreateMultipartCall struct { 53 43 Bucket string 54 44 Key string 55 45 } 56 46 57 - // CompleteCall records a CompleteMultipartUploadWithContext call 47 + // CompleteCall records a CompleteMultipartUpload call 58 48 type CompleteCall struct { 59 49 Bucket string 60 50 Key string ··· 62 52 Parts int 63 53 } 64 54 65 - // AbortCall records an AbortMultipartUploadWithContext call 55 + // AbortCall records an AbortMultipartUpload call 66 56 type AbortCall struct { 67 57 Bucket string 68 58 Key string 69 59 UploadID string 70 60 } 71 61 72 - // UploadPartCall records an UploadPartRequest call 62 + // UploadPartCall records a PresignUploadPart call 73 63 type UploadPartCall struct { 74 64 Bucket string 75 65 Key string 76 66 UploadID string 77 - PartNumber int64 67 + PartNumber int32 78 68 } 79 69 80 - // GetObjectCall records a GetObjectRequest call 70 + // GetObjectCall records a PresignGetObject call 81 71 type GetObjectCall struct { 82 72 Bucket string 83 73 Key string 84 74 } 85 75 86 - // HeadObjectCall records a HeadObjectRequest call 76 + // HeadObjectCall records a PresignHeadObject call 87 77 type HeadObjectCall struct { 88 78 Bucket string 89 79 Key string 90 80 } 91 81 92 - // PutObjectCall records a PutObjectRequest call 82 + // PutObjectCall records a PresignPutObject call 93 83 type PutObjectCall struct { 94 84 Bucket string 95 85 Key string ··· 109 99 } 110 100 } 111 101 112 - // CreateMultipartUploadWithContext implements S3Client 113 - func (m *MockS3Client) CreateMultipartUploadWithContext(ctx aws.Context, input *s3.CreateMultipartUploadInput, opts ...request.Option) (*s3.CreateMultipartUploadOutput, error) { 102 + // CreateMultipartUpload implements S3Client 103 + func (m *MockS3Client) CreateMultipartUpload(ctx context.Context, input *awss3.CreateMultipartUploadInput, opts ...func(*awss3.Options)) (*awss3.CreateMultipartUploadOutput, error) { 114 104 m.mu.Lock() 115 105 defer m.mu.Unlock() 116 106 117 107 m.CreateMultipartCalls = append(m.CreateMultipartCalls, CreateMultipartCall{ 118 - Bucket: aws.StringValue(input.Bucket), 119 - Key: aws.StringValue(input.Key), 108 + Bucket: aws.ToString(input.Bucket), 109 + Key: aws.ToString(input.Key), 120 110 }) 121 111 122 112 if m.CreateMultipartError != nil { ··· 128 118 uploadID = "mock-upload-" + uuid.New().String() 129 119 } 130 120 131 - return &s3.CreateMultipartUploadOutput{ 121 + return &awss3.CreateMultipartUploadOutput{ 132 122 UploadId: aws.String(uploadID), 133 123 }, nil 134 124 } 135 125 136 - // CompleteMultipartUploadWithContext implements S3Client 137 - func (m *MockS3Client) CompleteMultipartUploadWithContext(ctx aws.Context, input *s3.CompleteMultipartUploadInput, opts ...request.Option) (*s3.CompleteMultipartUploadOutput, error) { 126 + // CompleteMultipartUpload implements S3Client 127 + func (m *MockS3Client) CompleteMultipartUpload(ctx context.Context, input *awss3.CompleteMultipartUploadInput, opts ...func(*awss3.Options)) (*awss3.CompleteMultipartUploadOutput, error) { 138 128 m.mu.Lock() 139 129 defer m.mu.Unlock() 140 130 ··· 144 134 } 145 135 146 136 m.CompleteCalls = append(m.CompleteCalls, CompleteCall{ 147 - Bucket: aws.StringValue(input.Bucket), 148 - Key: aws.StringValue(input.Key), 149 - UploadID: aws.StringValue(input.UploadId), 137 + Bucket: aws.ToString(input.Bucket), 138 + Key: aws.ToString(input.Key), 139 + UploadID: aws.ToString(input.UploadId), 150 140 Parts: partsCount, 151 141 }) 152 142 ··· 156 146 157 147 // Return a mock ETag 158 148 etag := "\"mock-etag-" + uuid.New().String() + "\"" 159 - return &s3.CompleteMultipartUploadOutput{ 149 + return &awss3.CompleteMultipartUploadOutput{ 160 150 ETag: aws.String(etag), 161 151 }, nil 162 152 } 163 153 164 - // AbortMultipartUploadWithContext implements S3Client 165 - func (m *MockS3Client) AbortMultipartUploadWithContext(ctx aws.Context, input *s3.AbortMultipartUploadInput, opts ...request.Option) (*s3.AbortMultipartUploadOutput, error) { 154 + // AbortMultipartUpload implements S3Client 155 + func (m *MockS3Client) AbortMultipartUpload(ctx context.Context, input *awss3.AbortMultipartUploadInput, opts ...func(*awss3.Options)) (*awss3.AbortMultipartUploadOutput, error) { 166 156 m.mu.Lock() 167 157 defer m.mu.Unlock() 168 158 169 159 m.AbortCalls = append(m.AbortCalls, AbortCall{ 170 - Bucket: aws.StringValue(input.Bucket), 171 - Key: aws.StringValue(input.Key), 172 - UploadID: aws.StringValue(input.UploadId), 160 + Bucket: aws.ToString(input.Bucket), 161 + Key: aws.ToString(input.Key), 162 + UploadID: aws.ToString(input.UploadId), 173 163 }) 174 164 175 165 if m.AbortError != nil { 176 166 return nil, m.AbortError 177 167 } 178 168 179 - return &s3.AbortMultipartUploadOutput{}, nil 169 + return &awss3.AbortMultipartUploadOutput{}, nil 180 170 } 181 171 182 - // UploadPartPresignable implements S3Client 183 - // Returns a mock Presignable that generates test server URLs 184 - func (m *MockS3Client) UploadPartPresignable(input *s3.UploadPartInput) Presignable { 172 + // PresignUploadPart implements S3Client 173 + // Returns a mock presigned URL for test server 174 + func (m *MockS3Client) PresignUploadPart(ctx context.Context, input *awss3.UploadPartInput, expires time.Duration) (string, error) { 185 175 m.mu.Lock() 186 176 defer m.mu.Unlock() 187 177 188 178 m.UploadPartCalls = append(m.UploadPartCalls, UploadPartCall{ 189 - Bucket: aws.StringValue(input.Bucket), 190 - Key: aws.StringValue(input.Key), 191 - UploadID: aws.StringValue(input.UploadId), 192 - PartNumber: aws.Int64Value(input.PartNumber), 179 + Bucket: aws.ToString(input.Bucket), 180 + Key: aws.ToString(input.Key), 181 + UploadID: aws.ToString(input.UploadId), 182 + PartNumber: aws.ToInt32(input.PartNumber), 193 183 }) 194 184 195 - // Create a mock presignable request 196 185 url := fmt.Sprintf("%s/upload/%s?partNumber=%d&uploadId=%s", 197 186 m.TestServerURL, 198 - aws.StringValue(input.Key), 199 - aws.Int64Value(input.PartNumber), 200 - aws.StringValue(input.UploadId)) 187 + aws.ToString(input.Key), 188 + aws.ToInt32(input.PartNumber), 189 + aws.ToString(input.UploadId)) 201 190 202 - return &mockPresignable{url: url} 191 + return url, nil 203 192 } 204 193 205 - // GetObjectPresignable implements S3Client 206 - func (m *MockS3Client) GetObjectPresignable(input *s3.GetObjectInput) Presignable { 194 + // PresignGetObject implements S3Client 195 + func (m *MockS3Client) PresignGetObject(ctx context.Context, input *awss3.GetObjectInput, expires time.Duration) (string, error) { 207 196 m.mu.Lock() 208 197 defer m.mu.Unlock() 209 198 210 199 m.GetObjectCalls = append(m.GetObjectCalls, GetObjectCall{ 211 - Bucket: aws.StringValue(input.Bucket), 212 - Key: aws.StringValue(input.Key), 200 + Bucket: aws.ToString(input.Bucket), 201 + Key: aws.ToString(input.Key), 213 202 }) 214 203 215 - url := fmt.Sprintf("%s/get/%s", m.TestServerURL, aws.StringValue(input.Key)) 216 - return &mockPresignable{url: url} 204 + url := fmt.Sprintf("%s/get/%s", m.TestServerURL, aws.ToString(input.Key)) 205 + return url, nil 217 206 } 218 207 219 - // HeadObjectPresignable implements S3Client 220 - func (m *MockS3Client) HeadObjectPresignable(input *s3.HeadObjectInput) Presignable { 208 + // PresignHeadObject implements S3Client 209 + func (m *MockS3Client) PresignHeadObject(ctx context.Context, input *awss3.HeadObjectInput, expires time.Duration) (string, error) { 221 210 m.mu.Lock() 222 211 defer m.mu.Unlock() 223 212 224 213 m.HeadObjectCalls = append(m.HeadObjectCalls, HeadObjectCall{ 225 - Bucket: aws.StringValue(input.Bucket), 226 - Key: aws.StringValue(input.Key), 214 + Bucket: aws.ToString(input.Bucket), 215 + Key: aws.ToString(input.Key), 227 216 }) 228 217 229 - url := fmt.Sprintf("%s/head/%s", m.TestServerURL, aws.StringValue(input.Key)) 230 - return &mockPresignable{url: url} 218 + url := fmt.Sprintf("%s/head/%s", m.TestServerURL, aws.ToString(input.Key)) 219 + return url, nil 231 220 } 232 221 233 - // PutObjectPresignable implements S3Client 234 - func (m *MockS3Client) PutObjectPresignable(input *s3.PutObjectInput) Presignable { 222 + // PresignPutObject implements S3Client 223 + func (m *MockS3Client) PresignPutObject(ctx context.Context, input *awss3.PutObjectInput, expires time.Duration) (string, error) { 235 224 m.mu.Lock() 236 225 defer m.mu.Unlock() 237 226 238 227 m.PutObjectCalls = append(m.PutObjectCalls, PutObjectCall{ 239 - Bucket: aws.StringValue(input.Bucket), 240 - Key: aws.StringValue(input.Key), 228 + Bucket: aws.ToString(input.Bucket), 229 + Key: aws.ToString(input.Key), 241 230 }) 242 231 243 - url := fmt.Sprintf("%s/put/%s", m.TestServerURL, aws.StringValue(input.Key)) 244 - return &mockPresignable{url: url} 232 + url := fmt.Sprintf("%s/put/%s", m.TestServerURL, aws.ToString(input.Key)) 233 + return url, nil 245 234 }
+88 -65
pkg/s3/types.go
··· 3 3 package s3 4 4 5 5 import ( 6 + "context" 6 7 "fmt" 7 8 "log/slog" 8 9 "strings" 9 10 "time" 10 11 11 - "github.com/aws/aws-sdk-go/aws" 12 - "github.com/aws/aws-sdk-go/aws/credentials" 13 - "github.com/aws/aws-sdk-go/aws/request" 14 - "github.com/aws/aws-sdk-go/aws/session" 15 - "github.com/aws/aws-sdk-go/service/s3" 12 + "github.com/aws/aws-sdk-go-v2/aws" 13 + "github.com/aws/aws-sdk-go-v2/config" 14 + "github.com/aws/aws-sdk-go-v2/credentials" 15 + awss3 "github.com/aws/aws-sdk-go-v2/service/s3" 16 16 ) 17 17 18 - // Presignable represents a request that can be presigned for direct client access. 19 - // This interface allows mocking the Presign() method in tests. 20 - type Presignable interface { 21 - Presign(expire time.Duration) (string, error) 22 - } 23 - 24 18 // S3Client defines the S3 operations used by the hold service. 25 19 // This interface allows mocking S3 for tests without real credentials. 26 - // Use RealS3Client to wrap *s3.S3, or MockS3Client for testing. 20 + // Use RealS3Client to wrap *s3.Client, or MockS3Client for testing. 27 21 type S3Client interface { 28 22 // Multipart upload operations 29 - CreateMultipartUploadWithContext(ctx aws.Context, input *s3.CreateMultipartUploadInput, opts ...request.Option) (*s3.CreateMultipartUploadOutput, error) 30 - CompleteMultipartUploadWithContext(ctx aws.Context, input *s3.CompleteMultipartUploadInput, opts ...request.Option) (*s3.CompleteMultipartUploadOutput, error) 31 - AbortMultipartUploadWithContext(ctx aws.Context, input *s3.AbortMultipartUploadInput, opts ...request.Option) (*s3.AbortMultipartUploadOutput, error) 23 + CreateMultipartUpload(ctx context.Context, input *awss3.CreateMultipartUploadInput, opts ...func(*awss3.Options)) (*awss3.CreateMultipartUploadOutput, error) 24 + CompleteMultipartUpload(ctx context.Context, input *awss3.CompleteMultipartUploadInput, opts ...func(*awss3.Options)) (*awss3.CompleteMultipartUploadOutput, error) 25 + AbortMultipartUpload(ctx context.Context, input *awss3.AbortMultipartUploadInput, opts ...func(*awss3.Options)) (*awss3.AbortMultipartUploadOutput, error) 32 26 33 - // Presigned URL operations - return Presignable interface for testability 34 - // The second return value (_) is ignored by callers in practice 35 - UploadPartPresignable(input *s3.UploadPartInput) Presignable 36 - GetObjectPresignable(input *s3.GetObjectInput) Presignable 37 - HeadObjectPresignable(input *s3.HeadObjectInput) Presignable 38 - PutObjectPresignable(input *s3.PutObjectInput) Presignable 27 + // Presigned URL operations - return URL string directly 28 + PresignGetObject(ctx context.Context, input *awss3.GetObjectInput, expires time.Duration) (string, error) 29 + PresignHeadObject(ctx context.Context, input *awss3.HeadObjectInput, expires time.Duration) (string, error) 30 + PresignPutObject(ctx context.Context, input *awss3.PutObjectInput, expires time.Duration) (string, error) 31 + PresignUploadPart(ctx context.Context, input *awss3.UploadPartInput, expires time.Duration) (string, error) 39 32 } 40 33 41 - // RealS3Client wraps *s3.S3 to implement S3Client interface 34 + // RealS3Client wraps AWS SDK v2 *s3.Client to implement S3Client interface 42 35 type RealS3Client struct { 43 - client *s3.S3 36 + client *awss3.Client 37 + presign *awss3.PresignClient 44 38 } 45 39 46 40 // NewRealS3Client creates a new RealS3Client wrapper 47 - func NewRealS3Client(client *s3.S3) *RealS3Client { 48 - return &RealS3Client{client: client} 41 + func NewRealS3Client(client *awss3.Client) *RealS3Client { 42 + return &RealS3Client{ 43 + client: client, 44 + presign: awss3.NewPresignClient(client), 45 + } 49 46 } 50 47 51 - // CreateMultipartUploadWithContext implements S3Client 52 - func (r *RealS3Client) CreateMultipartUploadWithContext(ctx aws.Context, input *s3.CreateMultipartUploadInput, opts ...request.Option) (*s3.CreateMultipartUploadOutput, error) { 53 - return r.client.CreateMultipartUploadWithContext(ctx, input, opts...) 48 + // CreateMultipartUpload implements S3Client 49 + func (r *RealS3Client) CreateMultipartUpload(ctx context.Context, input *awss3.CreateMultipartUploadInput, opts ...func(*awss3.Options)) (*awss3.CreateMultipartUploadOutput, error) { 50 + return r.client.CreateMultipartUpload(ctx, input, opts...) 54 51 } 55 52 56 - // CompleteMultipartUploadWithContext implements S3Client 57 - func (r *RealS3Client) CompleteMultipartUploadWithContext(ctx aws.Context, input *s3.CompleteMultipartUploadInput, opts ...request.Option) (*s3.CompleteMultipartUploadOutput, error) { 58 - return r.client.CompleteMultipartUploadWithContext(ctx, input, opts...) 53 + // CompleteMultipartUpload implements S3Client 54 + func (r *RealS3Client) CompleteMultipartUpload(ctx context.Context, input *awss3.CompleteMultipartUploadInput, opts ...func(*awss3.Options)) (*awss3.CompleteMultipartUploadOutput, error) { 55 + return r.client.CompleteMultipartUpload(ctx, input, opts...) 59 56 } 60 57 61 - // AbortMultipartUploadWithContext implements S3Client 62 - func (r *RealS3Client) AbortMultipartUploadWithContext(ctx aws.Context, input *s3.AbortMultipartUploadInput, opts ...request.Option) (*s3.AbortMultipartUploadOutput, error) { 63 - return r.client.AbortMultipartUploadWithContext(ctx, input, opts...) 58 + // AbortMultipartUpload implements S3Client 59 + func (r *RealS3Client) AbortMultipartUpload(ctx context.Context, input *awss3.AbortMultipartUploadInput, opts ...func(*awss3.Options)) (*awss3.AbortMultipartUploadOutput, error) { 60 + return r.client.AbortMultipartUpload(ctx, input, opts...) 64 61 } 65 62 66 - // UploadPartPresignable implements S3Client 67 - func (r *RealS3Client) UploadPartPresignable(input *s3.UploadPartInput) Presignable { 68 - req, _ := r.client.UploadPartRequest(input) 69 - return req 63 + // PresignGetObject implements S3Client 64 + func (r *RealS3Client) PresignGetObject(ctx context.Context, input *awss3.GetObjectInput, expires time.Duration) (string, error) { 65 + result, err := r.presign.PresignGetObject(ctx, input, func(opts *awss3.PresignOptions) { 66 + opts.Expires = expires 67 + }) 68 + if err != nil { 69 + return "", err 70 + } 71 + return result.URL, nil 70 72 } 71 73 72 - // GetObjectPresignable implements S3Client 73 - func (r *RealS3Client) GetObjectPresignable(input *s3.GetObjectInput) Presignable { 74 - req, _ := r.client.GetObjectRequest(input) 75 - return req 74 + // PresignHeadObject implements S3Client 75 + func (r *RealS3Client) PresignHeadObject(ctx context.Context, input *awss3.HeadObjectInput, expires time.Duration) (string, error) { 76 + result, err := r.presign.PresignHeadObject(ctx, input, func(opts *awss3.PresignOptions) { 77 + opts.Expires = expires 78 + }) 79 + if err != nil { 80 + return "", err 81 + } 82 + return result.URL, nil 76 83 } 77 84 78 - // HeadObjectPresignable implements S3Client 79 - func (r *RealS3Client) HeadObjectPresignable(input *s3.HeadObjectInput) Presignable { 80 - req, _ := r.client.HeadObjectRequest(input) 81 - return req 85 + // PresignPutObject implements S3Client 86 + func (r *RealS3Client) PresignPutObject(ctx context.Context, input *awss3.PutObjectInput, expires time.Duration) (string, error) { 87 + result, err := r.presign.PresignPutObject(ctx, input, func(opts *awss3.PresignOptions) { 88 + opts.Expires = expires 89 + }) 90 + if err != nil { 91 + return "", err 92 + } 93 + return result.URL, nil 82 94 } 83 95 84 - // PutObjectPresignable implements S3Client 85 - func (r *RealS3Client) PutObjectPresignable(input *s3.PutObjectInput) Presignable { 86 - req, _ := r.client.PutObjectRequest(input) 87 - return req 96 + // PresignUploadPart implements S3Client 97 + func (r *RealS3Client) PresignUploadPart(ctx context.Context, input *awss3.UploadPartInput, expires time.Duration) (string, error) { 98 + result, err := r.presign.PresignUploadPart(ctx, input, func(opts *awss3.PresignOptions) { 99 + opts.Expires = expires 100 + }) 101 + if err != nil { 102 + return "", err 103 + } 104 + return result.URL, nil 88 105 } 89 106 90 107 // S3Service wraps an S3 client for presigned URL generation ··· 111 128 return nil, fmt.Errorf("S3 bucket not configured") 112 129 } 113 130 114 - // Build AWS config 115 - awsConfig := &aws.Config{ 116 - Region: &region, 117 - } 131 + // Build config options 132 + var configOpts []func(*config.LoadOptions) error 133 + configOpts = append(configOpts, config.WithRegion(region)) 118 134 119 135 // Add credentials if provided (allow IAM role auth if not provided) 120 136 if accessKey != "" && secretKey != "" { 121 - awsConfig.Credentials = credentials.NewStaticCredentials(accessKey, secretKey, "") 122 - } 123 - 124 - // Add custom endpoint for S3-compatible services (Storj, MinIO, R2, etc.) 125 - if endpoint, ok := params["regionendpoint"].(string); ok && endpoint != "" { 126 - awsConfig.Endpoint = &endpoint 127 - awsConfig.S3ForcePathStyle = aws.Bool(true) // Required for MinIO, Storj 137 + configOpts = append(configOpts, config.WithCredentialsProvider( 138 + credentials.NewStaticCredentialsProvider(accessKey, secretKey, ""), 139 + )) 128 140 } 129 141 130 - // Create AWS session 131 - sess, err := session.NewSession(awsConfig) 142 + // Load AWS config 143 + cfg, err := config.LoadDefaultConfig(context.Background(), configOpts...) 132 144 if err != nil { 133 - return nil, fmt.Errorf("failed to create AWS session: %w", err) 145 + return nil, fmt.Errorf("failed to load AWS config: %w", err) 134 146 } 135 147 148 + // Custom endpoint for S3-compatible services (Storj, MinIO, R2, etc.) 149 + endpoint, _ := params["regionendpoint"].(string) 150 + 151 + // Create S3 client 152 + client := awss3.NewFromConfig(cfg, func(o *awss3.Options) { 153 + if endpoint != "" { 154 + o.BaseEndpoint = aws.String(endpoint) 155 + o.UsePathStyle = true 156 + } 157 + }) 158 + 136 159 var s3PathPrefix string 137 160 // Extract path prefix if configured (rootdirectory in S3 params) 138 161 if rootDir, ok := params["rootdirectory"].(string); ok && rootDir != "" { ··· 146 169 147 170 // Create S3 client wrapped in RealS3Client for interface compatibility 148 171 return &S3Service{ 149 - Client: NewRealS3Client(s3.New(sess)), 172 + Client: NewRealS3Client(client), 150 173 Bucket: bucket, 151 174 PathPrefix: s3PathPrefix, 152 175 }, nil
+113
scanner/cmd/scanner/main.go
··· 1 + package main 2 + 3 + import ( 4 + "context" 5 + "fmt" 6 + "log/slog" 7 + "net/http" 8 + "os" 9 + "os/signal" 10 + "syscall" 11 + 12 + "github.com/spf13/cobra" 13 + 14 + "atcr.io/scanner/internal/client" 15 + "atcr.io/scanner/internal/config" 16 + "atcr.io/scanner/internal/queue" 17 + "atcr.io/scanner/internal/scan" 18 + ) 19 + 20 + var rootCmd = &cobra.Command{ 21 + Use: "atcr-scanner", 22 + Short: "ATCR Scanner - container image vulnerability scanner", 23 + } 24 + 25 + var serveCmd = &cobra.Command{ 26 + Use: "serve", 27 + Short: "Start the scanner service", 28 + Long: `Start the ATCR scanner service. 29 + 30 + The scanner connects to a hold service via WebSocket, receives scan jobs, 31 + generates SBOMs with Syft, scans for vulnerabilities with Grype, and sends 32 + results back over the same WebSocket connection. 33 + 34 + Configuration via environment variables (SCANNER_ prefix): 35 + SCANNER_HOLD_URL Hold service URL (required) 36 + SCANNER_SHARED_SECRET Shared secret for auth (required) 37 + SCANNER_WORKERS Worker count (default: 2) 38 + SCANNER_QUEUE_SIZE Max queue depth (default: 100) 39 + SCANNER_VULN_ENABLED Enable Grype scanning (default: true) 40 + SCANNER_VULN_DB_PATH Grype DB location (default: /var/lib/atcr-scanner/vulndb) 41 + SCANNER_TMP_DIR Temp dir for extraction (default: /var/lib/atcr-scanner/tmp) 42 + SCANNER_ADDR Health endpoint addr (default: :9090)`, 43 + Args: cobra.NoArgs, 44 + RunE: func(cmd *cobra.Command, args []string) error { 45 + cfg, err := config.Load() 46 + if err != nil { 47 + return fmt.Errorf("failed to load config: %w", err) 48 + } 49 + 50 + slog.Info("Starting ATCR scanner", 51 + "hold_url", cfg.HoldURL, 52 + "workers", cfg.Workers, 53 + "queue_size", cfg.QueueSize, 54 + "vuln_enabled", cfg.VulnEnabled) 55 + 56 + ctx, cancel := context.WithCancel(context.Background()) 57 + defer cancel() 58 + 59 + // Create priority queue 60 + q := queue.NewJobQueue(cfg.QueueSize) 61 + 62 + // Create hold WebSocket client 63 + holdClient := client.NewHoldClient(cfg.HoldURL, cfg.SharedSecret, q) 64 + 65 + // Start WebSocket connection (feeds queue) 66 + go holdClient.Connect() 67 + 68 + // Start worker pool (drains queue) 69 + pool := scan.NewWorkerPool(cfg, q, holdClient) 70 + pool.Start(ctx) 71 + 72 + // Start health endpoint 73 + mux := http.NewServeMux() 74 + mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { 75 + w.WriteHeader(http.StatusOK) 76 + w.Write([]byte("ok")) 77 + }) 78 + healthServer := &http.Server{Addr: cfg.Addr, Handler: mux} 79 + go func() { 80 + slog.Info("Health endpoint listening", "addr", cfg.Addr) 81 + if err := healthServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { 82 + slog.Error("Health server error", "error", err) 83 + } 84 + }() 85 + 86 + // Wait for shutdown signal 87 + sigCh := make(chan os.Signal, 1) 88 + signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) 89 + sig := <-sigCh 90 + slog.Info("Received shutdown signal", "signal", sig) 91 + 92 + // Graceful shutdown 93 + cancel() 94 + holdClient.Close() 95 + q.Close() 96 + pool.Wait() 97 + healthServer.Close() 98 + 99 + slog.Info("Scanner shutdown complete") 100 + return nil 101 + }, 102 + } 103 + 104 + func init() { 105 + rootCmd.AddCommand(serveCmd) 106 + } 107 + 108 + func main() { 109 + if err := rootCmd.Execute(); err != nil { 110 + slog.Error("Command failed", "error", err) 111 + os.Exit(1) 112 + } 113 + }
+308
scanner/go.mod
··· 1 + module atcr.io/scanner 2 + 3 + go 1.25.4 4 + 5 + require ( 6 + github.com/anchore/grype v0.107.1 7 + github.com/anchore/syft v1.41.2 8 + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 9 + github.com/spf13/cobra v1.10.2 10 + ) 11 + 12 + exclude google.golang.org/grpc/stats/opentelemetry v0.0.0-20240907200651-3ffb98b2c93a 13 + 14 + require ( 15 + cel.dev/expr v0.24.0 // indirect 16 + cloud.google.com/go v0.123.0 // indirect 17 + cloud.google.com/go/auth v0.17.0 // indirect 18 + cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect 19 + cloud.google.com/go/compute/metadata v0.9.0 // indirect 20 + cloud.google.com/go/iam v1.5.3 // indirect 21 + cloud.google.com/go/monitoring v1.24.2 // indirect 22 + cloud.google.com/go/storage v1.59.2 // indirect 23 + cyphar.com/go-pathrs v0.2.1 // indirect 24 + dario.cat/mergo v1.0.2 // indirect 25 + github.com/BurntSushi/toml v1.6.0 // indirect 26 + github.com/CycloneDX/cyclonedx-go v0.9.3 // indirect 27 + github.com/DataDog/zstd v1.5.7 // indirect 28 + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect 29 + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 // indirect 30 + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 // indirect 31 + github.com/Intevation/gval v1.3.0 // indirect 32 + github.com/Intevation/jsonpath v0.2.1 // indirect 33 + github.com/Masterminds/goutils v1.1.1 // indirect 34 + github.com/Masterminds/semver/v3 v3.4.0 // indirect 35 + github.com/Masterminds/sprig/v3 v3.3.0 // indirect 36 + github.com/Microsoft/go-winio v0.6.2 // indirect 37 + github.com/Microsoft/hcsshim v0.14.0-rc.1 // indirect 38 + github.com/OneOfOne/xxhash v1.2.8 // indirect 39 + github.com/ProtonMail/go-crypto v1.3.0 // indirect 40 + github.com/STARRY-S/zip v0.2.3 // indirect 41 + github.com/acobaugh/osrelease v0.1.0 // indirect 42 + github.com/adrg/xdg v0.5.3 // indirect 43 + github.com/agext/levenshtein v1.2.3 // indirect 44 + github.com/anchore/clio v0.0.0-20250715152405-a0fa658e5084 // indirect 45 + github.com/anchore/fangs v0.0.0-20250716230140-94c22408c232 // indirect 46 + github.com/anchore/go-collections v0.0.0-20251016125210-a3c352120e8c // indirect 47 + github.com/anchore/go-homedir v0.0.0-20250319154043-c29668562e4d // indirect 48 + github.com/anchore/go-logger v0.0.0-20250318195838-07ae343dd722 // indirect 49 + github.com/anchore/go-lzo v0.1.0 // indirect 50 + github.com/anchore/go-macholibre v0.0.0-20250320151634-807da7ad2331 // indirect 51 + github.com/anchore/go-rpmdb v0.0.0-20250516171929-f77691e1faec // indirect 52 + github.com/anchore/go-struct-converter v0.1.0 // indirect 53 + github.com/anchore/go-sync v0.0.0-20250714163430-add63db73ad1 // indirect 54 + github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4 // indirect 55 + github.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115 // indirect 56 + github.com/anchore/stereoscope v0.1.19 // indirect 57 + github.com/andybalholm/brotli v1.2.0 // indirect 58 + github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect 59 + github.com/aquasecurity/go-pep440-version v0.0.1 // indirect 60 + github.com/aquasecurity/go-version v0.0.1 // indirect 61 + github.com/aws/aws-sdk-go-v2 v1.41.0 // indirect 62 + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect 63 + github.com/aws/aws-sdk-go-v2/config v1.32.6 // indirect 64 + github.com/aws/aws-sdk-go-v2/credentials v1.19.6 // indirect 65 + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 // indirect 66 + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect 67 + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect 68 + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect 69 + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 // indirect 70 + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect 71 + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 // indirect 72 + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect 73 + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 // indirect 74 + github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0 // indirect 75 + github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 // indirect 76 + github.com/aws/aws-sdk-go-v2/service/sso v1.30.8 // indirect 77 + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 // indirect 78 + github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 // indirect 79 + github.com/aws/smithy-go v1.24.0 // indirect 80 + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect 81 + github.com/becheran/wildmatch-go v1.0.0 // indirect 82 + github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect 83 + github.com/bitnami/go-version v0.0.0-20250505154626-452e8c5ee607 // indirect 84 + github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect 85 + github.com/bmatcuk/doublestar/v2 v2.0.4 // indirect 86 + github.com/bmatcuk/doublestar/v4 v4.9.2 // indirect 87 + github.com/bodgit/plumbing v1.3.0 // indirect 88 + github.com/bodgit/sevenzip v1.6.1 // indirect 89 + github.com/bodgit/windows v1.0.1 // indirect 90 + github.com/cespare/xxhash/v2 v2.3.0 // indirect 91 + github.com/charmbracelet/colorprofile v0.3.1 // indirect 92 + github.com/charmbracelet/lipgloss v1.1.0 // indirect 93 + github.com/charmbracelet/x/ansi v0.10.1 // indirect 94 + github.com/charmbracelet/x/cellbuf v0.0.13 // indirect 95 + github.com/charmbracelet/x/term v0.2.1 // indirect 96 + github.com/clipperhouse/displaywidth v0.6.2 // indirect 97 + github.com/clipperhouse/stringish v0.1.1 // indirect 98 + github.com/clipperhouse/uax29/v2 v2.3.0 // indirect 99 + github.com/cloudflare/circl v1.6.1 // indirect 100 + github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f // indirect 101 + github.com/containerd/cgroups/v3 v3.1.2 // indirect 102 + github.com/containerd/containerd/api v1.10.0 // indirect 103 + github.com/containerd/containerd/v2 v2.2.1 // indirect 104 + github.com/containerd/continuity v0.4.5 // indirect 105 + github.com/containerd/errdefs v1.0.0 // indirect 106 + github.com/containerd/errdefs/pkg v0.3.0 // indirect 107 + github.com/containerd/fifo v1.1.0 // indirect 108 + github.com/containerd/log v0.1.0 // indirect 109 + github.com/containerd/platforms v1.0.0-rc.2 // indirect 110 + github.com/containerd/plugin v1.0.0 // indirect 111 + github.com/containerd/stargz-snapshotter/estargz v0.18.1 // indirect 112 + github.com/containerd/ttrpc v1.2.7 // indirect 113 + github.com/containerd/typeurl/v2 v2.2.3 // indirect 114 + github.com/cyphar/filepath-securejoin v0.6.0 // indirect 115 + github.com/deitch/magic v0.0.0-20240306090643-c67ab88f10cb // indirect 116 + github.com/diskfs/go-diskfs v1.7.0 // indirect 117 + github.com/distribution/reference v0.6.0 // indirect 118 + github.com/docker/cli v29.1.5+incompatible // indirect 119 + github.com/docker/distribution v2.8.3+incompatible // indirect 120 + github.com/docker/docker v28.5.2+incompatible // indirect 121 + github.com/docker/docker-credential-helpers v0.9.4 // indirect 122 + github.com/docker/go-connections v0.6.0 // indirect 123 + github.com/docker/go-units v0.5.0 // indirect 124 + github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect 125 + github.com/dustin/go-humanize v1.0.1 // indirect 126 + github.com/elliotchance/phpserialize v1.4.0 // indirect 127 + github.com/emirpasic/gods v1.18.1 // indirect 128 + github.com/envoyproxy/go-control-plane/envoy v1.35.0 // indirect 129 + github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect 130 + github.com/facebookincubator/nvdtools v0.1.5 // indirect 131 + github.com/fatih/color v1.18.0 // indirect 132 + github.com/felixge/fgprof v0.9.5 // indirect 133 + github.com/felixge/httpsnoop v1.0.4 // indirect 134 + github.com/fsnotify/fsnotify v1.9.0 // indirect 135 + github.com/gabriel-vasile/mimetype v1.4.12 // indirect 136 + github.com/github/go-spdx/v2 v2.3.6 // indirect 137 + github.com/glebarez/go-sqlite v1.22.0 // indirect 138 + github.com/glebarez/sqlite v1.11.0 // indirect 139 + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect 140 + github.com/go-git/go-billy/v5 v5.7.0 // indirect 141 + github.com/go-git/go-git/v5 v5.16.4 // indirect 142 + github.com/go-jose/go-jose/v4 v4.1.3 // indirect 143 + github.com/go-logr/logr v1.4.3 // indirect 144 + github.com/go-logr/stdr v1.2.2 // indirect 145 + github.com/go-restruct/restruct v1.2.0-alpha // indirect 146 + github.com/go-viper/mapstructure/v2 v2.5.0 // indirect 147 + github.com/goccy/go-yaml v1.19.2 // indirect 148 + github.com/gocsaf/csaf/v3 v3.5.1 // indirect 149 + github.com/gogo/protobuf v1.3.2 // indirect 150 + github.com/gohugoio/hashstructure v0.6.0 // indirect 151 + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect 152 + github.com/google/go-cmp v0.7.0 // indirect 153 + github.com/google/go-containerregistry v0.20.7 // indirect 154 + github.com/google/licensecheck v0.3.1 // indirect 155 + github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5 // indirect 156 + github.com/google/s2a-go v0.1.9 // indirect 157 + github.com/google/uuid v1.6.0 // indirect 158 + github.com/googleapis/enterprise-certificate-proxy v0.3.7 // indirect 159 + github.com/googleapis/gax-go/v2 v2.15.0 // indirect 160 + github.com/gookit/color v1.6.0 // indirect 161 + github.com/gpustack/gguf-parser-go v0.23.1 // indirect 162 + github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b // indirect 163 + github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.70 // indirect 164 + github.com/hashicorp/errwrap v1.1.0 // indirect 165 + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 166 + github.com/hashicorp/go-getter v1.8.4 // indirect 167 + github.com/hashicorp/go-multierror v1.1.1 // indirect 168 + github.com/hashicorp/go-version v1.8.0 // indirect 169 + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect 170 + github.com/hashicorp/hcl/v2 v2.24.0 // indirect 171 + github.com/henvic/httpretty v0.1.4 // indirect 172 + github.com/huandu/xstrings v1.5.0 // indirect 173 + github.com/iancoleman/strcase v0.3.0 // indirect 174 + github.com/inconshreveable/mousetrap v1.1.0 // indirect 175 + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect 176 + github.com/jinzhu/copier v0.4.0 // indirect 177 + github.com/jinzhu/inflection v1.0.0 // indirect 178 + github.com/jinzhu/now v1.1.5 // indirect 179 + github.com/json-iterator/go v1.1.12 // indirect 180 + github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 // indirect 181 + github.com/kevinburke/ssh_config v1.2.0 // indirect 182 + github.com/klauspost/compress v1.18.2 // indirect 183 + github.com/klauspost/pgzip v1.2.6 // indirect 184 + github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f // indirect 185 + github.com/knqyf263/go-deb-version v0.0.0-20241115132648-6f4aee6ccd23 // indirect 186 + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 187 + github.com/masahiro331/go-mvn-version v0.0.0-20250131095131-f4974fa13b8a // indirect 188 + github.com/mattn/go-colorable v0.1.14 // indirect 189 + github.com/mattn/go-isatty v0.0.20 // indirect 190 + github.com/mattn/go-runewidth v0.0.19 // indirect 191 + github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect 192 + github.com/mholt/archives v0.1.5 // indirect 193 + github.com/mikelolasagasti/xz v1.0.1 // indirect 194 + github.com/minio/minlz v1.0.1 // indirect 195 + github.com/mitchellh/copystructure v1.2.0 // indirect 196 + github.com/mitchellh/go-homedir v1.1.0 // indirect 197 + github.com/mitchellh/go-wordwrap v1.0.1 // indirect 198 + github.com/mitchellh/reflectwalk v1.0.2 // indirect 199 + github.com/moby/docker-image-spec v1.3.1 // indirect 200 + github.com/moby/locker v1.0.1 // indirect 201 + github.com/moby/sys/mountinfo v0.7.2 // indirect 202 + github.com/moby/sys/sequential v0.6.0 // indirect 203 + github.com/moby/sys/signal v0.7.1 // indirect 204 + github.com/moby/sys/user v0.4.0 // indirect 205 + github.com/moby/sys/userns v0.1.0 // indirect 206 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 207 + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect 208 + github.com/muesli/termenv v0.16.0 // indirect 209 + github.com/ncruces/go-strftime v1.0.0 // indirect 210 + github.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1 // indirect 211 + github.com/nwaples/rardecode/v2 v2.2.0 // indirect 212 + github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect 213 + github.com/olekukonko/errors v1.1.0 // indirect 214 + github.com/olekukonko/ll v0.1.4-0.20260115111900-9e59c2286df0 // indirect 215 + github.com/olekukonko/tablewriter v1.1.3 // indirect 216 + github.com/opencontainers/go-digest v1.0.0 // indirect 217 + github.com/opencontainers/image-spec v1.1.1 // indirect 218 + github.com/opencontainers/runtime-spec v1.3.0 // indirect 219 + github.com/opencontainers/selinux v1.13.1 // indirect 220 + github.com/openvex/go-vex v0.2.7 // indirect 221 + github.com/package-url/packageurl-go v0.1.3 // indirect 222 + github.com/pandatix/go-cvss v0.6.2 // indirect 223 + github.com/pborman/indent v1.2.1 // indirect 224 + github.com/pelletier/go-toml v1.9.5 // indirect 225 + github.com/pelletier/go-toml/v2 v2.2.4 // indirect 226 + github.com/pierrec/lz4/v4 v4.1.22 // indirect 227 + github.com/pjbgf/sha1cd v0.4.0 // indirect 228 + github.com/pkg/errors v0.9.1 // indirect 229 + github.com/pkg/profile v1.7.0 // indirect 230 + github.com/pkg/xattr v0.4.12 // indirect 231 + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect 232 + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect 233 + github.com/rivo/uniseg v0.4.7 // indirect 234 + github.com/rust-secure-code/go-rustaudit v0.0.0-20250226111315-e20ec32e963c // indirect 235 + github.com/sagikazarmark/locafero v0.9.0 // indirect 236 + github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect 237 + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect 238 + github.com/sassoftware/go-rpmutils v0.4.0 // indirect 239 + github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e // indirect 240 + github.com/sergi/go-diff v1.4.0 // indirect 241 + github.com/shopspring/decimal v1.4.0 // indirect 242 + github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect 243 + github.com/skeema/knownhosts v1.3.1 // indirect 244 + github.com/smallnest/ringbuffer v0.0.0-20241116012123-461381446e3d // indirect 245 + github.com/sorairolake/lzip-go v0.3.8 // indirect 246 + github.com/sourcegraph/conc v0.3.0 // indirect 247 + github.com/spdx/gordf v0.0.0-20250128162952-000978ccd6fb // indirect 248 + github.com/spdx/tools-golang v0.5.7 // indirect 249 + github.com/spf13/afero v1.15.0 // indirect 250 + github.com/spf13/cast v1.9.2 // indirect 251 + github.com/spf13/pflag v1.0.9 // indirect 252 + github.com/spf13/viper v1.20.1 // indirect 253 + github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect 254 + github.com/subosito/gotenv v1.6.0 // indirect 255 + github.com/sylabs/sif/v2 v2.22.0 // indirect 256 + github.com/sylabs/squashfs v1.0.6 // indirect 257 + github.com/therootcompany/xz v1.0.1 // indirect 258 + github.com/ulikunitz/xz v0.5.15 // indirect 259 + github.com/vbatts/go-mtree v0.7.0 // indirect 260 + github.com/vbatts/tar-split v0.12.2 // indirect 261 + github.com/vifraa/gopom v1.0.0 // indirect 262 + github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 // indirect 263 + github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0 // indirect 264 + github.com/xanzy/ssh-agent v0.3.3 // indirect 265 + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect 266 + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect 267 + github.com/zclconf/go-cty v1.16.3 // indirect 268 + go.etcd.io/bbolt v1.4.3 // indirect 269 + go.opencensus.io v0.24.0 // indirect 270 + go.opentelemetry.io/auto/sdk v1.2.1 // indirect 271 + go.opentelemetry.io/contrib/detectors/gcp v1.38.0 // indirect 272 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect 273 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect 274 + go.opentelemetry.io/otel v1.39.0 // indirect 275 + go.opentelemetry.io/otel/metric v1.39.0 // indirect 276 + go.opentelemetry.io/otel/sdk v1.39.0 // indirect 277 + go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect 278 + go.opentelemetry.io/otel/trace v1.39.0 // indirect 279 + go.uber.org/multierr v1.11.0 // indirect 280 + go.yaml.in/yaml/v3 v3.0.4 // indirect 281 + go4.org v0.0.0-20230225012048-214862532bf5 // indirect 282 + golang.org/x/crypto v0.47.0 // indirect 283 + golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect 284 + golang.org/x/mod v0.32.0 // indirect 285 + golang.org/x/net v0.49.0 // indirect 286 + golang.org/x/oauth2 v0.33.0 // indirect 287 + golang.org/x/sync v0.19.0 // indirect 288 + golang.org/x/sys v0.40.0 // indirect 289 + golang.org/x/term v0.39.0 // indirect 290 + golang.org/x/text v0.33.0 // indirect 291 + golang.org/x/time v0.14.0 // indirect 292 + golang.org/x/tools v0.41.0 // indirect 293 + golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect 294 + gonum.org/v1/gonum v0.16.0 // indirect 295 + google.golang.org/api v0.256.0 // indirect 296 + google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9 // indirect 297 + google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba // indirect 298 + google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect 299 + google.golang.org/grpc v1.78.0 // indirect 300 + google.golang.org/protobuf v1.36.10 // indirect 301 + gopkg.in/warnings.v0 v0.1.2 // indirect 302 + gopkg.in/yaml.v3 v3.0.1 // indirect 303 + gorm.io/gorm v1.31.1 // indirect 304 + modernc.org/libc v1.67.6 // indirect 305 + modernc.org/mathutil v1.7.1 // indirect 306 + modernc.org/memory v1.11.0 // indirect 307 + modernc.org/sqlite v1.44.3 // indirect 308 + )
+1556
scanner/go.sum
··· 1 + cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= 2 + cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= 3 + cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 4 + cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 5 + cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 6 + cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 7 + cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 8 + cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 9 + cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 10 + cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 11 + cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 12 + cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 13 + cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 14 + cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 15 + cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 16 + cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 17 + cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 18 + cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= 19 + cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= 20 + cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= 21 + cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= 22 + cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= 23 + cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= 24 + cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= 25 + cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= 26 + cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= 27 + cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= 28 + cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= 29 + cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= 30 + cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= 31 + cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= 32 + cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= 33 + cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= 34 + cloud.google.com/go/auth v0.17.0 h1:74yCm7hCj2rUyyAocqnFzsAYXgJhrG26XCFimrc/Kz4= 35 + cloud.google.com/go/auth v0.17.0/go.mod h1:6wv/t5/6rOPAX4fJiRjKkJCvswLwdet7G8+UGXt7nCQ= 36 + cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= 37 + cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= 38 + cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 39 + cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 40 + cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 41 + cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 42 + cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 43 + cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 44 + cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= 45 + cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= 46 + cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 47 + cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 48 + cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= 49 + cloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc= 50 + cloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU= 51 + cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc= 52 + cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA= 53 + cloud.google.com/go/longrunning v0.7.0 h1:FV0+SYF1RIj59gyoWDRi45GiYUMM3K1qO51qoboQT1E= 54 + cloud.google.com/go/longrunning v0.7.0/go.mod h1:ySn2yXmjbK9Ba0zsQqunhDkYi0+9rlXIwnoAf+h+TPY= 55 + cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM= 56 + cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U= 57 + cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 58 + cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 59 + cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 60 + cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 61 + cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 62 + cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 63 + cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 64 + cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 65 + cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 66 + cloud.google.com/go/storage v1.59.2 h1:gmOAuG1opU8YvycMNpP+DvHfT9BfzzK5Cy+arP+Nocw= 67 + cloud.google.com/go/storage v1.59.2/go.mod h1:cMWbtM+anpC74gn6qjLh+exqYcfmB9Hqe5z6adx+CLI= 68 + cloud.google.com/go/trace v1.11.6 h1:2O2zjPzqPYAHrn3OKl029qlqG6W8ZdYaOWRyr8NgMT4= 69 + cloud.google.com/go/trace v1.11.6/go.mod h1:GA855OeDEBiBMzcckLPE2kDunIpC72N+Pq8WFieFjnI= 70 + cyphar.com/go-pathrs v0.2.1 h1:9nx1vOgwVvX1mNBWDu93+vaceedpbsDqo+XuBGL40b8= 71 + cyphar.com/go-pathrs v0.2.1/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc= 72 + dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= 73 + dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= 74 + dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 75 + github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= 76 + github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= 77 + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= 78 + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= 79 + github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 80 + github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= 81 + github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= 82 + github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= 83 + github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 84 + github.com/CycloneDX/cyclonedx-go v0.9.3 h1:Pyk/lwavPz7AaZNvugKFkdWOm93MzaIyWmBwmBo3aUI= 85 + github.com/CycloneDX/cyclonedx-go v0.9.3/go.mod h1:vcK6pKgO1WanCdd61qx4bFnSsDJQ6SbM2ZuMIgq86Jg= 86 + github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= 87 + github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= 88 + github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= 89 + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= 90 + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= 91 + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 h1:lhhYARPUu3LmHysQ/igznQphfzynnqI3D75oUyw1HXk= 92 + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0/go.mod h1:l9rva3ApbBpEJxSNYnwT9N4CDLrWgtq3u8736C5hyJw= 93 + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0 h1:xfK3bbi6F2RDtaZFtUdKO3osOBIhNb+xTs8lFW6yx9o= 94 + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA= 95 + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 h1:s0WlVbf9qpvkh1c/uDAPElam0WrL7fHRIidgZJ7UqZI= 96 + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= 97 + github.com/Intevation/gval v1.3.0 h1:+Ze5sft5MmGbZrHj06NVUbcxCb67l9RaPTLMNr37mjw= 98 + github.com/Intevation/gval v1.3.0/go.mod h1:xmGyGpP5be12EL0P12h+dqiYG8qn2j3PJxIgkoOHO5o= 99 + github.com/Intevation/jsonpath v0.2.1 h1:rINNQJ0Pts5XTFEG+zamtdL7l9uuE1z0FBA+r55Sw+A= 100 + github.com/Intevation/jsonpath v0.2.1/go.mod h1:WnZ8weMmwAx/fAO3SutjYFU+v7DFreNYnibV7CiaYIw= 101 + github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= 102 + github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= 103 + github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= 104 + github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= 105 + github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= 106 + github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= 107 + github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= 108 + github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= 109 + github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= 110 + github.com/Microsoft/hcsshim v0.14.0-rc.1 h1:qAPXKwGOkVn8LlqgBN8GS0bxZ83hOJpcjxzmlQKxKsQ= 111 + github.com/Microsoft/hcsshim v0.14.0-rc.1/go.mod h1:hTKFGbnDtQb1wHiOWv4v0eN+7boSWAHyK/tNAaYZL0c= 112 + github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 113 + github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= 114 + github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= 115 + github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw= 116 + github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= 117 + github.com/STARRY-S/zip v0.2.3 h1:luE4dMvRPDOWQdeDdUxUoZkzUIpTccdKdhHHsQJ1fm4= 118 + github.com/STARRY-S/zip v0.2.3/go.mod h1:lqJ9JdeRipyOQJrYSOtpNAiaesFO6zVDsE8GIGFaoSk= 119 + github.com/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+UifRE= 120 + github.com/acobaugh/osrelease v0.1.0/go.mod h1:4bFEs0MtgHNHBrmHCt67gNisnabCRAlzdVasCEGHTWY= 121 + github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78= 122 + github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ= 123 + github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= 124 + github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= 125 + github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 126 + github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 127 + github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 128 + github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 129 + github.com/anchore/clio v0.0.0-20250715152405-a0fa658e5084 h1:7DUAXEdAxoANPlDgxYiaSRKnWnTygvdrrWhnmvEjNLg= 130 + github.com/anchore/clio v0.0.0-20250715152405-a0fa658e5084/go.mod h1:42dWox8z4//b898OIELsQnSdYq9q1aCXkwp5fKF+BEU= 131 + github.com/anchore/fangs v0.0.0-20250716230140-94c22408c232 h1:aVC6r9h5wGNh8BYTW3CXxOdPoZzY/bBRWne1NvSTlO8= 132 + github.com/anchore/fangs v0.0.0-20250716230140-94c22408c232/go.mod h1:Zees1AEKNpXIRgdVAMYWITncarLFiPOtEQ7rl45V/h0= 133 + github.com/anchore/go-collections v0.0.0-20251016125210-a3c352120e8c h1:eoJXyC0n7DZ4YvySG/ETdYkTar2Due7eH+UmLK6FbrA= 134 + github.com/anchore/go-collections v0.0.0-20251016125210-a3c352120e8c/go.mod h1:1aiktV46ATCkuVg0O573ZrH56BUawTECPETbZyBcqT8= 135 + github.com/anchore/go-homedir v0.0.0-20250319154043-c29668562e4d h1:gT69osH9AsdpOfqxbRwtxcNnSZ1zg4aKy2BevO3ZBdc= 136 + github.com/anchore/go-homedir v0.0.0-20250319154043-c29668562e4d/go.mod h1:PhSnuFYknwPZkOWKB1jXBNToChBA+l0FjwOxtViIc50= 137 + github.com/anchore/go-logger v0.0.0-20250318195838-07ae343dd722 h1:2SqmFgE7h+Ql4VyBzhjLkRF/3gDrcpUBj8LjvvO6OOM= 138 + github.com/anchore/go-logger v0.0.0-20250318195838-07ae343dd722/go.mod h1:oFuE8YuTCM+spgMXhePGzk3asS94yO9biUfDzVTFqNw= 139 + github.com/anchore/go-lzo v0.1.0 h1:NgAacnzqPeGH49Ky19QKLBZEuFRqtTG9cdaucc3Vncs= 140 + github.com/anchore/go-lzo v0.1.0/go.mod h1:3kLx0bve2oN1iDwgM1U5zGku1Tfbdb0No5qp1eL1fIk= 141 + github.com/anchore/go-macholibre v0.0.0-20250320151634-807da7ad2331 h1:fWPHXkH3FQGVCyPkFMqNvMjQvdNMfkylBTsDqZC4lE4= 142 + github.com/anchore/go-macholibre v0.0.0-20250320151634-807da7ad2331/go.mod h1:DYvTRnWrlJ//6YOR83SiewmJiNFDEMRaOTnrzgco9FA= 143 + github.com/anchore/go-rpmdb v0.0.0-20250516171929-f77691e1faec h1:SjjPMOXTzpuU1ZME4XeoHyek+dry3/C7I8gzaCo02eg= 144 + github.com/anchore/go-rpmdb v0.0.0-20250516171929-f77691e1faec/go.mod h1:eQVa6QFGzKy0qMcnW2pez0XBczvgwSjw9vA23qifEyU= 145 + github.com/anchore/go-struct-converter v0.1.0 h1:2rDRssAl6mgKBSLNiVCMADgZRhoqtw9dedlWa0OhD30= 146 + github.com/anchore/go-struct-converter v0.1.0/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA= 147 + github.com/anchore/go-sync v0.0.0-20250714163430-add63db73ad1 h1:UK1SWZf2xD5jq8QVeDdpt6wW31cO3RckBvPmGlDrTkg= 148 + github.com/anchore/go-sync v0.0.0-20250714163430-add63db73ad1/go.mod h1:hd0Ol9qFM8tRDdF50a+DpZEoB0HFNaEnCp/BSVyBRlg= 149 + github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 h1:VzprUTpc0vW0nnNKJfJieyH/TZ9UYAnTZs5/gHTdAe8= 150 + github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04/go.mod h1:6dK64g27Qi1qGQZ67gFmBFvEHScy0/C8qhQhNe5B5pQ= 151 + github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4 h1:rmZG77uXgE+o2gozGEBoUMpX27lsku+xrMwlmBZJtbg= 152 + github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E= 153 + github.com/anchore/grype v0.107.1 h1:N7EIlJfuq7RKA5nSgXPxOfifyB8EABYd2vP+CJwL1bY= 154 + github.com/anchore/grype v0.107.1/go.mod h1:DilbSyGMuYZREWL/tIZYOA4PedC2X2FOaEMAmQaNGhg= 155 + github.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115 h1:ZyRCmiEjnoGJZ1+Ah0ZZ/mKKqNhGcUZBl0s7PTTDzvY= 156 + github.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115/go.mod h1:KoYIv7tdP5+CC9VGkeZV4/vGCKsY55VvoG+5dadg4YI= 157 + github.com/anchore/stereoscope v0.1.19 h1:1G5LVmRN1Sz6qNezpVAEeN7QfWwCE9zw9TJK1ZGnkvw= 158 + github.com/anchore/stereoscope v0.1.19/go.mod h1:+laNHlk05xA2YqgEzq8mxkFzclL3NRdeNIsiQQVeZZ4= 159 + github.com/anchore/syft v1.41.2 h1:mC2l3P8dUvBdz+97ZNcKD410s8vGFGFXdZa+neaQEb8= 160 + github.com/anchore/syft v1.41.2/go.mod h1:j8SaTiPQzSxElS0MWw3ML2m2EK4av/7Vm4q8WpwUmYw= 161 + github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= 162 + github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= 163 + github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= 164 + github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= 165 + github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= 166 + github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= 167 + github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= 168 + github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= 169 + github.com/aquasecurity/go-pep440-version v0.0.1 h1:8VKKQtH2aV61+0hovZS3T//rUF+6GDn18paFTVS0h0M= 170 + github.com/aquasecurity/go-pep440-version v0.0.1/go.mod h1:3naPe+Bp6wi3n4l5iBFCZgS0JG8vY6FT0H4NGhFJ+i4= 171 + github.com/aquasecurity/go-version v0.0.1 h1:4cNl516agK0TCn5F7mmYN+xVs1E3S45LkgZk3cbaW2E= 172 + github.com/aquasecurity/go-version v0.0.1/go.mod h1:s1UU6/v2hctXcOa3OLwfj5d9yoXHa3ahf+ipSwEvGT0= 173 + github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 174 + github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= 175 + github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= 176 + github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 177 + github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 178 + github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= 179 + github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= 180 + github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= 181 + github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= 182 + github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4= 183 + github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= 184 + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU= 185 + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4= 186 + github.com/aws/aws-sdk-go-v2/config v1.32.6 h1:hFLBGUKjmLAekvi1evLi5hVvFQtSo3GYwi+Bx4lpJf8= 187 + github.com/aws/aws-sdk-go-v2/config v1.32.6/go.mod h1:lcUL/gcd8WyjCrMnxez5OXkO3/rwcNmvfno62tnXNcI= 188 + github.com/aws/aws-sdk-go-v2/credentials v1.19.6 h1:F9vWao2TwjV2MyiyVS+duza0NIRtAslgLUM0vTA1ZaE= 189 + github.com/aws/aws-sdk-go-v2/credentials v1.19.6/go.mod h1:SgHzKjEVsdQr6Opor0ihgWtkWdfRAIwxYzSJ8O85VHY= 190 + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 h1:80+uETIWS1BqjnN9uJ0dBUaETh+P1XwFy5vwHwK5r9k= 191 + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16/go.mod h1:wOOsYuxYuB/7FlnVtzeBYRcjSRtQpAW0hCP7tIULMwo= 192 + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc= 193 + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA= 194 + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U= 195 + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc= 196 + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk= 197 + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= 198 + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 h1:CjMzUs78RDDv4ROu3JnJn/Ig1r6ZD7/T2DXLLRpejic= 199 + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16/go.mod h1:uVW4OLBqbJXSHJYA9svT9BluSvvwbzLQ2Crf6UPzR3c= 200 + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E= 201 + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow= 202 + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 h1:DIBqIrJ7hv+e4CmIk2z3pyKT+3B6qVMgRsawHiR3qso= 203 + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7/go.mod h1:vLm00xmBke75UmpNvOcZQ/Q30ZFjbczeLFqGx5urmGo= 204 + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI= 205 + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM= 206 + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 h1:NSbvS17MlI2lurYgXnCOLvCFX38sBW4eiVER7+kkgsU= 207 + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16/go.mod h1:SwT8Tmqd4sA6G1qaGdzWCJN99bUmPGHfRwwq3G5Qb+A= 208 + github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0 h1:MIWra+MSq53CFaXXAywB2qg9YvVZifkk6vEGl/1Qor0= 209 + github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0/go.mod h1:79S2BdqCJpScXZA2y+cpZuocWsjGjJINyXnOsf5DTz8= 210 + github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 h1:HpI7aMmJ+mm1wkSHIA2t5EaFFv5EFYXePW30p1EIrbQ= 211 + github.com/aws/aws-sdk-go-v2/service/signin v1.0.4/go.mod h1:C5RdGMYGlfM0gYq/tifqgn4EbyX99V15P2V3R+VHbQU= 212 + github.com/aws/aws-sdk-go-v2/service/sso v1.30.8 h1:aM/Q24rIlS3bRAhTyFurowU8A0SMyGDtEOY/l/s/1Uw= 213 + github.com/aws/aws-sdk-go-v2/service/sso v1.30.8/go.mod h1:+fWt2UHSb4kS7Pu8y+BMBvJF0EWx+4H0hzNwtDNRTrg= 214 + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 h1:AHDr0DaHIAo8c9t1emrzAlVDFp+iMMKnPdYy6XO4MCE= 215 + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12/go.mod h1:GQ73XawFFiWxyWXMHWfhiomvP3tXtdNar/fi8z18sx0= 216 + github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70= 217 + github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk= 218 + github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= 219 + github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= 220 + github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= 221 + github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= 222 + github.com/becheran/wildmatch-go v1.0.0 h1:mE3dGGkTmpKtT4Z+88t8RStG40yN9T+kFEGj2PZFSzA= 223 + github.com/becheran/wildmatch-go v1.0.0/go.mod h1:gbMvj0NtVdJ15Mg/mH9uxk2R1QCistMyU7d9KFzroX4= 224 + github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 225 + github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 226 + github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 227 + github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= 228 + github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= 229 + github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 230 + github.com/bitnami/go-version v0.0.0-20250505154626-452e8c5ee607 h1:lBg3tHGquFySSblLi9zNi2iGNmVLRHBzVal2fqphCM8= 231 + github.com/bitnami/go-version v0.0.0-20250505154626-452e8c5ee607/go.mod h1:9iglf1GG4oNRJ39bZ5AZrjgAFD2RwQbXw6Qf7Cs47wo= 232 + github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4= 233 + github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= 234 + github.com/bmatcuk/doublestar/v2 v2.0.4 h1:6I6oUiT/sU27eE2OFcWqBhL1SwjyvQuOssxT4a1yidI= 235 + github.com/bmatcuk/doublestar/v2 v2.0.4/go.mod h1:QMmcs3H2AUQICWhfzLXz+IYln8lRQmTZRptLie8RgRw= 236 + github.com/bmatcuk/doublestar/v4 v4.9.2 h1:b0mc6WyRSYLjzofB2v/0cuDUZ+MqoGyH3r0dVij35GI= 237 + github.com/bmatcuk/doublestar/v4 v4.9.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= 238 + github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU= 239 + github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs= 240 + github.com/bodgit/sevenzip v1.6.1 h1:kikg2pUMYC9ljU7W9SaqHXhym5HyKm8/M/jd31fYan4= 241 + github.com/bodgit/sevenzip v1.6.1/go.mod h1:GVoYQbEVbOGT8n2pfqCIMRUaRjQ8F9oSqoBEqZh5fQ8= 242 + github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4= 243 + github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM= 244 + github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M= 245 + github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= 246 + github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= 247 + github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= 248 + github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 249 + github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 250 + github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 251 + github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 252 + github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 253 + github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= 254 + github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 255 + github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs= 256 + github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg= 257 + github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw= 258 + github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4= 259 + github.com/charmbracelet/colorprofile v0.3.1 h1:k8dTHMd7fgw4bnFd7jXTLZrSU/CQrKnL3m+AxCzDz40= 260 + github.com/charmbracelet/colorprofile v0.3.1/go.mod h1:/GkGusxNs8VB/RSOh3fu0TJmQ4ICMMPApIIVn0KszZ0= 261 + github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= 262 + github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= 263 + github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ= 264 + github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE= 265 + github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k= 266 + github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= 267 + github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= 268 + github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= 269 + github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= 270 + github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= 271 + github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= 272 + github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 273 + github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= 274 + github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 275 + github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= 276 + github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 277 + github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= 278 + github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= 279 + github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= 280 + github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 281 + github.com/clipperhouse/displaywidth v0.6.2 h1:ZDpTkFfpHOKte4RG5O/BOyf3ysnvFswpyYrV7z2uAKo= 282 + github.com/clipperhouse/displaywidth v0.6.2/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o= 283 + github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= 284 + github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= 285 + github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= 286 + github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= 287 + github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= 288 + github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= 289 + github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 290 + github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 291 + github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 292 + github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= 293 + github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 294 + github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 295 + github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 296 + github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 297 + github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 298 + github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 299 + github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f h1:Y8xYupdHxryycyPlc9Y+bSQAYZnetRJ70VMVKm5CKI0= 300 + github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f/go.mod h1:HlzOvOjVBOfTGSRXRyY0OiCS/3J1akRGQQpRO/7zyF4= 301 + github.com/containerd/cgroups/v3 v3.1.2 h1:OSosXMtkhI6Qove637tg1XgK4q+DhR0mX8Wi8EhrHa4= 302 + github.com/containerd/cgroups/v3 v3.1.2/go.mod h1:PKZ2AcWmSBsY/tJUVhtS/rluX0b1uq1GmPO1ElCmbOw= 303 + github.com/containerd/containerd/api v1.10.0 h1:5n0oHYVBwN4VhoX9fFykCV9dF1/BvAXeg2F8W6UYq1o= 304 + github.com/containerd/containerd/api v1.10.0/go.mod h1:NBm1OAk8ZL+LG8R0ceObGxT5hbUYj7CzTmR3xh0DlMM= 305 + github.com/containerd/containerd/v2 v2.2.1 h1:TpyxcY4AL5A+07dxETevunVS5zxqzuq7ZqJXknM11yk= 306 + github.com/containerd/containerd/v2 v2.2.1/go.mod h1:NR70yW1iDxe84F2iFWbR9xfAN0N2F0NcjTi1OVth4nU= 307 + github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= 308 + github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= 309 + github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= 310 + github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= 311 + github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= 312 + github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= 313 + github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY= 314 + github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o= 315 + github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= 316 + github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= 317 + github.com/containerd/platforms v1.0.0-rc.2 h1:0SPgaNZPVWGEi4grZdV8VRYQn78y+nm6acgLGv/QzE4= 318 + github.com/containerd/platforms v1.0.0-rc.2/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4= 319 + github.com/containerd/plugin v1.0.0 h1:c8Kf1TNl6+e2TtMHZt+39yAPDbouRH9WAToRjex483Y= 320 + github.com/containerd/plugin v1.0.0/go.mod h1:hQfJe5nmWfImiqT1q8Si3jLv3ynMUIBB47bQ+KexvO8= 321 + github.com/containerd/stargz-snapshotter/estargz v0.18.1 h1:cy2/lpgBXDA3cDKSyEfNOFMA/c10O1axL69EU7iirO8= 322 + github.com/containerd/stargz-snapshotter/estargz v0.18.1/go.mod h1:ALIEqa7B6oVDsrF37GkGN20SuvG/pIMm7FwP7ZmRb0Q= 323 + github.com/containerd/ttrpc v1.2.7 h1:qIrroQvuOL9HQ1X6KHe2ohc7p+HP/0VE6XPU7elJRqQ= 324 + github.com/containerd/ttrpc v1.2.7/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o= 325 + github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++dYSw40= 326 + github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk= 327 + github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 328 + github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 329 + github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 330 + github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 331 + github.com/cyphar/filepath-securejoin v0.6.0 h1:BtGB77njd6SVO6VztOHfPxKitJvd/VPT+OFBFMOi1Is= 332 + github.com/cyphar/filepath-securejoin v0.6.0/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc= 333 + github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 334 + github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 335 + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= 336 + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 337 + github.com/deitch/magic v0.0.0-20240306090643-c67ab88f10cb h1:4W/2rQ3wzEimF5s+J6OY3ODiQtJZ5W1sForSgogVXkY= 338 + github.com/deitch/magic v0.0.0-20240306090643-c67ab88f10cb/go.mod h1:B3tI9iGHi4imdLi4Asdha1Sc6feLMTfPLXh9IUYmysk= 339 + github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4= 340 + github.com/diskfs/go-diskfs v1.7.0 h1:vonWmt5CMowXwUc79jWyGrf2DIMeoOjkLlMnQYGVOs8= 341 + github.com/diskfs/go-diskfs v1.7.0/go.mod h1:LhQyXqOugWFRahYUSw47NyZJPezFzB9UELwhpszLP/k= 342 + github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= 343 + github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= 344 + github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c= 345 + github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0= 346 + github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= 347 + github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= 348 + github.com/docker/cli v29.1.5+incompatible h1:GckbANUt3j+lsnQ6eCcQd70mNSOismSHWt8vk2AX8ao= 349 + github.com/docker/cli v29.1.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= 350 + github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= 351 + github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= 352 + github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= 353 + github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 354 + github.com/docker/docker-credential-helpers v0.9.4 h1:76ItO69/AP/V4yT9V4uuuItG0B1N8hvt0T0c0NN/DzI= 355 + github.com/docker/docker-credential-helpers v0.9.4/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c= 356 + github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= 357 + github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= 358 + github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= 359 + github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 360 + github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4= 361 + github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= 362 + github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= 363 + github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 364 + github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 365 + github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= 366 + github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= 367 + github.com/elliotchance/phpserialize v1.4.0 h1:cAp/9+KSnEbUC8oYCE32n2n84BeW8HOY3HMDI8hG2OY= 368 + github.com/elliotchance/phpserialize v1.4.0/go.mod h1:gt7XX9+ETUcLXbtTKEuyrqW3lcLUAeS/AnGZ2e49TZs= 369 + github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab h1:h1UgjJdAAhj+uPL68n7XASS6bU+07ZX1WJvVS2eyoeY= 370 + github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab/go.mod h1:GLo/8fDswSAniFG+BFIaiSPcK610jyzgEhWYPQwuQdw= 371 + github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= 372 + github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= 373 + github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 374 + github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 375 + github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 376 + github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= 377 + github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 378 + github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 379 + github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= 380 + github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= 381 + github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= 382 + github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329 h1:K+fnvUM0VZ7ZFJf0n4L/BRlnsb9pL/GuDG6FqaH+PwM= 383 + github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329/go.mod h1:Alz8LEClvR7xKsrq3qzoc4N0guvVNSS8KmSChGYr9hs= 384 + github.com/envoyproxy/go-control-plane/envoy v1.35.0 h1:ixjkELDE+ru6idPxcHLj8LBVc2bFP7iBytj353BoHUo= 385 + github.com/envoyproxy/go-control-plane/envoy v1.35.0/go.mod h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs= 386 + github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= 387 + github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= 388 + github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 389 + github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= 390 + github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= 391 + github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= 392 + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= 393 + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= 394 + github.com/facebookincubator/flog v0.0.0-20190930132826-d2511d0ce33c/go.mod h1:QGzNH9ujQ2ZUr/CjDGZGWeDAVStrWNjHeEcjJL96Nuk= 395 + github.com/facebookincubator/nvdtools v0.1.5 h1:jbmDT1nd6+k+rlvKhnkgMokrCAzHoASWE5LtHbX2qFQ= 396 + github.com/facebookincubator/nvdtools v0.1.5/go.mod h1:Kh55SAWnjckS96TBSrXI99KrEKH4iB0OJby3N8GRJO4= 397 + github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 398 + github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= 399 + github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= 400 + github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= 401 + github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= 402 + github.com/fatih/set v0.2.1 h1:nn2CaJyknWE/6txyUDGwysr3G5QC6xWB/PtVjPBbeaA= 403 + github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI= 404 + github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= 405 + github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY= 406 + github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM= 407 + github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= 408 + github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= 409 + github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= 410 + github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 411 + github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= 412 + github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= 413 + github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= 414 + github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= 415 + github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= 416 + github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 417 + github.com/github/go-spdx/v2 v2.3.6 h1:9flm625VmmTlWXi0YH5W9V8FdMfulvxalHdYnUfoqxc= 418 + github.com/github/go-spdx/v2 v2.3.6/go.mod h1:/5rwgS0txhGtRdUZwc02bTglzg6HK3FfuEbECKlK2Sg= 419 + github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= 420 + github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= 421 + github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= 422 + github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ= 423 + github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= 424 + github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= 425 + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= 426 + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= 427 + github.com/go-git/go-billy/v5 v5.7.0 h1:83lBUJhGWhYp0ngzCMSgllhUSuoHP1iEWYjsPl9nwqM= 428 + github.com/go-git/go-billy/v5 v5.7.0/go.mod h1:/1IUejTKH8xipsAcdfcSAlUlo2J7lkYV8GTKxAT/L3E= 429 + github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= 430 + github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= 431 + github.com/go-git/go-git/v5 v5.16.4 h1:7ajIEZHZJULcyJebDLo99bGgS0jRrOxzZG4uCk2Yb2Y= 432 + github.com/go-git/go-git/v5 v5.16.4/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8= 433 + github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 434 + github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 435 + github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 436 + github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= 437 + github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= 438 + github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 439 + github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 440 + github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 441 + github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 442 + github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 443 + github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= 444 + github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 445 + github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 446 + github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 447 + github.com/go-restruct/restruct v1.2.0-alpha h1:2Lp474S/9660+SJjpVxoKuWX09JsXHSrdV7Nv3/gkvc= 448 + github.com/go-restruct/restruct v1.2.0-alpha/go.mod h1:KqrpKpn4M8OLznErihXTGLlsXFGeLxHUrLRRI/1YjGk= 449 + github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 450 + github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 451 + github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= 452 + github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= 453 + github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= 454 + github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 455 + github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= 456 + github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= 457 + github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= 458 + github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= 459 + github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= 460 + github.com/gocsaf/csaf/v3 v3.5.1 h1:jTA1fLrK0/JIczPs7itTD53qANoO4tn2VaGvUeitePc= 461 + github.com/gocsaf/csaf/v3 v3.5.1/go.mod h1:pga89lE+iWJm7smTdzYcXuetYUbgY8caXfaIP4BJG98= 462 + github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 463 + github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 464 + github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 465 + github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 466 + github.com/gohugoio/hashstructure v0.6.0 h1:7wMB/2CfXoThFYhdWRGv3u3rUM761Cq29CxUW+NltUg= 467 + github.com/gohugoio/hashstructure v0.6.0/go.mod h1:lapVLk9XidheHG1IQ4ZSbyYrXcaILU1ZEP/+vno5rBQ= 468 + github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 469 + github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 470 + github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 471 + github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 472 + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 473 + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= 474 + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= 475 + github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 476 + github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 477 + github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 478 + github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 479 + github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 480 + github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 481 + github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 482 + github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= 483 + github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 484 + github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 485 + github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 486 + github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 487 + github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 488 + github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 489 + github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 490 + github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 491 + github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 492 + github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 493 + github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 494 + github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 495 + github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 496 + github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 497 + github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 498 + github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 499 + github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= 500 + github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 501 + github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= 502 + github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 503 + github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 504 + github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 505 + github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 506 + github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 507 + github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 508 + github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 509 + github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 510 + github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 511 + github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 512 + github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 513 + github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 514 + github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 515 + github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 516 + github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 517 + github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 518 + github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 519 + github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 520 + github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 521 + github.com/google/go-containerregistry v0.20.7 h1:24VGNpS0IwrOZ2ms2P1QE3Xa5X9p4phx0aUgzYzHW6I= 522 + github.com/google/go-containerregistry v0.20.7/go.mod h1:Lx5LCZQjLH1QBaMPeGwsME9biPeo1lPx6lbGj/UmzgM= 523 + github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 524 + github.com/google/licensecheck v0.3.1 h1:QoxgoDkaeC4nFrtGN1jV7IPmDCHFNIVh54e5hSt6sPs= 525 + github.com/google/licensecheck v0.3.1/go.mod h1:ORkR35t/JjW+emNKtfJDII0zlciG9JgbT7SmsohlHmY= 526 + github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= 527 + github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 528 + github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 529 + github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 530 + github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= 531 + github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= 532 + github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= 533 + github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 534 + github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 535 + github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 536 + github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 537 + github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 538 + github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 539 + github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 540 + github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 541 + github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 542 + github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 543 + github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 544 + github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 545 + github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 546 + github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 547 + github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= 548 + github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= 549 + github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5 h1:xhMrHhTJ6zxu3gA4enFM9MLn9AY7613teCdFnlUVbSQ= 550 + github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA= 551 + github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 552 + github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= 553 + github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= 554 + github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 555 + github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 556 + github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 557 + github.com/googleapis/enterprise-certificate-proxy v0.3.7 h1:zrn2Ee/nWmHulBx5sAVrGgAa0f2/R35S4DJwfFaUPFQ= 558 + github.com/googleapis/enterprise-certificate-proxy v0.3.7/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= 559 + github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 560 + github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 561 + github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= 562 + github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= 563 + github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= 564 + github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= 565 + github.com/gookit/assert v0.1.1 h1:lh3GcawXe/p+cU7ESTZ5Ui3Sm/x8JWpIis4/1aF0mY0= 566 + github.com/gookit/assert v0.1.1/go.mod h1:jS5bmIVQZTIwk42uXl4lyj4iaaxx32tqH16CFj0VX2E= 567 + github.com/gookit/color v1.2.5/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg= 568 + github.com/gookit/color v1.6.0 h1:JjJXBTk1ETNyqyilJhkTXJYYigHG24TM9Xa2M1xAhRA= 569 + github.com/gookit/color v1.6.0/go.mod h1:9ACFc7/1IpHGBW8RwuDm/0YEnhg3dwwXpoMsmtyHfjs= 570 + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= 571 + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= 572 + github.com/gpustack/gguf-parser-go v0.23.1 h1:0U7DOrsi7ryx2L/dlMy+BSQ5bJV4AuMEIgGBs4RK46A= 573 + github.com/gpustack/gguf-parser-go v0.23.1/go.mod h1:y4TwTtDqFWTK+xvprOjRUh+dowgU2TKCX37vRKvGiZ0= 574 + github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= 575 + github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= 576 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA= 577 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M= 578 + github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b h1:wDUNC2eKiL35DbLvsDhiblTUXHxcOPwQSCzi7xpQUN4= 579 + github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b/go.mod h1:VzxiSdG6j1pi7rwGm/xYI5RbtpBgM8sARDXlvEvxlu0= 580 + github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.70 h1:0HADrxxqaQkGycO1JoUUA+B4FnIkuo8d2bz/hSaTFFQ= 581 + github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.70/go.mod h1:fm2FdDCzJdtbXF7WKAMvBb5NEPouXPHFbGNYs9ShFns= 582 + github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= 583 + github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= 584 + github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 585 + github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= 586 + github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 587 + github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 588 + github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 589 + github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= 590 + github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= 591 + github.com/hashicorp/go-getter v1.8.4 h1:hGEd2xsuVKgwkMtPVufq73fAmZU/x65PPcqH3cb0D9A= 592 + github.com/hashicorp/go-getter v1.8.4/go.mod h1:x27pPGSg9kzoB147QXI8d/nDvp2IgYGcwuRjpaXE9Yg= 593 + github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= 594 + github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= 595 + github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= 596 + github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= 597 + github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= 598 + github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 599 + github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= 600 + github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= 601 + github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= 602 + github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= 603 + github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= 604 + github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= 605 + github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= 606 + github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 607 + github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 608 + github.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4= 609 + github.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 610 + github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 611 + github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 612 + github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= 613 + github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= 614 + github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= 615 + github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 616 + github.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQxvE= 617 + github.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM= 618 + github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= 619 + github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= 620 + github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= 621 + github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= 622 + github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= 623 + github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= 624 + github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= 625 + github.com/henvic/httpretty v0.1.4 h1:Jo7uwIRWVFxkqOnErcoYfH90o3ddQyVrSANeS4cxYmU= 626 + github.com/henvic/httpretty v0.1.4/go.mod h1:Dn60sQTZfbt2dYsdUSNsCljyF4AfdqnuJFDLJA1I4AM= 627 + github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= 628 + github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= 629 + github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= 630 + github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= 631 + github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= 632 + github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 633 + github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 634 + github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= 635 + github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= 636 + github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 637 + github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 638 + github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 639 + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= 640 + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= 641 + github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= 642 + github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= 643 + github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 644 + github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 645 + github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= 646 + github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 647 + github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= 648 + github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 649 + github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 650 + github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 651 + github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 652 + github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 653 + github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 654 + github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 655 + github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 656 + github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 h1:WdAeg/imY2JFPc/9CST4bZ80nNJbiBFCAdSZCSgrS5Y= 657 + github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953/go.mod h1:6o+UrvuZWc4UTyBhQf0LGjW9Ld7qJxLz/OqvSOWWlEc= 658 + github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= 659 + github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= 660 + github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 661 + github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 662 + github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 663 + github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= 664 + github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= 665 + github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 666 + github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= 667 + github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= 668 + github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f h1:GvCU5GXhHq+7LeOzx/haG7HSIZokl3/0GkoUFzsRJjg= 669 + github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f/go.mod h1:q59u9px8b7UTj0nIjEjvmTWekazka6xIt6Uogz5Dm+8= 670 + github.com/knqyf263/go-deb-version v0.0.0-20241115132648-6f4aee6ccd23 h1:dWzdsqjh1p2gNtRKqNwuBvKqMNwnLOPLzVZT1n6DK7s= 671 + github.com/knqyf263/go-deb-version v0.0.0-20241115132648-6f4aee6ccd23/go.mod h1:lUaIXCWzf7BRKTY5iEcrYy1TfgbYLYVIS/B2vPkJzOc= 672 + github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 673 + github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 674 + github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 675 + github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 676 + github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 677 + github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 678 + github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 679 + github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 680 + github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 681 + github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 682 + github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 683 + github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= 684 + github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= 685 + github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= 686 + github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= 687 + github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= 688 + github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= 689 + github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= 690 + github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= 691 + github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 692 + github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 693 + github.com/masahiro331/go-mvn-version v0.0.0-20250131095131-f4974fa13b8a h1:eLvAzVoRfHEOl64OxFhepPf3vj7SKvXY/tFc3BS0b7s= 694 + github.com/masahiro331/go-mvn-version v0.0.0-20250131095131-f4974fa13b8a/go.mod h1:jZ3F25l7DbD7l7DcA8aj7eo1EZ84nbzcQHBB4lCSrI8= 695 + github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 696 + github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 697 + github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 698 + github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 699 + github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 700 + github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= 701 + github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= 702 + github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 703 + github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 704 + github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= 705 + github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= 706 + github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 707 + github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 708 + github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 709 + github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 710 + github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75 h1:P8UmIzZMYDR+NGImiFvErt6VWfIRPuGM+vyjiEdkmIw= 711 + github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= 712 + github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= 713 + github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= 714 + github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 715 + github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= 716 + github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= 717 + github.com/mholt/archives v0.1.5 h1:Fh2hl1j7VEhc6DZs2DLMgiBNChUux154a1G+2esNvzQ= 718 + github.com/mholt/archives v0.1.5/go.mod h1:3TPMmBLPsgszL+1As5zECTuKwKvIfj6YcwWPpeTAXF4= 719 + github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= 720 + github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= 721 + github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= 722 + github.com/mikelolasagasti/xz v1.0.1 h1:Q2F2jX0RYJUG3+WsM+FJknv+6eVjsjXNDV0KJXZzkD0= 723 + github.com/mikelolasagasti/xz v1.0.1/go.mod h1:muAirjiOUxPRXwm9HdDtB3uoRPrGnL85XHtokL9Hcgc= 724 + github.com/minio/minlz v1.0.1 h1:OUZUzXcib8diiX+JYxyRLIdomyZYzHct6EShOKtQY2A= 725 + github.com/minio/minlz v1.0.1/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec= 726 + github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= 727 + github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= 728 + github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= 729 + github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 730 + github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 731 + github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 732 + github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= 733 + github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= 734 + github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 735 + github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 736 + github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 737 + github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= 738 + github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 739 + github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= 740 + github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= 741 + github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= 742 + github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= 743 + github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= 744 + github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= 745 + github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= 746 + github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= 747 + github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= 748 + github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= 749 + github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0= 750 + github.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8= 751 + github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= 752 + github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= 753 + github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= 754 + github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= 755 + github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= 756 + github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= 757 + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 758 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 759 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 760 + github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 761 + github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 762 + github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 763 + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= 764 + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 765 + github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= 766 + github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= 767 + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= 768 + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= 769 + github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= 770 + github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= 771 + github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= 772 + github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= 773 + github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 774 + github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= 775 + github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= 776 + github.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1 h1:kpt9ZfKcm+EDG4s40hMwE//d5SBgDjUOrITReV2u4aA= 777 + github.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1/go.mod h1:qgCw4bBKZX8qMgGeEZzGFVT3notl42dBjNqO2jut0M0= 778 + github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 h1:NHrXEjTNQY7P0Zfx1aMrNhpgxHmow66XQtm0aQLY0AE= 779 + github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8= 780 + github.com/nwaples/rardecode/v2 v2.2.0 h1:4ufPGHiNe1rYJxYfehALLjup4Ls3ck42CWwjKiOqu0A= 781 + github.com/nwaples/rardecode/v2 v2.2.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw= 782 + github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc= 783 + github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0= 784 + github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM= 785 + github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= 786 + github.com/olekukonko/ll v0.1.4-0.20260115111900-9e59c2286df0 h1:jrYnow5+hy3WRDCBypUFvVKNSPPCdqgSXIE9eJDD8LM= 787 + github.com/olekukonko/ll v0.1.4-0.20260115111900-9e59c2286df0/go.mod h1:b52bVQRRPObe+yyBl0TxNfhesL0nedD4Cht0/zx55Ew= 788 + github.com/olekukonko/tablewriter v1.1.3 h1:VSHhghXxrP0JHl+0NnKid7WoEmd9/urKRJLysb70nnA= 789 + github.com/olekukonko/tablewriter v1.1.3/go.mod h1:9VU0knjhmMkXjnMKrZ3+L2JhhtsQ/L38BbL3CRNE8tM= 790 + github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= 791 + github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= 792 + github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= 793 + github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= 794 + github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= 795 + github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= 796 + github.com/opencontainers/runtime-spec v1.3.0 h1:YZupQUdctfhpZy3TM39nN9Ika5CBWT5diQ8ibYCRkxg= 797 + github.com/opencontainers/runtime-spec v1.3.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= 798 + github.com/opencontainers/selinux v1.13.1 h1:A8nNeceYngH9Ow++M+VVEwJVpdFmrlxsN22F+ISDCJE= 799 + github.com/opencontainers/selinux v1.13.1/go.mod h1:S10WXZ/osk2kWOYKy1x2f/eXF5ZHJoUs8UU/2caNRbg= 800 + github.com/openvex/go-vex v0.2.7 h1:/pN3bqvS4QOc6WkkL0hbKzJuAtsUD9vmvk9IZkzD3Zc= 801 + github.com/openvex/go-vex v0.2.7/go.mod h1:ZyQC3NXl9jjS53JOpBG3LAUXySkW8IlJ/GIhsnf5D54= 802 + github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= 803 + github.com/package-url/packageurl-go v0.1.3 h1:4juMED3hHiz0set3Vq3KeQ75KD1avthoXLtmE3I0PLs= 804 + github.com/package-url/packageurl-go v0.1.3/go.mod h1:nKAWB8E6uk1MHqiS/lQb9pYBGH2+mdJ2PJc2s50dQY0= 805 + github.com/pandatix/go-cvss v0.6.2 h1:TFiHlzUkT67s6UkelHmK6s1INKVUG7nlKYiWWDTITGI= 806 + github.com/pandatix/go-cvss v0.6.2/go.mod h1:jDXYlQBZrc8nvrMUVVvTG8PhmuShOnKrxP53nOFkt8Q= 807 + github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 808 + github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 809 + github.com/pborman/indent v1.2.1 h1:lFiviAbISHv3Rf0jcuh489bi06hj98JsVMtIDZQb9yM= 810 + github.com/pborman/indent v1.2.1/go.mod h1:FitS+t35kIYtB5xWTZAPhnmrxcciEEOdbyrrpz5K6Vw= 811 + github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= 812 + github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= 813 + github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= 814 + github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= 815 + github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= 816 + github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= 817 + github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= 818 + github.com/pjbgf/sha1cd v0.4.0 h1:NXzbL1RvjTUi6kgYZCX3fPwwl27Q1LJndxtUDVfJGRY= 819 + github.com/pjbgf/sha1cd v0.4.0/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= 820 + github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 821 + github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 822 + github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 823 + github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 824 + github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= 825 + github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= 826 + github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= 827 + github.com/pkg/xattr v0.4.12 h1:rRTkSyFNTRElv6pkA3zpjHpQ90p/OdHQC1GmGh1aTjM= 828 + github.com/pkg/xattr v0.4.12/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU= 829 + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= 830 + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= 831 + github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 832 + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 833 + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 834 + github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 835 + github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= 836 + github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 837 + github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 838 + github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= 839 + github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 840 + github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 841 + github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 842 + github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 843 + github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 844 + github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= 845 + github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 846 + github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 847 + github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= 848 + github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= 849 + github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= 850 + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= 851 + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= 852 + github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 853 + github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 854 + github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 855 + github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 856 + github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= 857 + github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= 858 + github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 859 + github.com/rust-secure-code/go-rustaudit v0.0.0-20250226111315-e20ec32e963c h1:8gOLsYwaY2JwlTMT4brS5/9XJdrdIbmk2obvQ748CC0= 860 + github.com/rust-secure-code/go-rustaudit v0.0.0-20250226111315-e20ec32e963c/go.mod h1:kwM/7r/rVluTE8qJbHAffduuqmSv4knVQT2IajGvSiA= 861 + github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= 862 + github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= 863 + github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= 864 + github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= 865 + github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= 866 + github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA= 867 + github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= 868 + github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA= 869 + github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= 870 + github.com/sanity-io/litter v1.5.8 h1:uM/2lKrWdGbRXDrIq08Lh9XtVYoeGtcQxk9rtQ7+rYg= 871 + github.com/sanity-io/litter v1.5.8/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= 872 + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= 873 + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= 874 + github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg= 875 + github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI= 876 + github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e h1:7q6NSFZDeGfvvtIRwBrU/aegEYJYmvev0cHAwo17zZQ= 877 + github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e/go.mod h1:DkpGd78rljTxKAnTDPFqXSGxvETQnJyuSOQwsHycqfs= 878 + github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= 879 + github.com/sebdah/goldie/v2 v2.7.1 h1:PkBHymaYdtvEkZV7TmyqKxdmn5/Vcj+8TpATWZjnG5E= 880 + github.com/sebdah/goldie/v2 v2.7.1/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= 881 + github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= 882 + github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= 883 + github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= 884 + github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= 885 + github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 886 + github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= 887 + github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= 888 + github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 889 + github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 890 + github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 891 + github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0= 892 + github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 893 + github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= 894 + github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= 895 + github.com/smallnest/ringbuffer v0.0.0-20241116012123-461381446e3d h1:3VwvTjiRPA7cqtgOWddEL+JrcijMlXUmj99c/6YyZoY= 896 + github.com/smallnest/ringbuffer v0.0.0-20241116012123-461381446e3d/go.mod h1:tAG61zBM1DYRaGIPloumExGvScf08oHuo0kFoOqdbT0= 897 + github.com/sorairolake/lzip-go v0.3.8 h1:j5Q2313INdTA80ureWYRhX+1K78mUXfMoPZCw/ivWik= 898 + github.com/sorairolake/lzip-go v0.3.8/go.mod h1:JcBqGMV0frlxwrsE9sMWXDjqn3EeVf0/54YPsw66qkU= 899 + github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= 900 + github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= 901 + github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 902 + github.com/spdx/gordf v0.0.0-20250128162952-000978ccd6fb h1:7G2Czq97VORM5xNRrD8tSQdhoXPRs8s+Otlc7st9TS0= 903 + github.com/spdx/gordf v0.0.0-20250128162952-000978ccd6fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM= 904 + github.com/spdx/tools-golang v0.5.7 h1:+sWcKGnhwp3vLdMqPcLdA6QK679vd86cK9hQWH3AwCg= 905 + github.com/spdx/tools-golang v0.5.7/go.mod h1:jg7w0LOpoNAw6OxKEzCoqPC2GCTj45LyTlVmXubDsYw= 906 + github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= 907 + github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= 908 + github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= 909 + github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= 910 + github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 911 + github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE= 912 + github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= 913 + github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= 914 + github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= 915 + github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= 916 + github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 917 + github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 918 + github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= 919 + github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 920 + github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= 921 + github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= 922 + github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= 923 + github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= 924 + github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= 925 + github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 926 + github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 927 + github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 928 + github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 929 + github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= 930 + github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 931 + github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 932 + github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 933 + github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 934 + github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 935 + github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 936 + github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 937 + github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 938 + github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 939 + github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 940 + github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= 941 + github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 942 + github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= 943 + github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= 944 + github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= 945 + github.com/sylabs/sif/v2 v2.22.0 h1:Y+xXufp4RdgZe02SR3nWEg7S6q4tPWN237WHYzkDSKA= 946 + github.com/sylabs/sif/v2 v2.22.0/go.mod h1:W1XhWTmG1KcG7j5a3KSYdMcUIFvbs240w/MMVW627hs= 947 + github.com/sylabs/squashfs v1.0.6 h1:PvJcDzxr+vIm2kH56mEMbaOzvGu79gK7P7IX+R7BDZI= 948 + github.com/sylabs/squashfs v1.0.6/go.mod h1:DlDeUawVXLWAsSRa085Eo0ZenGzAB32JdAUFaB0LZfE= 949 + github.com/terminalstatic/go-xsd-validate v0.1.6 h1:TenYeQ3eY631qNi1/cTmLH/s2slHPRKTTHT+XSHkepo= 950 + github.com/terminalstatic/go-xsd-validate v0.1.6/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw= 951 + github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= 952 + github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY= 953 + github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= 954 + github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 955 + github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= 956 + github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 957 + github.com/vbatts/go-mtree v0.7.0 h1:ytmOc3MTRidZiBi9VBCyZ2BHe4fZS47L5v7BVXDWW4E= 958 + github.com/vbatts/go-mtree v0.7.0/go.mod h1:EjdpFC+LZy1TXbRGNa1MKKgjQ+7ew3foMFJK8o4/TdY= 959 + github.com/vbatts/tar-split v0.12.2 h1:w/Y6tjxpeiFMR47yzZPlPj/FcPLpXbTUi/9H7d3CPa4= 960 + github.com/vbatts/tar-split v0.12.2/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA= 961 + github.com/vifraa/gopom v1.0.0 h1:L9XlKbyvid8PAIK8nr0lihMApJQg/12OBvMA28BcWh0= 962 + github.com/vifraa/gopom v1.0.0/go.mod h1:oPa1dcrGrtlO37WPDBm5SqHAT+wTgF8An1Q71Z6Vv4o= 963 + github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 h1:jIVmlAFIqV3d+DOxazTR9v+zgj8+VYuQBzPgBZvWBHA= 964 + github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651/go.mod h1:b26F2tHLqaoRQf8DywqzVaV1MQ9yvjb0OMcNl7Nxu20= 965 + github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0 h1:0KGbf+0SMg+UFy4e1A/CPVvXn21f1qtWdeJwxZFoQG8= 966 + github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0/go.mod h1:jLXFoL31zFaHKAAyZUh+sxiTDFe1L1ZHrcK2T1itVKA= 967 + github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= 968 + github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= 969 + github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= 970 + github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= 971 + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= 972 + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= 973 + github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= 974 + github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= 975 + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= 976 + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= 977 + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= 978 + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= 979 + github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= 980 + github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= 981 + github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 982 + github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 983 + github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 984 + github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 985 + github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 986 + github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 987 + github.com/zclconf/go-cty v1.16.3 h1:osr++gw2T61A8KVYHoQiFbFd1Lh3JOCXc/jFLJXKTxk= 988 + github.com/zclconf/go-cty v1.16.3/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= 989 + github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= 990 + github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= 991 + go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo= 992 + go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E= 993 + go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= 994 + go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= 995 + go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= 996 + go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 997 + go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 998 + go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 999 + go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 1000 + go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 1001 + go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= 1002 + go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= 1003 + go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= 1004 + go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= 1005 + go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= 1006 + go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= 1007 + go.opentelemetry.io/contrib/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY6LiIY9I8cUfm+pJs= 1008 + go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts= 1009 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= 1010 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= 1011 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= 1012 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= 1013 + go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= 1014 + go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= 1015 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw= 1016 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4= 1017 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg= 1018 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk= 1019 + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= 1020 + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= 1021 + go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= 1022 + go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= 1023 + go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= 1024 + go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= 1025 + go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= 1026 + go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= 1027 + go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= 1028 + go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= 1029 + go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= 1030 + go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os= 1031 + go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= 1032 + go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 1033 + go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= 1034 + go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= 1035 + go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 1036 + go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= 1037 + go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 1038 + go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= 1039 + go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= 1040 + go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= 1041 + go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc= 1042 + go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU= 1043 + golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 1044 + golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 1045 + golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 1046 + golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 1047 + golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 1048 + golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 1049 + golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= 1050 + golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 1051 + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 1052 + golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 1053 + golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 1054 + golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 1055 + golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= 1056 + golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= 1057 + golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 1058 + golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 1059 + golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 1060 + golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 1061 + golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 1062 + golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 1063 + golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 1064 + golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 1065 + golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 1066 + golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 1067 + golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= 1068 + golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= 1069 + golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 1070 + golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 1071 + golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 1072 + golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 1073 + golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 1074 + golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 1075 + golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 1076 + golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 1077 + golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 1078 + golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 1079 + golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 1080 + golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 1081 + golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 1082 + golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 1083 + golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 1084 + golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 1085 + golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 1086 + golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 1087 + golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 1088 + golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 1089 + golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 1090 + golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 1091 + golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 1092 + golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 1093 + golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 1094 + golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= 1095 + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 1096 + golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= 1097 + golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= 1098 + golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 1099 + golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 1100 + golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 1101 + golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 1102 + golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 1103 + golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 1104 + golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 1105 + golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 1106 + golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 1107 + golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 1108 + golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 1109 + golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 1110 + golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 1111 + golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 1112 + golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 1113 + golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 1114 + golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 1115 + golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 1116 + golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 1117 + golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 1118 + golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 1119 + golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 1120 + golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 1121 + golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 1122 + golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 1123 + golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 1124 + golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 1125 + golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 1126 + golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 1127 + golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 1128 + golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 1129 + golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 1130 + golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 1131 + golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 1132 + golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 1133 + golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 1134 + golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= 1135 + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 1136 + golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= 1137 + golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 1138 + golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 1139 + golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 1140 + golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 1141 + golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 1142 + golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= 1143 + golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= 1144 + golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 1145 + golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 1146 + golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 1147 + golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 1148 + golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 1149 + golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 1150 + golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 1151 + golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 1152 + golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 1153 + golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 1154 + golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 1155 + golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 1156 + golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 1157 + golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 1158 + golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 1159 + golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 1160 + golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 1161 + golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= 1162 + golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= 1163 + golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 1164 + golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 1165 + golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 1166 + golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 1167 + golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 1168 + golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 1169 + golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 1170 + golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 1171 + golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 1172 + golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 1173 + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 1174 + golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 1175 + golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= 1176 + golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 1177 + golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 1178 + golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 1179 + golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 1180 + golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 1181 + golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 1182 + golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 1183 + golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 1184 + golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1185 + golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1186 + golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1187 + golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1188 + golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1189 + golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1190 + golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1191 + golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1192 + golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1193 + golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1194 + golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1195 + golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1196 + golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1197 + golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1198 + golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1199 + golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1200 + golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1201 + golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1202 + golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1203 + golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1204 + golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1205 + golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1206 + golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1207 + golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1208 + golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1209 + golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1210 + golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1211 + golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1212 + golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1213 + golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1214 + golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1215 + golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1216 + golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1217 + golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1218 + golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1219 + golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1220 + golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1221 + golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1222 + golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1223 + golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1224 + golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1225 + golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1226 + golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1227 + golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1228 + golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 1229 + golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1230 + golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1231 + golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1232 + golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1233 + golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1234 + golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1235 + golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1236 + golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1237 + golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1238 + golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1239 + golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1240 + golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1241 + golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1242 + golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1243 + golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1244 + golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1245 + golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1246 + golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1247 + golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1248 + golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1249 + golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 1250 + golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= 1251 + golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 1252 + golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 1253 + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 1254 + golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 1255 + golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= 1256 + golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= 1257 + golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 1258 + golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 1259 + golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 1260 + golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 1261 + golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 1262 + golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 1263 + golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 1264 + golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 1265 + golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 1266 + golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 1267 + golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= 1268 + golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= 1269 + golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 1270 + golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 1271 + golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 1272 + golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= 1273 + golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= 1274 + golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 1275 + golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 1276 + golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 1277 + golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 1278 + golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 1279 + golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 1280 + golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 1281 + golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 1282 + golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 1283 + golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 1284 + golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 1285 + golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 1286 + golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 1287 + golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 1288 + golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 1289 + golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 1290 + golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 1291 + golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 1292 + golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 1293 + golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 1294 + golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 1295 + golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 1296 + golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 1297 + golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 1298 + golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 1299 + golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 1300 + golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 1301 + golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 1302 + golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 1303 + golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 1304 + golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 1305 + golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 1306 + golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 1307 + golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 1308 + golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 1309 + golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 1310 + golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 1311 + golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 1312 + golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 1313 + golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 1314 + golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 1315 + golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 1316 + golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= 1317 + golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 1318 + golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 1319 + golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 1320 + golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 1321 + golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 1322 + golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 1323 + golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 1324 + golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 1325 + golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 1326 + golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 1327 + golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 1328 + golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 1329 + golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= 1330 + golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= 1331 + golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 1332 + golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 1333 + golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 1334 + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 1335 + golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= 1336 + golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= 1337 + gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= 1338 + gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= 1339 + google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 1340 + google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 1341 + google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 1342 + google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 1343 + google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 1344 + google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 1345 + google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 1346 + google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 1347 + google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 1348 + google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 1349 + google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 1350 + google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 1351 + google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 1352 + google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 1353 + google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 1354 + google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 1355 + google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= 1356 + google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= 1357 + google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= 1358 + google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= 1359 + google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= 1360 + google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= 1361 + google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= 1362 + google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= 1363 + google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= 1364 + google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= 1365 + google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= 1366 + google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= 1367 + google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= 1368 + google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= 1369 + google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= 1370 + google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= 1371 + google.golang.org/api v0.256.0 h1:u6Khm8+F9sxbCTYNoBHg6/Hwv0N/i+V94MvkOSor6oI= 1372 + google.golang.org/api v0.256.0/go.mod h1:KIgPhksXADEKJlnEoRa9qAII4rXcy40vfI8HRqcU964= 1373 + google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 1374 + google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 1375 + google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 1376 + google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 1377 + google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 1378 + google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 1379 + google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 1380 + google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 1381 + google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 1382 + google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 1383 + google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 1384 + google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 1385 + google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 1386 + google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 1387 + google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 1388 + google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 1389 + google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 1390 + google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 1391 + google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 1392 + google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 1393 + google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 1394 + google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 1395 + google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 1396 + google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 1397 + google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 1398 + google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 1399 + google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 1400 + google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 1401 + google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 1402 + google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 1403 + google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 1404 + google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 1405 + google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 1406 + google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 1407 + google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 1408 + google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 1409 + google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 1410 + google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 1411 + google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 1412 + google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 1413 + google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 1414 + google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 1415 + google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 1416 + google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 1417 + google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 1418 + google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 1419 + google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= 1420 + google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= 1421 + google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= 1422 + google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= 1423 + google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= 1424 + google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= 1425 + google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= 1426 + google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= 1427 + google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= 1428 + google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= 1429 + google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= 1430 + google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 1431 + google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 1432 + google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 1433 + google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 1434 + google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 1435 + google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 1436 + google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 1437 + google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 1438 + google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 1439 + google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 1440 + google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 1441 + google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 1442 + google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 1443 + google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9 h1:LvZVVaPE0JSqL+ZWb6ErZfnEOKIqqFWUJE2D0fObSmc= 1444 + google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9/go.mod h1:QFOrLhdAe2PsTp3vQY4quuLKTi9j3XG3r6JPPaw7MSc= 1445 + google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= 1446 + google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= 1447 + google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= 1448 + google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= 1449 + google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 1450 + google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 1451 + google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 1452 + google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 1453 + google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 1454 + google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 1455 + google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 1456 + google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 1457 + google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 1458 + google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 1459 + google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 1460 + google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 1461 + google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 1462 + google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= 1463 + google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 1464 + google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= 1465 + google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 1466 + google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 1467 + google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 1468 + google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 1469 + google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 1470 + google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 1471 + google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= 1472 + google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= 1473 + google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= 1474 + google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= 1475 + google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= 1476 + google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= 1477 + google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= 1478 + google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 1479 + google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 1480 + google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 1481 + google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 1482 + google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 1483 + google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 1484 + google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 1485 + google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 1486 + google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 1487 + google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 1488 + google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 1489 + google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 1490 + google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 1491 + google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 1492 + google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= 1493 + google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= 1494 + gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 1495 + gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 1496 + gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 1497 + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 1498 + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 1499 + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 1500 + gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 1501 + gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 1502 + gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= 1503 + gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 1504 + gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 1505 + gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 1506 + gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 1507 + gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 1508 + gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 1509 + gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 1510 + gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 1511 + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 1512 + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 1513 + gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 1514 + gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 1515 + gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg= 1516 + gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= 1517 + gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= 1518 + gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= 1519 + honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 1520 + honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 1521 + honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 1522 + honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 1523 + honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 1524 + honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 1525 + honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 1526 + modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis= 1527 + modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= 1528 + modernc.org/ccgo/v4 v4.30.1 h1:4r4U1J6Fhj98NKfSjnPUN7Ze2c6MnAdL0hWw6+LrJpc= 1529 + modernc.org/ccgo/v4 v4.30.1/go.mod h1:bIOeI1JL54Utlxn+LwrFyjCx2n2RDiYEaJVSrgdrRfM= 1530 + modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA= 1531 + modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= 1532 + modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= 1533 + modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= 1534 + modernc.org/gc/v3 v3.1.1 h1:k8T3gkXWY9sEiytKhcgyiZ2L0DTyCQ/nvX+LoCljoRE= 1535 + modernc.org/gc/v3 v3.1.1/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= 1536 + modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= 1537 + modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= 1538 + modernc.org/libc v1.67.6 h1:eVOQvpModVLKOdT+LvBPjdQqfrZq+pC39BygcT+E7OI= 1539 + modernc.org/libc v1.67.6/go.mod h1:JAhxUVlolfYDErnwiqaLvUqc8nfb2r6S6slAgZOnaiE= 1540 + modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= 1541 + modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= 1542 + modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= 1543 + modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= 1544 + modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= 1545 + modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= 1546 + modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= 1547 + modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= 1548 + modernc.org/sqlite v1.44.3 h1:+39JvV/HWMcYslAwRxHb8067w+2zowvFOUrOWIy9PjY= 1549 + modernc.org/sqlite v1.44.3/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA= 1550 + modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= 1551 + modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= 1552 + modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= 1553 + modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= 1554 + rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 1555 + rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 1556 + rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+267
scanner/internal/client/hold.go
··· 1 + // Package client implements the bidirectional WebSocket client for communicating 2 + // with the hold service, plus HTTP helpers for downloading blobs. 3 + package client 4 + 5 + import ( 6 + "encoding/json" 7 + "fmt" 8 + "io" 9 + "log/slog" 10 + "net/http" 11 + "net/url" 12 + "os" 13 + "sync" 14 + "time" 15 + 16 + scanner "atcr.io/scanner" 17 + "atcr.io/scanner/internal/queue" 18 + "github.com/gorilla/websocket" 19 + ) 20 + 21 + // HoldClient manages the WebSocket connection to a hold service 22 + type HoldClient struct { 23 + holdURL string 24 + secret string 25 + queue *queue.JobQueue 26 + conn *websocket.Conn 27 + mu sync.Mutex // protects conn writes 28 + done chan struct{} 29 + } 30 + 31 + // NewHoldClient creates a new hold client 32 + func NewHoldClient(holdURL, secret string, q *queue.JobQueue) *HoldClient { 33 + return &HoldClient{ 34 + holdURL: holdURL, 35 + secret: secret, 36 + queue: q, 37 + done: make(chan struct{}), 38 + } 39 + } 40 + 41 + // Connect establishes the WebSocket connection with auto-reconnect 42 + func (c *HoldClient) Connect() { 43 + var cursor int64 = -1 44 + 45 + for { 46 + select { 47 + case <-c.done: 48 + return 49 + default: 50 + } 51 + 52 + err := c.connectOnce(cursor) 53 + if err != nil { 54 + slog.Error("WebSocket connection failed, reconnecting", 55 + "error", err) 56 + } 57 + 58 + // Exponential backoff with max 30s 59 + select { 60 + case <-c.done: 61 + return 62 + case <-time.After(5 * time.Second): 63 + } 64 + } 65 + } 66 + 67 + func (c *HoldClient) connectOnce(cursor int64) error { 68 + // Build WebSocket URL 69 + u, err := url.Parse(c.holdURL) 70 + if err != nil { 71 + return fmt.Errorf("invalid hold URL: %w", err) 72 + } 73 + 74 + // Convert http(s) to ws(s) 75 + switch u.Scheme { 76 + case "http": 77 + u.Scheme = "ws" 78 + case "https": 79 + u.Scheme = "wss" 80 + case "ws", "wss": 81 + // Already correct 82 + } 83 + 84 + u.Path = "/xrpc/io.atcr.hold.subscribeScanJobs" 85 + q := u.Query() 86 + q.Set("secret", c.secret) 87 + if cursor >= 0 { 88 + q.Set("cursor", fmt.Sprintf("%d", cursor)) 89 + } 90 + u.RawQuery = q.Encode() 91 + 92 + slog.Info("Connecting to hold service", "url", u.Host) 93 + 94 + conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil) 95 + if err != nil { 96 + return fmt.Errorf("dial failed: %w", err) 97 + } 98 + 99 + c.mu.Lock() 100 + c.conn = conn 101 + c.mu.Unlock() 102 + 103 + slog.Info("Connected to hold service") 104 + 105 + // Read messages from hold 106 + for { 107 + _, data, err := conn.ReadMessage() 108 + if err != nil { 109 + if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseNormalClosure) { 110 + slog.Error("WebSocket read error", "error", err) 111 + } 112 + return err 113 + } 114 + 115 + var raw scanner.ScanJobRaw 116 + if err := json.Unmarshal(data, &raw); err != nil { 117 + slog.Error("Failed to unmarshal message", "error", err) 118 + continue 119 + } 120 + 121 + if raw.Type != "job" { 122 + slog.Warn("Unknown message type from hold", "type", raw.Type) 123 + continue 124 + } 125 + 126 + // Parse config and layers from raw JSON 127 + var config scanner.BlobDescriptor 128 + if err := json.Unmarshal(raw.Config, &config); err != nil { 129 + slog.Error("Failed to unmarshal config", "seq", raw.Seq, "error", err) 130 + continue 131 + } 132 + 133 + var layers []scanner.BlobDescriptor 134 + if err := json.Unmarshal(raw.Layers, &layers); err != nil { 135 + slog.Error("Failed to unmarshal layers", "seq", raw.Seq, "error", err) 136 + continue 137 + } 138 + 139 + job := &scanner.ScanJob{ 140 + Seq: raw.Seq, 141 + ManifestDigest: raw.ManifestDigest, 142 + Repository: raw.Repository, 143 + Tag: raw.Tag, 144 + UserDID: raw.UserDID, 145 + UserHandle: raw.UserHandle, 146 + HoldDID: raw.HoldDID, 147 + HoldEndpoint: raw.HoldEndpoint, 148 + Tier: raw.Tier, 149 + Config: config, 150 + Layers: layers, 151 + } 152 + 153 + // Send ack immediately 154 + c.SendAck(job.Seq) 155 + 156 + // Enqueue into priority queue 157 + if !c.queue.Enqueue(job) { 158 + slog.Warn("Queue full, sending error", 159 + "seq", job.Seq, 160 + "repository", job.Repository) 161 + c.SendError(job.Seq, "scanner queue full") 162 + } 163 + } 164 + } 165 + 166 + // SendAck sends an acknowledgement for a received job 167 + func (c *HoldClient) SendAck(seq int64) { 168 + c.sendJSON(scanner.AckMessage{Type: "ack", Seq: seq}) 169 + } 170 + 171 + // SendResult sends scan results back to the hold 172 + func (c *HoldClient) SendResult(seq int64, result *scanner.ScanResult) { 173 + msg := scanner.ResultMessage{ 174 + Type: "result", 175 + Seq: seq, 176 + Summary: result.Summary, 177 + } 178 + if result.SBOM != nil { 179 + msg.SBOM = string(result.SBOM) 180 + } 181 + if result.VulnReport != nil { 182 + msg.VulnReport = string(result.VulnReport) 183 + } 184 + c.sendJSON(msg) 185 + } 186 + 187 + // SendError sends an error message for a failed scan 188 + func (c *HoldClient) SendError(seq int64, errMsg string) { 189 + c.sendJSON(scanner.ErrorMessage{Type: "error", Seq: seq, Error: errMsg}) 190 + } 191 + 192 + func (c *HoldClient) sendJSON(v any) { 193 + c.mu.Lock() 194 + defer c.mu.Unlock() 195 + 196 + if c.conn == nil { 197 + slog.Warn("Cannot send, no connection") 198 + return 199 + } 200 + 201 + if err := c.conn.WriteJSON(v); err != nil { 202 + slog.Error("Failed to send WebSocket message", "error", err) 203 + } 204 + } 205 + 206 + // Close shuts down the client 207 + func (c *HoldClient) Close() { 208 + close(c.done) 209 + c.mu.Lock() 210 + if c.conn != nil { 211 + c.conn.Close() 212 + } 213 + c.mu.Unlock() 214 + } 215 + 216 + // GetBlobPresignedURL gets a presigned download URL from the hold service 217 + func GetBlobPresignedURL(holdEndpoint, holdDID, digest string) (string, error) { 218 + reqURL := fmt.Sprintf("%s/xrpc/com.atproto.sync.getBlob?did=%s&cid=%s&method=GET", 219 + holdEndpoint, 220 + url.QueryEscape(holdDID), 221 + url.QueryEscape(digest)) 222 + 223 + resp, err := http.Get(reqURL) 224 + if err != nil { 225 + return "", fmt.Errorf("failed to get presigned URL: %w", err) 226 + } 227 + defer resp.Body.Close() 228 + 229 + if resp.StatusCode != http.StatusOK { 230 + body, _ := io.ReadAll(resp.Body) 231 + return "", fmt.Errorf("hold returned status %d: %s", resp.StatusCode, string(body)) 232 + } 233 + 234 + var result struct { 235 + URL string `json:"url"` 236 + } 237 + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { 238 + return "", fmt.Errorf("failed to decode response: %w", err) 239 + } 240 + 241 + return result.URL, nil 242 + } 243 + 244 + // DownloadBlob downloads a blob from a presigned URL to a local file 245 + func DownloadBlob(presignedURL, destPath string) error { 246 + resp, err := http.Get(presignedURL) 247 + if err != nil { 248 + return fmt.Errorf("failed to download blob: %w", err) 249 + } 250 + defer resp.Body.Close() 251 + 252 + if resp.StatusCode != http.StatusOK { 253 + return fmt.Errorf("download returned status %d", resp.StatusCode) 254 + } 255 + 256 + out, err := os.Create(destPath) 257 + if err != nil { 258 + return fmt.Errorf("failed to create file: %w", err) 259 + } 260 + defer out.Close() 261 + 262 + if _, err := io.Copy(out, resp.Body); err != nil { 263 + return fmt.Errorf("failed to write blob: %w", err) 264 + } 265 + 266 + return nil 267 + }
+83
scanner/internal/config/config.go
··· 1 + // Package config provides environment-based configuration for the scanner service. 2 + package config 3 + 4 + import ( 5 + "fmt" 6 + "os" 7 + "strconv" 8 + ) 9 + 10 + // Config holds all scanner configuration 11 + type Config struct { 12 + // Addr is the HTTP address for the health endpoint 13 + Addr string 14 + 15 + // HoldURL is the WebSocket URL of the hold service 16 + HoldURL string 17 + 18 + // SharedSecret is the shared secret for scanner authentication 19 + SharedSecret string 20 + 21 + // Workers is the number of concurrent scan workers 22 + Workers int 23 + 24 + // QueueSize is the maximum priority queue depth 25 + QueueSize int 26 + 27 + // VulnEnabled enables Grype vulnerability scanning 28 + VulnEnabled bool 29 + 30 + // VulnDBPath is the directory for the Grype vulnerability database 31 + VulnDBPath string 32 + 33 + // TmpDir is the directory for temporary layer extraction 34 + TmpDir string 35 + } 36 + 37 + // Load reads configuration from environment variables with SCANNER_ prefix 38 + func Load() (*Config, error) { 39 + cfg := &Config{ 40 + Addr: envOr("SCANNER_ADDR", ":9090"), 41 + HoldURL: os.Getenv("SCANNER_HOLD_URL"), 42 + SharedSecret: os.Getenv("SCANNER_SHARED_SECRET"), 43 + Workers: envIntOr("SCANNER_WORKERS", 2), 44 + QueueSize: envIntOr("SCANNER_QUEUE_SIZE", 100), 45 + VulnEnabled: envBoolOr("SCANNER_VULN_ENABLED", true), 46 + VulnDBPath: envOr("SCANNER_VULN_DB_PATH", "/var/lib/atcr-scanner/vulndb"), 47 + TmpDir: envOr("SCANNER_TMP_DIR", "/var/lib/atcr-scanner/tmp"), 48 + } 49 + 50 + if cfg.HoldURL == "" { 51 + return nil, fmt.Errorf("SCANNER_HOLD_URL is required") 52 + } 53 + if cfg.SharedSecret == "" { 54 + return nil, fmt.Errorf("SCANNER_SHARED_SECRET is required") 55 + } 56 + 57 + return cfg, nil 58 + } 59 + 60 + func envOr(key, fallback string) string { 61 + if v := os.Getenv(key); v != "" { 62 + return v 63 + } 64 + return fallback 65 + } 66 + 67 + func envIntOr(key string, fallback int) int { 68 + if v := os.Getenv(key); v != "" { 69 + if n, err := strconv.Atoi(v); err == nil { 70 + return n 71 + } 72 + } 73 + return fallback 74 + } 75 + 76 + func envBoolOr(key string, fallback bool) bool { 77 + if v := os.Getenv(key); v != "" { 78 + if b, err := strconv.ParseBool(v); err == nil { 79 + return b 80 + } 81 + } 82 + return fallback 83 + }
+144
scanner/internal/queue/priority_queue.go
··· 1 + // Package queue provides a priority queue for scan jobs. 2 + // Jobs are ordered by tier priority (paid first) with FIFO tiebreaker. 3 + package queue 4 + 5 + import ( 6 + "container/heap" 7 + "sync" 8 + 9 + scanner "atcr.io/scanner" 10 + ) 11 + 12 + // Priority levels: lower number = higher priority 13 + const ( 14 + PriorityOwner = 0 15 + PriorityQuartermaster = 1 16 + PriorityBosun = 2 17 + PriorityDeckhand = 3 18 + ) 19 + 20 + // TierToPriority converts a tier name to a priority level 21 + func TierToPriority(tier string) int { 22 + switch tier { 23 + case "owner": 24 + return PriorityOwner 25 + case "quartermaster": 26 + return PriorityQuartermaster 27 + case "bosun": 28 + return PriorityBosun 29 + default: 30 + return PriorityDeckhand 31 + } 32 + } 33 + 34 + // item wraps a ScanJob with priority metadata for the heap 35 + type item struct { 36 + job *scanner.ScanJob 37 + priority int 38 + seq int64 // FIFO tiebreaker 39 + } 40 + 41 + // priorityHeap implements heap.Interface 42 + type priorityHeap []*item 43 + 44 + func (h priorityHeap) Len() int { return len(h) } 45 + 46 + func (h priorityHeap) Less(i, j int) bool { 47 + if h[i].priority != h[j].priority { 48 + return h[i].priority < h[j].priority 49 + } 50 + return h[i].seq < h[j].seq 51 + } 52 + 53 + func (h priorityHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } 54 + 55 + func (h *priorityHeap) Push(x any) { 56 + *h = append(*h, x.(*item)) 57 + } 58 + 59 + func (h *priorityHeap) Pop() any { 60 + old := *h 61 + n := len(old) 62 + it := old[n-1] 63 + old[n-1] = nil 64 + *h = old[:n-1] 65 + return it 66 + } 67 + 68 + // JobQueue is a thread-safe priority queue for scan jobs. 69 + // Workers block on Dequeue until a job is available. 70 + type JobQueue struct { 71 + mu sync.Mutex 72 + cond *sync.Cond 73 + h priorityHeap 74 + maxSize int 75 + closed bool 76 + } 77 + 78 + // NewJobQueue creates a new priority queue with the given max size 79 + func NewJobQueue(maxSize int) *JobQueue { 80 + q := &JobQueue{ 81 + h: make(priorityHeap, 0), 82 + maxSize: maxSize, 83 + } 84 + q.cond = sync.NewCond(&q.mu) 85 + heap.Init(&q.h) 86 + return q 87 + } 88 + 89 + // Enqueue adds a job to the priority queue. 90 + // Returns false if the queue is full. 91 + func (q *JobQueue) Enqueue(job *scanner.ScanJob) bool { 92 + q.mu.Lock() 93 + defer q.mu.Unlock() 94 + 95 + if q.closed { 96 + return false 97 + } 98 + 99 + if q.h.Len() >= q.maxSize { 100 + return false 101 + } 102 + 103 + heap.Push(&q.h, &item{ 104 + job: job, 105 + priority: TierToPriority(job.Tier), 106 + seq: job.Seq, 107 + }) 108 + 109 + q.cond.Signal() 110 + return true 111 + } 112 + 113 + // Dequeue blocks until a job is available and returns it. 114 + // Returns nil if the queue is closed. 115 + func (q *JobQueue) Dequeue() *scanner.ScanJob { 116 + q.mu.Lock() 117 + defer q.mu.Unlock() 118 + 119 + for q.h.Len() == 0 && !q.closed { 120 + q.cond.Wait() 121 + } 122 + 123 + if q.closed && q.h.Len() == 0 { 124 + return nil 125 + } 126 + 127 + it := heap.Pop(&q.h).(*item) 128 + return it.job 129 + } 130 + 131 + // Len returns the number of jobs in the queue 132 + func (q *JobQueue) Len() int { 133 + q.mu.Lock() 134 + defer q.mu.Unlock() 135 + return q.h.Len() 136 + } 137 + 138 + // Close signals all waiting goroutines to stop 139 + func (q *JobQueue) Close() { 140 + q.mu.Lock() 141 + defer q.mu.Unlock() 142 + q.closed = true 143 + q.cond.Broadcast() 144 + }
+94
scanner/internal/queue/priority_queue_test.go
··· 1 + package queue 2 + 3 + import ( 4 + "testing" 5 + 6 + scanner "atcr.io/scanner" 7 + ) 8 + 9 + func TestTierToPriority(t *testing.T) { 10 + tests := []struct { 11 + tier string 12 + expected int 13 + }{ 14 + {"owner", PriorityOwner}, 15 + {"quartermaster", PriorityQuartermaster}, 16 + {"bosun", PriorityBosun}, 17 + {"deckhand", PriorityDeckhand}, 18 + {"unknown", PriorityDeckhand}, 19 + {"", PriorityDeckhand}, 20 + } 21 + 22 + for _, tt := range tests { 23 + if got := TierToPriority(tt.tier); got != tt.expected { 24 + t.Errorf("TierToPriority(%q) = %d, want %d", tt.tier, got, tt.expected) 25 + } 26 + } 27 + } 28 + 29 + func TestJobQueue_PriorityOrder(t *testing.T) { 30 + q := NewJobQueue(10) 31 + 32 + // Enqueue jobs in reverse priority order 33 + q.Enqueue(&scanner.ScanJob{Seq: 1, Tier: "deckhand", Repository: "free-1"}) 34 + q.Enqueue(&scanner.ScanJob{Seq: 2, Tier: "owner", Repository: "owner-1"}) 35 + q.Enqueue(&scanner.ScanJob{Seq: 3, Tier: "bosun", Repository: "bosun-1"}) 36 + q.Enqueue(&scanner.ScanJob{Seq: 4, Tier: "quartermaster", Repository: "qm-1"}) 37 + 38 + // Should dequeue in priority order: owner, quartermaster, bosun, deckhand 39 + expected := []string{"owner-1", "qm-1", "bosun-1", "free-1"} 40 + for _, exp := range expected { 41 + job := q.Dequeue() 42 + if job.Repository != exp { 43 + t.Errorf("expected %q, got %q", exp, job.Repository) 44 + } 45 + } 46 + } 47 + 48 + func TestJobQueue_FIFOWithinSamePriority(t *testing.T) { 49 + q := NewJobQueue(10) 50 + 51 + q.Enqueue(&scanner.ScanJob{Seq: 10, Tier: "deckhand", Repository: "first"}) 52 + q.Enqueue(&scanner.ScanJob{Seq: 20, Tier: "deckhand", Repository: "second"}) 53 + q.Enqueue(&scanner.ScanJob{Seq: 30, Tier: "deckhand", Repository: "third"}) 54 + 55 + // Should dequeue in FIFO order within same priority 56 + expected := []string{"first", "second", "third"} 57 + for _, exp := range expected { 58 + job := q.Dequeue() 59 + if job.Repository != exp { 60 + t.Errorf("expected %q, got %q", exp, job.Repository) 61 + } 62 + } 63 + } 64 + 65 + func TestJobQueue_Full(t *testing.T) { 66 + q := NewJobQueue(2) 67 + 68 + ok1 := q.Enqueue(&scanner.ScanJob{Seq: 1, Tier: "deckhand"}) 69 + ok2 := q.Enqueue(&scanner.ScanJob{Seq: 2, Tier: "deckhand"}) 70 + ok3 := q.Enqueue(&scanner.ScanJob{Seq: 3, Tier: "deckhand"}) 71 + 72 + if !ok1 || !ok2 { 73 + t.Error("first two enqueues should succeed") 74 + } 75 + if ok3 { 76 + t.Error("third enqueue should fail (queue full)") 77 + } 78 + } 79 + 80 + func TestJobQueue_CloseUnblocks(t *testing.T) { 81 + q := NewJobQueue(10) 82 + 83 + done := make(chan struct{}) 84 + go func() { 85 + job := q.Dequeue() 86 + if job != nil { 87 + t.Error("expected nil from closed queue") 88 + } 89 + close(done) 90 + }() 91 + 92 + q.Close() 93 + <-done 94 + }
+180
scanner/internal/scan/extractor.go
··· 1 + package scan 2 + 3 + import ( 4 + "archive/tar" 5 + "compress/gzip" 6 + "encoding/json" 7 + "fmt" 8 + "io" 9 + "log/slog" 10 + "os" 11 + "path/filepath" 12 + "strings" 13 + 14 + scanner "atcr.io/scanner" 15 + "atcr.io/scanner/internal/client" 16 + ) 17 + 18 + // extractLayers downloads and extracts all image layers via presigned URLs 19 + // Returns the rootfs directory path and a cleanup function 20 + func extractLayers(job *scanner.ScanJob, tmpDir string) (string, func(), error) { 21 + scanDir, err := os.MkdirTemp(tmpDir, "scan-*") 22 + if err != nil { 23 + return "", nil, fmt.Errorf("failed to create temp directory: %w", err) 24 + } 25 + 26 + cleanup := func() { 27 + if err := os.RemoveAll(scanDir); err != nil { 28 + slog.Warn("Failed to clean up temp directory", "dir", scanDir, "error", err) 29 + } 30 + } 31 + 32 + imageDir := filepath.Join(scanDir, "image") 33 + rootfsDir := filepath.Join(imageDir, "rootfs") 34 + layersDir := filepath.Join(imageDir, "layers") 35 + 36 + for _, dir := range []string{rootfsDir, layersDir} { 37 + if err := os.MkdirAll(dir, 0755); err != nil { 38 + cleanup() 39 + return "", nil, fmt.Errorf("failed to create directory %s: %w", dir, err) 40 + } 41 + } 42 + 43 + // Download and validate config blob 44 + slog.Info("Downloading config blob", "digest", job.Config.Digest) 45 + configPath := filepath.Join(imageDir, "config.json") 46 + if err := downloadBlobViaPresignedURL(job.HoldEndpoint, job.HoldDID, job.Config.Digest, configPath); err != nil { 47 + cleanup() 48 + return "", nil, fmt.Errorf("failed to download config blob: %w", err) 49 + } 50 + 51 + configData, err := os.ReadFile(configPath) 52 + if err != nil { 53 + cleanup() 54 + return "", nil, fmt.Errorf("failed to read config: %w", err) 55 + } 56 + var configObj map[string]interface{} 57 + if err := json.Unmarshal(configData, &configObj); err != nil { 58 + cleanup() 59 + return "", nil, fmt.Errorf("invalid config JSON: %w", err) 60 + } 61 + 62 + // Download and extract each layer 63 + for i, layer := range job.Layers { 64 + slog.Info("Extracting layer", "index", i, "digest", layer.Digest, "size", layer.Size) 65 + 66 + layerPath := filepath.Join(layersDir, fmt.Sprintf("layer-%d.tar.gz", i)) 67 + if err := downloadBlobViaPresignedURL(job.HoldEndpoint, job.HoldDID, layer.Digest, layerPath); err != nil { 68 + cleanup() 69 + return "", nil, fmt.Errorf("failed to download layer %d: %w", i, err) 70 + } 71 + 72 + if err := extractTarGz(layerPath, rootfsDir); err != nil { 73 + cleanup() 74 + return "", nil, fmt.Errorf("failed to extract layer %d: %w", i, err) 75 + } 76 + 77 + // Remove layer tar.gz to save space 78 + os.Remove(layerPath) 79 + } 80 + 81 + entries, err := os.ReadDir(rootfsDir) 82 + if err != nil { 83 + slog.Warn("Failed to read rootfs directory", "error", err) 84 + } else { 85 + slog.Info("Successfully extracted image", 86 + "layers", len(job.Layers), 87 + "topLevelEntries", len(entries)) 88 + } 89 + 90 + return rootfsDir, cleanup, nil 91 + } 92 + 93 + // downloadBlobViaPresignedURL gets a presigned URL from the hold and downloads the blob 94 + func downloadBlobViaPresignedURL(holdEndpoint, holdDID, digest, destPath string) error { 95 + presignedURL, err := client.GetBlobPresignedURL(holdEndpoint, holdDID, digest) 96 + if err != nil { 97 + return fmt.Errorf("failed to get presigned URL for %s: %w", digest, err) 98 + } 99 + return client.DownloadBlob(presignedURL, destPath) 100 + } 101 + 102 + // extractTarGz extracts a tar.gz file to a destination directory (overlayfs style) 103 + func extractTarGz(tarGzPath, destDir string) error { 104 + file, err := os.Open(tarGzPath) 105 + if err != nil { 106 + return fmt.Errorf("failed to open tar.gz: %w", err) 107 + } 108 + defer file.Close() 109 + 110 + gzr, err := gzip.NewReader(file) 111 + if err != nil { 112 + return fmt.Errorf("failed to create gzip reader: %w", err) 113 + } 114 + defer gzr.Close() 115 + 116 + tr := tar.NewReader(gzr) 117 + 118 + for { 119 + header, err := tr.Next() 120 + if err == io.EOF { 121 + break 122 + } 123 + if err != nil { 124 + return fmt.Errorf("failed to read tar header: %w", err) 125 + } 126 + 127 + target := filepath.Join(destDir, filepath.Clean(header.Name)) 128 + 129 + // Security: ensure target is within destDir 130 + if !strings.HasPrefix(target, filepath.Clean(destDir)+string(os.PathSeparator)) { 131 + slog.Warn("Skipping path outside destination", "path", header.Name) 132 + continue 133 + } 134 + 135 + switch header.Typeflag { 136 + case tar.TypeDir: 137 + if err := os.MkdirAll(target, os.FileMode(header.Mode)); err != nil { 138 + return fmt.Errorf("failed to create directory %s: %w", target, err) 139 + } 140 + 141 + case tar.TypeReg: 142 + if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil { 143 + return fmt.Errorf("failed to create parent directory: %w", err) 144 + } 145 + outFile, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.FileMode(header.Mode)) 146 + if err != nil { 147 + return fmt.Errorf("failed to create file %s: %w", target, err) 148 + } 149 + if _, err := io.Copy(outFile, tr); err != nil { 150 + outFile.Close() 151 + return fmt.Errorf("failed to write file %s: %w", target, err) 152 + } 153 + outFile.Close() 154 + 155 + case tar.TypeSymlink: 156 + if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil { 157 + return fmt.Errorf("failed to create parent directory for symlink: %w", err) 158 + } 159 + os.Remove(target) 160 + if err := os.Symlink(header.Linkname, target); err != nil { 161 + slog.Warn("Failed to create symlink", "target", target, "link", header.Linkname, "error", err) 162 + } 163 + 164 + case tar.TypeLink: 165 + linkTarget := filepath.Join(destDir, filepath.Clean(header.Linkname)) 166 + if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil { 167 + return fmt.Errorf("failed to create parent directory for hardlink: %w", err) 168 + } 169 + os.Remove(target) 170 + if err := os.Link(linkTarget, target); err != nil { 171 + slog.Warn("Failed to create hardlink", "target", target, "link", linkTarget, "error", err) 172 + } 173 + 174 + default: 175 + slog.Debug("Skipping unsupported tar entry type", "type", header.Typeflag, "name", header.Name) 176 + } 177 + } 178 + 179 + return nil 180 + }
+248
scanner/internal/scan/grype.go
··· 1 + package scan 2 + 3 + import ( 4 + "context" 5 + "crypto/sha256" 6 + "encoding/json" 7 + "fmt" 8 + "log/slog" 9 + "os" 10 + "path/filepath" 11 + "sync" 12 + "time" 13 + 14 + scanner "atcr.io/scanner" 15 + "github.com/anchore/grype/grype" 16 + "github.com/anchore/grype/grype/db/v6/distribution" 17 + "github.com/anchore/grype/grype/db/v6/installation" 18 + "github.com/anchore/grype/grype/distro" 19 + "github.com/anchore/grype/grype/match" 20 + "github.com/anchore/grype/grype/matcher" 21 + "github.com/anchore/grype/grype/matcher/dotnet" 22 + "github.com/anchore/grype/grype/matcher/golang" 23 + "github.com/anchore/grype/grype/matcher/java" 24 + "github.com/anchore/grype/grype/matcher/javascript" 25 + "github.com/anchore/grype/grype/matcher/python" 26 + "github.com/anchore/grype/grype/matcher/ruby" 27 + "github.com/anchore/grype/grype/matcher/stock" 28 + grypePkg "github.com/anchore/grype/grype/pkg" 29 + "github.com/anchore/grype/grype/vulnerability" 30 + "github.com/anchore/syft/syft/sbom" 31 + ) 32 + 33 + // Global vulnerability database (shared across workers) 34 + var ( 35 + vulnDB vulnerability.Provider 36 + vulnDBLock sync.RWMutex 37 + ) 38 + 39 + // scanVulnerabilities scans an SBOM for vulnerabilities using Grype 40 + func scanVulnerabilities(ctx context.Context, s *sbom.SBOM, vulnDBPath string) ([]byte, string, scanner.VulnerabilitySummary, error) { 41 + slog.Info("Scanning for vulnerabilities with Grype") 42 + 43 + store, err := loadVulnDatabase(ctx, vulnDBPath) 44 + if err != nil { 45 + return nil, "", scanner.VulnerabilitySummary{}, fmt.Errorf("failed to load vulnerability database: %w", err) 46 + } 47 + 48 + var grypeDistro *distro.Distro 49 + if s.Artifacts.LinuxDistribution != nil { 50 + grypeDistro = distro.FromRelease(s.Artifacts.LinuxDistribution, nil) 51 + } 52 + 53 + synthesisConfig := grypePkg.SynthesisConfig{ 54 + GenerateMissingCPEs: true, 55 + Distro: grypePkg.DistroConfig{ 56 + Override: grypeDistro, 57 + }, 58 + } 59 + grypePackages := grypePkg.FromCollection(s.Artifacts.Packages, synthesisConfig) 60 + 61 + slog.Info("Converted packages for vulnerability scanning", 62 + "syftPackages", s.Artifacts.Packages.PackageCount(), 63 + "grypePackages", len(grypePackages)) 64 + 65 + matchers := matcher.NewDefaultMatchers(matcher.Config{ 66 + Java: java.MatcherConfig{}, 67 + Ruby: ruby.MatcherConfig{}, 68 + Python: python.MatcherConfig{}, 69 + Dotnet: dotnet.MatcherConfig{}, 70 + Javascript: javascript.MatcherConfig{}, 71 + Golang: golang.MatcherConfig{}, 72 + Stock: stock.MatcherConfig{}, 73 + }) 74 + 75 + pkgContext := grypePkg.Context{ 76 + Source: &s.Source, 77 + Distro: grypeDistro, 78 + } 79 + 80 + vulnerabilityMatcher := &grype.VulnerabilityMatcher{ 81 + VulnerabilityProvider: store, 82 + Matchers: matchers, 83 + NormalizeByCVE: true, 84 + } 85 + 86 + allMatches, _, err := vulnerabilityMatcher.FindMatches(grypePackages, pkgContext) 87 + if err != nil { 88 + return nil, "", scanner.VulnerabilitySummary{}, fmt.Errorf("failed to find vulnerabilities: %w", err) 89 + } 90 + 91 + summary := countVulnerabilitiesBySeverity(*allMatches) 92 + 93 + slog.Info("Vulnerability scan complete", 94 + "critical", summary.Critical, 95 + "high", summary.High, 96 + "medium", summary.Medium, 97 + "low", summary.Low, 98 + "total", summary.Total) 99 + 100 + report := map[string]interface{}{ 101 + "matches": allMatches.Sorted(), 102 + "source": s.Source, 103 + "distro": s.Artifacts.LinuxDistribution, 104 + "descriptor": map[string]interface{}{ 105 + "name": "grype", 106 + "version": "v0.107.1", 107 + }, 108 + "summary": summary, 109 + } 110 + 111 + reportJSON, err := json.MarshalIndent(report, "", " ") 112 + if err != nil { 113 + return nil, "", scanner.VulnerabilitySummary{}, fmt.Errorf("failed to encode vulnerability report: %w", err) 114 + } 115 + 116 + hash := sha256.Sum256(reportJSON) 117 + digest := fmt.Sprintf("sha256:%x", hash) 118 + 119 + return reportJSON, digest, summary, nil 120 + } 121 + 122 + // loadVulnDatabase loads the Grype vulnerability database (with caching) 123 + func loadVulnDatabase(ctx context.Context, vulnDBPath string) (vulnerability.Provider, error) { 124 + vulnDBLock.RLock() 125 + if vulnDB != nil { 126 + vulnDBLock.RUnlock() 127 + return vulnDB, nil 128 + } 129 + vulnDBLock.RUnlock() 130 + 131 + vulnDBLock.Lock() 132 + defer vulnDBLock.Unlock() 133 + 134 + if vulnDB != nil { 135 + return vulnDB, nil 136 + } 137 + 138 + slog.Info("Loading Grype vulnerability database", "path", vulnDBPath) 139 + 140 + if err := os.MkdirAll(vulnDBPath, 0755); err != nil { 141 + return nil, fmt.Errorf("failed to create vulnerability database directory: %w", err) 142 + } 143 + 144 + distConfig := distribution.DefaultConfig() 145 + installConfig := installation.Config{ 146 + DBRootDir: vulnDBPath, 147 + ValidateAge: true, 148 + ValidateChecksum: true, 149 + MaxAllowedBuiltAge: 5 * 24 * time.Hour, // 5 days 150 + } 151 + 152 + store, status, err := grype.LoadVulnerabilityDB(distConfig, installConfig, false) 153 + if err != nil { 154 + return nil, fmt.Errorf("failed to load vulnerability database (status=%v): %w", status, err) 155 + } 156 + 157 + slog.Info("Vulnerability database loaded", 158 + "built", status.Built, 159 + "schemaVersion", status.SchemaVersion) 160 + 161 + vulnDB = store 162 + return vulnDB, nil 163 + } 164 + 165 + // initializeVulnDatabase downloads the vulnerability database on startup 166 + func initializeVulnDatabase(vulnDBPath, tmpDir string) error { 167 + slog.Info("Initializing vulnerability database", "path", vulnDBPath) 168 + 169 + if err := os.MkdirAll(vulnDBPath, 0755); err != nil { 170 + return fmt.Errorf("failed to create database directory: %w", err) 171 + } 172 + 173 + grpeTmpDir := filepath.Join(tmpDir, "grype-dl") 174 + if err := os.MkdirAll(grpeTmpDir, 0755); err != nil { 175 + return fmt.Errorf("failed to create temp directory: %w", err) 176 + } 177 + 178 + oldTmpDir := os.Getenv("TMPDIR") 179 + os.Setenv("TMPDIR", grpeTmpDir) 180 + defer func() { 181 + if oldTmpDir != "" { 182 + os.Setenv("TMPDIR", oldTmpDir) 183 + } else { 184 + os.Unsetenv("TMPDIR") 185 + } 186 + }() 187 + 188 + distConfig := distribution.DefaultConfig() 189 + installConfig := installation.Config{ 190 + DBRootDir: vulnDBPath, 191 + ValidateAge: true, 192 + ValidateChecksum: true, 193 + MaxAllowedBuiltAge: 5 * 24 * time.Hour, 194 + } 195 + 196 + downloader, err := distribution.NewClient(distConfig) 197 + if err != nil { 198 + return fmt.Errorf("failed to create database downloader: %w", err) 199 + } 200 + 201 + curator, err := installation.NewCurator(installConfig, downloader) 202 + if err != nil { 203 + return fmt.Errorf("failed to create database curator: %w", err) 204 + } 205 + 206 + status := curator.Status() 207 + if !status.Built.IsZero() && status.Error == nil { 208 + slog.Info("Vulnerability database already exists", "built", status.Built) 209 + return nil 210 + } 211 + 212 + slog.Info("Downloading vulnerability database (this may take 5-10 minutes)...") 213 + updated, err := curator.Update() 214 + if err != nil { 215 + return fmt.Errorf("failed to download vulnerability database: %w", err) 216 + } 217 + 218 + if updated { 219 + slog.Info("Vulnerability database downloaded successfully") 220 + } else { 221 + slog.Info("Vulnerability database is up to date") 222 + } 223 + 224 + return nil 225 + } 226 + 227 + func countVulnerabilitiesBySeverity(matches match.Matches) scanner.VulnerabilitySummary { 228 + summary := scanner.VulnerabilitySummary{} 229 + 230 + for m := range matches.Enumerate() { 231 + summary.Total++ 232 + 233 + if m.Vulnerability.Metadata != nil { 234 + switch m.Vulnerability.Metadata.Severity { 235 + case "Critical": 236 + summary.Critical++ 237 + case "High": 238 + summary.High++ 239 + case "Medium": 240 + summary.Medium++ 241 + case "Low": 242 + summary.Low++ 243 + } 244 + } 245 + } 246 + 247 + return summary 248 + }
+69
scanner/internal/scan/syft.go
··· 1 + package scan 2 + 3 + import ( 4 + "context" 5 + "crypto/sha256" 6 + "fmt" 7 + "log/slog" 8 + "os" 9 + 10 + "github.com/anchore/syft/syft" 11 + "github.com/anchore/syft/syft/format" 12 + "github.com/anchore/syft/syft/format/spdxjson" 13 + "github.com/anchore/syft/syft/sbom" 14 + "github.com/anchore/syft/syft/source/directorysource" 15 + ) 16 + 17 + // generateSBOM generates an SBOM using Syft from an extracted image directory 18 + // Returns the SBOM object, SBOM JSON bytes, and its digest 19 + func generateSBOM(ctx context.Context, imageDir string) (*sbom.SBOM, []byte, string, error) { 20 + slog.Info("Generating SBOM with Syft", "imageDir", imageDir) 21 + 22 + entries, err := os.ReadDir(imageDir) 23 + if err != nil { 24 + return nil, nil, "", fmt.Errorf("failed to read image directory: %w", err) 25 + } 26 + slog.Info("Image directory contents", "path", imageDir, "entries", len(entries)) 27 + 28 + src, err := directorysource.NewFromPath(imageDir) 29 + if err != nil { 30 + return nil, nil, "", fmt.Errorf("failed to create Syft source: %w", err) 31 + } 32 + defer src.Close() 33 + 34 + slog.Info("Running Syft cataloging") 35 + sbomResult, err := syft.CreateSBOM(ctx, src, nil) 36 + if err != nil { 37 + return nil, nil, "", fmt.Errorf("failed to generate SBOM: %w", err) 38 + } 39 + 40 + if sbomResult == nil { 41 + return nil, nil, "", fmt.Errorf("Syft returned nil SBOM") 42 + } 43 + 44 + slog.Info("SBOM generated", 45 + "packages", sbomResult.Artifacts.Packages.PackageCount(), 46 + "distro", func() string { 47 + if sbomResult.Artifacts.LinuxDistribution != nil { 48 + return fmt.Sprintf("%s %s", sbomResult.Artifacts.LinuxDistribution.Name, sbomResult.Artifacts.LinuxDistribution.Version) 49 + } 50 + return "none" 51 + }()) 52 + 53 + encoder, err := spdxjson.NewFormatEncoderWithConfig(spdxjson.DefaultEncoderConfig()) 54 + if err != nil { 55 + return nil, nil, "", fmt.Errorf("failed to create SPDX encoder: %w", err) 56 + } 57 + 58 + sbomJSON, err := format.Encode(*sbomResult, encoder) 59 + if err != nil { 60 + return nil, nil, "", fmt.Errorf("failed to encode SBOM to SPDX JSON: %w", err) 61 + } 62 + 63 + hash := sha256.Sum256(sbomJSON) 64 + digest := fmt.Sprintf("sha256:%x", hash) 65 + 66 + slog.Info("SBOM encoded", "format", "spdx-json", "size", len(sbomJSON), "digest", digest) 67 + 68 + return sbomResult, sbomJSON, digest, nil 69 + }
+150
scanner/internal/scan/worker.go
··· 1 + // Package scan implements the vulnerability scanning pipeline: 2 + // extract layers → generate SBOM → scan vulnerabilities → send result. 3 + package scan 4 + 5 + import ( 6 + "context" 7 + "fmt" 8 + "log/slog" 9 + "os" 10 + "sync" 11 + "time" 12 + 13 + scanner "atcr.io/scanner" 14 + "atcr.io/scanner/internal/client" 15 + "atcr.io/scanner/internal/config" 16 + "atcr.io/scanner/internal/queue" 17 + ) 18 + 19 + // WorkerPool manages a pool of scan workers 20 + type WorkerPool struct { 21 + cfg *config.Config 22 + queue *queue.JobQueue 23 + client *client.HoldClient 24 + wg sync.WaitGroup 25 + } 26 + 27 + // NewWorkerPool creates a new worker pool 28 + func NewWorkerPool(cfg *config.Config, q *queue.JobQueue, c *client.HoldClient) *WorkerPool { 29 + return &WorkerPool{ 30 + cfg: cfg, 31 + queue: q, 32 + client: c, 33 + } 34 + } 35 + 36 + // Start launches worker goroutines 37 + func (wp *WorkerPool) Start(ctx context.Context) { 38 + // Initialize vuln database on startup if enabled 39 + if wp.cfg.VulnEnabled { 40 + go func() { 41 + if err := initializeVulnDatabase(wp.cfg.VulnDBPath, wp.cfg.TmpDir); err != nil { 42 + slog.Error("Failed to initialize vulnerability database", "error", err) 43 + slog.Warn("Vulnerability scanning will be disabled until database is available") 44 + } 45 + }() 46 + } 47 + 48 + for i := 0; i < wp.cfg.Workers; i++ { 49 + wp.wg.Add(1) 50 + go wp.worker(ctx, i) 51 + } 52 + 53 + slog.Info("Scanner worker pool started", "workers", wp.cfg.Workers) 54 + } 55 + 56 + // Wait blocks until all workers finish 57 + func (wp *WorkerPool) Wait() { 58 + wp.wg.Wait() 59 + } 60 + 61 + func (wp *WorkerPool) worker(ctx context.Context, id int) { 62 + defer wp.wg.Done() 63 + 64 + slog.Info("Scanner worker started", "worker_id", id) 65 + 66 + for { 67 + job := wp.queue.Dequeue() 68 + if job == nil { 69 + slog.Info("Scanner worker shutting down", "worker_id", id) 70 + return 71 + } 72 + 73 + slog.Info("Processing scan job", 74 + "worker_id", id, 75 + "repository", job.Repository, 76 + "tag", job.Tag, 77 + "digest", job.ManifestDigest, 78 + "tier", job.Tier) 79 + 80 + result, err := wp.processJob(ctx, job) 81 + if err != nil { 82 + slog.Error("Scan job failed", 83 + "worker_id", id, 84 + "repository", job.Repository, 85 + "error", err) 86 + wp.client.SendError(job.Seq, err.Error()) 87 + continue 88 + } 89 + 90 + wp.client.SendResult(job.Seq, result) 91 + 92 + slog.Info("Scan job completed", 93 + "worker_id", id, 94 + "repository", job.Repository, 95 + "vulnerabilities", result.Summary.Total) 96 + } 97 + } 98 + 99 + func (wp *WorkerPool) processJob(ctx context.Context, job *scanner.ScanJob) (*scanner.ScanResult, error) { 100 + startTime := time.Now() 101 + 102 + // Ensure tmp dir exists 103 + if err := ensureDir(wp.cfg.TmpDir); err != nil { 104 + return nil, fmt.Errorf("failed to create tmp dir: %w", err) 105 + } 106 + 107 + // Step 1: Extract image layers from hold via presigned URLs 108 + slog.Info("Extracting image layers", "repository", job.Repository) 109 + imageDir, cleanup, err := extractLayers(job, wp.cfg.TmpDir) 110 + if err != nil { 111 + return nil, fmt.Errorf("failed to extract layers: %w", err) 112 + } 113 + defer cleanup() 114 + 115 + // Step 2: Generate SBOM with Syft 116 + slog.Info("Generating SBOM", "repository", job.Repository) 117 + sbomResult, sbomJSON, sbomDigest, err := generateSBOM(ctx, imageDir) 118 + if err != nil { 119 + return nil, fmt.Errorf("failed to generate SBOM: %w", err) 120 + } 121 + 122 + result := &scanner.ScanResult{ 123 + ManifestDigest: job.ManifestDigest, 124 + SBOM: sbomJSON, 125 + SBOMDigest: sbomDigest, 126 + } 127 + 128 + // Step 3: Scan SBOM with Grype (if enabled) 129 + if wp.cfg.VulnEnabled { 130 + slog.Info("Scanning for vulnerabilities", "repository", job.Repository) 131 + vulnJSON, vulnDigest, summary, err := scanVulnerabilities(ctx, sbomResult, wp.cfg.VulnDBPath) 132 + if err != nil { 133 + return nil, fmt.Errorf("failed to scan vulnerabilities: %w", err) 134 + } 135 + result.VulnReport = vulnJSON 136 + result.VulnDigest = vulnDigest 137 + result.Summary = &summary 138 + } 139 + 140 + duration := time.Since(startTime) 141 + slog.Info("Scan pipeline completed", 142 + "repository", job.Repository, 143 + "duration", duration) 144 + 145 + return result, nil 146 + } 147 + 148 + func ensureDir(path string) error { 149 + return os.MkdirAll(path, 0755) 150 + }
+84
scanner/types.go
··· 1 + // Package scanner defines shared types for the ATCR scanner service. 2 + // These types are self-contained with no imports from the root module. 3 + package scanner 4 + 5 + import "encoding/json" 6 + 7 + // ScanJob represents a vulnerability scanning job received from the hold service 8 + type ScanJob struct { 9 + Seq int64 `json:"seq"` 10 + ManifestDigest string `json:"manifestDigest"` 11 + Repository string `json:"repository"` 12 + Tag string `json:"tag"` 13 + UserDID string `json:"userDid"` 14 + UserHandle string `json:"userHandle"` 15 + HoldDID string `json:"holdDid"` 16 + HoldEndpoint string `json:"holdEndpoint"` 17 + Tier string `json:"tier"` 18 + Config BlobDescriptor `json:"config"` 19 + Layers []BlobDescriptor `json:"layers"` 20 + } 21 + 22 + // ScanJobRaw is the raw WebSocket message with JSON config/layers 23 + type ScanJobRaw struct { 24 + Type string `json:"type"` // "job" 25 + Seq int64 `json:"seq"` 26 + ManifestDigest string `json:"manifestDigest"` 27 + Repository string `json:"repository"` 28 + Tag string `json:"tag"` 29 + UserDID string `json:"userDid"` 30 + UserHandle string `json:"userHandle"` 31 + HoldDID string `json:"holdDid"` 32 + HoldEndpoint string `json:"holdEndpoint"` 33 + Tier string `json:"tier"` 34 + Config json.RawMessage `json:"config"` 35 + Layers json.RawMessage `json:"layers"` 36 + } 37 + 38 + // BlobDescriptor describes a blob (layer or config) in a container image 39 + type BlobDescriptor struct { 40 + Digest string `json:"digest"` 41 + Size int64 `json:"size"` 42 + MediaType string `json:"mediaType"` 43 + } 44 + 45 + // ScanResult contains the output of a completed scan 46 + type ScanResult struct { 47 + ManifestDigest string `json:"manifestDigest"` 48 + SBOM []byte `json:"sbom,omitempty"` 49 + SBOMDigest string `json:"sbomDigest,omitempty"` 50 + VulnReport []byte `json:"vulnReport,omitempty"` 51 + VulnDigest string `json:"vulnDigest,omitempty"` 52 + Summary *VulnerabilitySummary `json:"summary,omitempty"` 53 + } 54 + 55 + // VulnerabilitySummary contains counts of vulnerabilities by severity 56 + type VulnerabilitySummary struct { 57 + Critical int `json:"critical"` 58 + High int `json:"high"` 59 + Medium int `json:"medium"` 60 + Low int `json:"low"` 61 + Total int `json:"total"` 62 + } 63 + 64 + // AckMessage is sent from scanner to hold to acknowledge job receipt 65 + type AckMessage struct { 66 + Type string `json:"type"` // "ack" 67 + Seq int64 `json:"seq"` 68 + } 69 + 70 + // ResultMessage is sent from scanner to hold with scan results 71 + type ResultMessage struct { 72 + Type string `json:"type"` // "result" 73 + Seq int64 `json:"seq"` 74 + SBOM string `json:"sbom,omitempty"` 75 + VulnReport string `json:"vulnReport,omitempty"` 76 + Summary *VulnerabilitySummary `json:"summary,omitempty"` 77 + } 78 + 79 + // ErrorMessage is sent from scanner to hold when a scan fails 80 + type ErrorMessage struct { 81 + Type string `json:"type"` // "error" 82 + Seq int64 `json:"seq"` 83 + Error string `json:"error"` 84 + }