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

implementation of syft/grype scanner as a separate binary

evan.jarrett.net d6114cf5 9c9c808e

verified
+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 + }