diff --git a/go.mod b/go.mod index 96d4e6c..3904599 100644 --- a/go.mod +++ b/go.mod @@ -1,56 +1,59 @@ module github.com/compliance-framework/plugin-apt-versions -go 1.23.2 +go 1.23.6 + +toolchain go1.24.1 require ( - github.com/compliance-framework/agent v0.0.15 - github.com/compliance-framework/configuration-service v0.0.5 - github.com/golang/protobuf v1.5.4 + github.com/compliance-framework/agent v0.1.1 + github.com/compliance-framework/configuration-service v0.1.1 github.com/google/uuid v1.6.0 - github.com/hashicorp/go-hclog v1.5.0 - github.com/hashicorp/go-plugin v1.6.2 - google.golang.org/protobuf v1.35.2 + github.com/hashicorp/go-hclog v1.6.3 + github.com/hashicorp/go-plugin v1.6.3 + github.com/stretchr/testify v1.10.0 + google.golang.org/protobuf v1.36.6 ) require ( - github.com/OneOfOne/xxhash v1.2.8 // indirect - github.com/agnivade/levenshtein v1.2.0 // indirect + github.com/agnivade/levenshtein v1.2.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/defenseunicorns/go-oscal v0.6.2 // indirect - github.com/fatih/color v1.15.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/fatih/color v1.18.0 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/hashicorp/yamux v0.1.1 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/hashicorp/yamux v0.1.2 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/oklog/run v1.0.0 // indirect - github.com/open-policy-agent/opa v1.0.0 // indirect - github.com/prometheus/client_golang v1.20.5 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/open-policy-agent/opa v1.2.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.21.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.57.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect + github.com/prometheus/common v0.63.0 // indirect + github.com/prometheus/procfs v0.16.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/tchap/go-patricia/v2 v2.3.1 // indirect + github.com/tchap/go-patricia/v2 v2.3.2 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/yashtewari/glob-intersection v0.2.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.33.0 // indirect - go.opentelemetry.io/otel/metric v1.33.0 // indirect - go.opentelemetry.io/otel/sdk v1.33.0 // indirect - go.opentelemetry.io/otel/trace v1.33.0 // indirect - golang.org/x/net v0.34.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/text v0.21.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect - google.golang.org/grpc v1.69.2 // indirect + go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/sdk v1.35.0 // indirect + go.opentelemetry.io/otel/trace v1.35.0 // indirect + golang.org/x/net v0.37.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/text v0.23.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect + google.golang.org/grpc v1.71.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 5c95b58..2a0594b 100644 --- a/go.sum +++ b/go.sum @@ -6,14 +6,12 @@ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= -github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/agnivade/levenshtein v1.2.0 h1:U9L4IOT0Y3i0TIlUIDJ7rVUziKi/zPbrJGaFrtYH3SY= -github.com/agnivade/levenshtein v1.2.0/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= +github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM= +github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -24,16 +22,14 @@ github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HV github.com/bytecodealliance/wasmtime-go/v3 v3.0.2/go.mod h1:RnUjnIXxEJcL6BgCvNyzCCRzZcxCgsZCi+RNlvYor5Q= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/compliance-framework/agent v0.0.15 h1:VEB3xI3VSgTeudw8L+Czv9VCMt6vM7Nutd+JeMjWjuk= -github.com/compliance-framework/agent v0.0.15/go.mod h1:/ZxHkJJm/wthxm+W7atUgSMfL2217cCaBgN6dfsDSYo= -github.com/compliance-framework/configuration-service v0.0.5 h1:vK9mSb8dzaaTt+hd+g2g3+8nvfr/Ha5pMXB4yiYMA64= -github.com/compliance-framework/configuration-service v0.0.5/go.mod h1:irXS+U+ZGaNrOmaNqb+pMmo+4BxSZJ0/vs4ne/5qVJc= -github.com/containerd/containerd v1.7.24 h1:zxszGrGjrra1yYJW/6rhm9cJ1ZQ8rkKBR48brqsa7nA= -github.com/containerd/containerd v1.7.24/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw= +github.com/compliance-framework/agent v0.1.1 h1:uQ4idgwOMqrgM0JeYCtBv20HZoMymsH2nownrkl457w= +github.com/compliance-framework/agent v0.1.1/go.mod h1:jy/26xgTx9+at64ipTV1oo80pTVyhtlZaSMViQ3cVVQ= +github.com/compliance-framework/configuration-service v0.1.1 h1:p/r5vq1FLe0S8j/kLhth4Dvda8xajVPOBjnO9QauMjM= +github.com/compliance-framework/configuration-service v0.1.1/go.mod h1:tLKJKXbQbY9Pg/e3BJtJVkqxaejXJMHoE8Yp0NW4lDE= +github.com/containerd/containerd v1.7.26 h1:3cs8K2RHlMQaPifLqgRyI4VBkoldNdEw62cb7qQga7k= +github.com/containerd/containerd v1.7.26/go.mod h1:m4JU0E+h0ebbo9yXD7Hyt+sWnc8tChm7MudCjj4jRvQ= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= @@ -46,10 +42,10 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/defenseunicorns/go-oscal v0.6.2 h1:oLkMAJYVMq73Rm+9efcyaKq5SLMditjB6wv7o3XXpq8= github.com/defenseunicorns/go-oscal v0.6.2/go.mod h1:UHp2yK9ty2mYJDun7oNhbstCq6SAAwP4YGbw9n7uG6o= -github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg= -github.com/dgraph-io/badger/v3 v3.2103.5/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw= -github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= -github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= +github.com/dgraph-io/badger/v4 v4.5.1 h1:7DCIXrQjo1LKmM96YD+hLVJ2EEsyyoWxJfpdd56HLps= +github.com/dgraph-io/badger/v4 v4.5.1/go.mod h1:qn3Be0j3TfV4kPbVoK0arXCD1/nr1ftth6sbL5jxdoA= +github.com/dgraph-io/ristretto/v2 v2.1.0 h1:59LjpOJLNDULHh8MC4UaegN52lC4JnO2dITsie/Pa8I= +github.com/dgraph-io/ristretto/v2 v2.1.0/go.mod h1:uejeqfYXpUomfse0+lO+13ATz4TypQYLJZzBSAemuB4= github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54 h1:SG7nF6SRlWhcT7cNTs5R6Hk4V2lcmLz2NsG2VnInyNo= github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= @@ -63,8 +59,8 @@ github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= @@ -104,31 +100,29 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= -github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM= -github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v24.12.23+incompatible h1:ubBKR94NR4pXUCY/MUsRVzd9umNW7ht7EG9hHfS9FX8= +github.com/google/flatbuffers v24.12.23+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog= -github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q= -github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= -github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0UUrwg= +github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0= +github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= +github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -153,11 +147,10 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= @@ -180,10 +173,10 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/open-policy-agent/opa v1.0.0 h1:fZsEwxg1knpPvUn0YDJuJZBcbVg4G3zKpWa3+CnYK+I= -github.com/open-policy-agent/opa v1.0.0/go.mod h1:+JyoH12I0+zqyC1iX7a2tmoQlipwAEGvOhVJMhmy+rM= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/open-policy-agent/opa v1.2.0 h1:88NDVCM0of1eO6Z4AFeL3utTEtMuwloFmWWU7dRV1z0= +github.com/open-policy-agent/opa v1.2.0/go.mod h1:30euUmOvuBoebRCcJ7DMF42bRBOPznvt0ACUMYDUGVY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -195,14 +188,14 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= +github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY= -github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= +github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= +github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM= +github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= @@ -224,8 +217,8 @@ github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM= github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= -github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes= -github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= +github.com/tchap/go-patricia/v2 v2.3.2 h1:xTHFutuitO2zqKAQ5rCROYgUb7Or/+IC3fts9/Yc7nM= +github.com/tchap/go-patricia/v2 v2.3.2/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= github.com/testcontainers/testcontainers-go v0.35.0 h1:uADsZpTKFAtp8SLK+hMwSaa+X+JiERHtd4sQAFmXeMo= github.com/testcontainers/testcontainers-go v0.35.0/go.mod h1:oEVBj5zrfJTrgjwONs1SsRbnBtH9OKl+IGl3UMcr2B4= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= @@ -258,60 +251,61 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= -go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= -go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 h1:5pojmb1U1AogINhN3SurB+zm/nIcusopeBNp42f45QM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0/go.mod h1:57gTHJSE5S1tqg+EKsLPlTWhpHMsWlVmer+LA926XiA= -go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= -go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= -go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM= -go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= -go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= -go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= -go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= -go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= -go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= +go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= +golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= -golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= +golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= -google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q= -google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= -google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= -google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= -google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= -google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA= +google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= +google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/internal/packages.go b/internal/packages.go new file mode 100644 index 0000000..491be06 --- /dev/null +++ b/internal/packages.go @@ -0,0 +1,126 @@ +package internal + +import ( + "bytes" + "fmt" + "os/exec" + "strings" + + "github.com/compliance-framework/agent/runner/proto" + "github.com/hashicorp/go-hclog" +) + +// GetInstalledPackages retrieves the list of installed packages in JSON format +func GetInstalledPackages(logger hclog.Logger) (map[string]any, []*proto.Step, error) { + steps := make([]*proto.Step, 0) + + steps = append(steps, &proto.Step{ + Title: "Get installed packages", + Description: "Get the list of installed package names and versions on the host using the `dpkg-query` command. This will be used to evaluate the versions of installed packages against the policies supplied.", + Remarks: StringAddressed("`dpkg-query -W -f='${Package} ${Version}'` is used to collect the installed packages and their versions."), + }) + + command := `dpkg-query -W -f='${Package} ${Version}\n'` + logger.Debug(fmt.Sprintf("RUNNING COMMAND: %s", command)) + dpkgCmd := exec.Command("bash", "-c", command) + + var dpkgStdout bytes.Buffer + var dpkgStderr bytes.Buffer + dpkgCmd.Stdout = &dpkgStdout + dpkgCmd.Stderr = &dpkgStderr + if err := dpkgCmd.Run(); err != nil { + if dpkgStderr.Len() > 0 { + logger.Error(fmt.Sprintf("stderr: %s", dpkgStderr.String())) + } + return nil, steps, fmt.Errorf("error running dpkg-query: %w", err) + } + + if dpkgStderr.Len() > 0 { + logger.Warn(fmt.Sprintf("error found running dpkg-query, continuing as exited successfully: %s", dpkgStderr.String())) + } + + // Parse the output into a map + packages, newSteps := getPackages(logger, dpkgStdout.String()) + steps = append(steps, newSteps...) + + return packages, steps, nil +} + +func getPackages(logger hclog.Logger, packageData string) (map[string]any, []*proto.Step) { + packages := make(map[string]any) + + for _, line := range strings.Split(packageData, "\n") { + if len(line) == 0 { + continue + } + + parts := strings.Split(line, " ") + if len(parts) != 2 { + logger.Warn(fmt.Sprintf("unexpected number of parts in package line, cannot process: %s", line)) + continue + } + + packageName := parts[0] + packageVersion := getVersion(parts[1]) + + packages[packageName] = packageVersion + } + + step := &proto.Step{ + Title: "Retrieved all installed packages and normalised versions", + Description: "Retrieved all the installed packages and their versions on the host. The versions are all normalised to a standard format for comparison of the format `x.y.z` where `x`, `y` and `z` are all integers and intended to match the standard SemVer pattern of `major.minor.patch`.", + Remarks: StringAddressed(fmt.Sprintf("Normalized %d package versions", len(packages))), + } + + return packages, []*proto.Step{step} +} + +func getVersion(version string) string { + // If the version contains a colon, we'll split the string and return the version from the second part + if colonIndex := strings.Index(version, ":"); colonIndex != -1 { + version = version[colonIndex+1:] + } + + // If we have any of the characters, '-', '+', '~', we'll split the string and return the version from the first part + if dashIndex := strings.IndexAny(version, "-+~"); dashIndex != -1 { + version = version[:dashIndex] + } + + // Split the version into parts + parts := strings.Split(version, ".") + + // Check each part is just a number, if it's not we'll split the part and only keep the number + for i, part := range parts { + // If the part contains a string after a number we skip from the number onwards + for j, char := range part { + if char >= '0' && char <= '9' { + continue + } + parts[i] = part[:j] + break + } + } + + // Check each part for leading zeros and remove them + for i, part := range parts { + for j, char := range part { + if char != '0' { + parts[i] = part[j:] + break + } + } + } + + // Make sure we have exactly 3 parts separated by a dot, if we don't we append 0 to the version, if more we skip the rest + if len(parts) < 3 { + for i := len(parts); i < 3; i++ { + parts = append(parts, "0") + } + } else if len(parts) > 3 { + parts = parts[:3] + } + + version = strings.Join(parts, ".") + + return version +} diff --git a/internal/packages_test.go b/internal/packages_test.go new file mode 100644 index 0000000..808bc07 --- /dev/null +++ b/internal/packages_test.go @@ -0,0 +1,208 @@ +package internal + +import ( + "strings" + "testing" + + "github.com/hashicorp/go-hclog" + "github.com/stretchr/testify/assert" +) + +func TestGetSimplePackage(t *testing.T) { + logger := hclog.New(&hclog.LoggerOptions{ + Level: hclog.Error, + JSONFormat: true, + }) + packages, steps := getPackages(logger, "mycoolpackage 1.2.3\n") + + version := packages["mycoolpackage"].(string) + assert.Equal(t, version, "1.2.3") + assert.Len(t, steps, 1) +} + +func TestGetPackageWithEpochVersion(t *testing.T) { + logger := hclog.New(&hclog.LoggerOptions{ + Level: hclog.Error, + JSONFormat: true, + }) + packages, steps := getPackages(logger, "mycoolpackage 2:1.2.3\n") + + version := packages["mycoolpackage"].(string) + assert.Equal(t, version, "1.2.3") + assert.Len(t, steps, 1) + + packages, steps = getPackages(logger, "mycoolpackage 24:1.2\n") + + version = packages["mycoolpackage"].(string) + assert.Equal(t, version, "1.2.0") + assert.Len(t, steps, 1) +} + +func TestGetPackageWithSpecialCharactersInVersion(t *testing.T) { + logger := hclog.New(&hclog.LoggerOptions{ + Level: hclog.Error, + JSONFormat: true, + }) + packages, steps := getPackages(logger, "mycoolpackage 1.2.3-1~ubuntu1\n") + + version := packages["mycoolpackage"].(string) + assert.Equal(t, version, "1.2.3") + assert.Len(t, steps, 1) + + packages, steps = getPackages(logger, "mycoolpackage 1.2-1ubuntu1+foo\n") + + version = packages["mycoolpackage"].(string) + assert.Equal(t, version, "1.2.0") + assert.Len(t, steps, 1) + + packages, steps = getPackages(logger, "mycoolpackage 25.2.35+ubuntu1\n") + + version = packages["mycoolpackage"].(string) + assert.Equal(t, version, "25.2.35") +} + +func TestGetPackageWithStringCharsInVersion(t *testing.T) { + logger := hclog.New(&hclog.LoggerOptions{ + Level: hclog.Error, + JSONFormat: true, + }) + packages, steps := getPackages(logger, "mycoolpackage 1.2.3ubuntu1\n") + + version := packages["mycoolpackage"].(string) + assert.Equal(t, version, "1.2.3") + assert.Len(t, steps, 1) + + packages, steps = getPackages(logger, "mycoolpackage 25.22ubuntu1\n") + + version = packages["mycoolpackage"].(string) + assert.Equal(t, version, "25.22.0") + assert.Len(t, steps, 1) + + packages, steps = getPackages(logger, "mycoolpackage 25.22ubuntu1.44mystring1\n") + + version = packages["mycoolpackage"].(string) + assert.Equal(t, version, "25.22.44") + assert.Len(t, steps, 1) +} + +func TestGetPackageWithLeadingZeroesInVersion(t *testing.T) { + logger := hclog.New(&hclog.LoggerOptions{ + Level: hclog.Error, + JSONFormat: true, + }) + packages, steps := getPackages(logger, "mycoolpackage 01.2.3\n") + + version := packages["mycoolpackage"].(string) + assert.Equal(t, version, "1.2.3") + assert.Len(t, steps, 1) + + packages, steps = getPackages(logger, "mycoolpackage 25.02\n") + + version = packages["mycoolpackage"].(string) + assert.Equal(t, version, "25.2.0") + assert.Len(t, steps, 1) +} + +func TestGetPackageWithoutThreeNumsInVersion(t *testing.T) { + logger := hclog.New(&hclog.LoggerOptions{ + Level: hclog.Error, + JSONFormat: true, + }) + packages, steps := getPackages(logger, "mycoolpackage 1.2\n") + + version := packages["mycoolpackage"].(string) + assert.Equal(t, version, "1.2.0") + assert.Len(t, steps, 1) + + packages, steps = getPackages(logger, "mycoolpackage 25.2.5.1.6\n") + + version = packages["mycoolpackage"].(string) + assert.Equal(t, version, "25.2.5") + assert.Len(t, steps, 1) +} + +func TestGetMultiplePackagesFromRealExamples(t *testing.T) { + // Setup + logger := hclog.New(&hclog.LoggerOptions{ + Level: hclog.Error, + JSONFormat: true, + }) + + packageStrings := []string{ + "accountsservice 23.13.9-2ubuntu6", + "acl 2.3.2-1build1.1", + "adduser 3.137ubuntu1", + "adwaita-icon-theme 46.0-1", + "alsa-base 1.0.25+dfsg-0ubuntu7", + "amd64-microcode 3.20231019.1ubuntu2.1", + "apg 2.2.3.dfsg.1-5build3", + "g++ 4:13.2.0-7ubuntu1", + "g++-13-x86-64-linux-gnu 13.3.0-6ubuntu2~24.04", + "gir1.2-gmenu-3.0 3.36.0-1.1ubuntu3", + "gir1.2-upowerglib-1.0 1.90.3-1", + "heif-gdk-pixbuf 1.17.6-1ubuntu4.1", + "libatomic1 14.2.0-4ubuntu2~24.04", + "libatopology2t64 1.2.11-1build2", + "libatspi2.0-0t64 2.52.0-1build1", + "libattr1 1:2.5.2-1build1.1", + "libaudit-common 1:3.1.2-2.1build1.1", + "libcairo-gobject-perl 1.005-4build3", + "libdbusmenu-glib4 18.10.20180917~bzr492+repack1-3.1ubuntu5", // TODO: Should we have 20180917 as a patch? + "libjavascriptcoregtk-4.1-0 2.46.6-0ubuntu0.24.04.1", + "libplymouth5 24.004.60-1ubuntu7.1", // TODO: Should we definitely remove leading zeros on the 004? + "libplist-2.0-4 2.3.0-1~exp2build2", + "make 4.3-4.1build2", + "mongodb-mongosh 2.4.2", + "nano 7.2-2ubuntu0.1", + "nvidia-driver-550 550.144.03-0ubuntu1", + "openjdk-21-jre 21.0.6+7-1~24.04.1", + "openssh-server 1:9.6p1-3ubuntu13.8", + "printer-driver-foo2zjs 20200505dfsg0-2ubuntu6", + } + + // Get the packages + packages, steps := getPackages(logger, strings.Join(packageStrings, "\n")) + + // Assertions + assert.Equal(t, len(packages), len(packageStrings)) + + // Check the correct packages are in the map + for expectedPkg, expectedVersion := range map[string]string{ + "accountsservice": "23.13.9", + "acl": "2.3.2", + "adduser": "3.137.0", + "adwaita-icon-theme": "46.0.0", + "alsa-base": "1.0.25", + "amd64-microcode": "3.20231019.1", + "apg": "2.2.3", + "g++": "13.2.0", + "g++-13-x86-64-linux-gnu": "13.3.0", + "gir1.2-gmenu-3.0": "3.36.0", + "gir1.2-upowerglib-1.0": "1.90.3", + "heif-gdk-pixbuf": "1.17.6", + "libatomic1": "14.2.0", + "libatopology2t64": "1.2.11", + "libatspi2.0-0t64": "2.52.0", + "libattr1": "2.5.2", + "libaudit-common": "3.1.2", + "libcairo-gobject-perl": "1.5.0", + "libdbusmenu-glib4": "18.10.20180917", + "libjavascriptcoregtk-4.1-0": "2.46.6", + "libplist-2.0-4": "2.3.0", + "libplymouth5": "24.4.60", + "make": "4.3.0", + "mongodb-mongosh": "2.4.2", + "nano": "7.2.0", + "nvidia-driver-550": "550.144.3", + "openjdk-21-jre": "21.0.6", + "openssh-server": "9.6.0", + "printer-driver-foo2zjs": "20200505.0.0", + } { + assert.Contains(t, packages, expectedPkg) + version := packages[expectedPkg].(string) + assert.Equal(t, version, expectedVersion) + } + + assert.Len(t, steps, 1) + assert.Contains(t, steps[0].GetRemarks(), "29 package") +} diff --git a/internal/util.go b/internal/util.go new file mode 100644 index 0000000..feb597f --- /dev/null +++ b/internal/util.go @@ -0,0 +1,15 @@ +package internal + +func MergeMaps(maps ...map[string]string) map[string]string { + result := make(map[string]string) + for _, imap := range maps { + for k, v := range imap { + result[k] = v + } + } + return result +} + +func StringAddressed(str string) *string { + return &str +} diff --git a/main.go b/main.go index 357a535..3c35833 100644 --- a/main.go +++ b/main.go @@ -1,22 +1,21 @@ package main import ( - "bytes" "context" - "encoding/json" + "errors" "fmt" + "os" + "time" + policyManager "github.com/compliance-framework/agent/policy-manager" "github.com/compliance-framework/agent/runner" "github.com/compliance-framework/agent/runner/proto" "github.com/compliance-framework/configuration-service/sdk" - protolang "github.com/golang/protobuf/proto" + "github.com/compliance-framework/plugin-apt-versions/internal" "github.com/google/uuid" "github.com/hashicorp/go-hclog" goplugin "github.com/hashicorp/go-plugin" "google.golang.org/protobuf/types/known/timestamppb" - "os" - "os/exec" - "time" ) type AptVersion struct { @@ -24,28 +23,29 @@ type AptVersion struct { config map[string]string } -// Configure, PrepareForEval, and Eval are called at different times during the plugin execution lifecycle, +// Configure, and Eval are called at different times during the plugin execution lifecycle, // and are responsible for different tasks: // // Configure is called on plugin startup. It is primarily used to configure a plugin for its lifetime. // Here you should store any configurations like usernames and password required by the plugin. // -// PrepareForEval is called on a scheduled execution of the plugin. Whenever the plugin is going to be run, -// PrepareForEval is called, so it can collect any data necessary for making assertions. -// Here you should run any commands, call any endpoints, or process any reports, which you want to turn into -// compliance findings and observations. +// Eval is called once for each scheduled execution with a list of policy paths and it is responsible +// for evaluating each of these policy paths against the data it requires to evaluate those policies. +// The plugin is responsible for collecting the data it needs to evaluate the policies in the Eval +// method and then running the policies against that data. // -// Eval is called multiple times for each scheduled execution. It is responsible for running policies against the -// collected data from PrepareForEval. When a user passed multiple matching policy bundles to the agent, each of them -// will be passed to Eval in sequence. Eval will run against the collected data N times, where N is the amount -// of matching policies passed into the agent. +// The simplest way to handle multiple policies is to do an initial lookup of all the data that may +// be required for all policies in the method, and then run the policies against that data. This, +// however, may not be the most efficient way to run policies, and you may want to optimize this +// while writing plugins to reduce the amount of data you need to collect and store in memory. It +// is the plugins responsibility to ensure that it is (reasonably) efficient in its use of +// resources. // // A user starts the agent, and passes the plugin and any policy bundles. // // The agent will: // - Start the plugin // - Call Configure() with teh required config -// - Call PrepareForEval() so the plugin can collect the relevant state // - Call Eval() with the first policy bundles (one by one, in turn), // so the plugin can report any violations against the configuration func (l *AptVersion) Configure(req *proto.ConfigureRequest) (*proto.ConfigureResponse, error) { @@ -53,210 +53,233 @@ func (l *AptVersion) Configure(req *proto.ConfigureRequest) (*proto.ConfigureRes // Configure is used to set up any configuration needed by this plugin over its lifetime. // This will likely only be called once on plugin startup, which may then run for an extended period of time. - // In this method, you should save any configuration values to your plugin struct, so you can later - // re-use them in PrepareForEval and Eval. - - l.config = req.Config + l.config = req.GetConfig() return &proto.ConfigureResponse{}, nil } -// GetInstalledPackages retrieves the list of installed packages in JSON format -func GetInstalledPackages(l *AptVersion) (map[string]interface{}, string, error) { - command := ` - dpkg-query -W -f='${Package} ${Version}\n' | - sed -E ' - # We want to extract the major, minor, and patch versions from the apt version string, eg: 1:2.38.1-5+deb12u3 => 2.38.1 - # Remove anything after the '-+~' - s/^([^[:space:]]*)[[:space:]](.*)[-+~].*/\1 \2/g; - - # If we see x.y.z, then extract those - s/^([^[:space:]]*)[[:space:]]([0-9]*:?)?:?([0-9]+)\.([0-9]+)[\.-]([0-9]+).*/\1 \3.\4.\5/g; - - # Remove 'ubuntu' et al - s/^([^[:space:]]*)[[:space:]]([^a-z]*)([a-z]+)([^a-z].*)/\1 \2.\4/g; - - # Then, if we see x.y, then extract that, and add a 0 for the patch version - s/^([[^:space:]]*)[[:space:]]([0-9]*:?)?:?([0-9]+)\.([0-9]+)[^.].*/\1 \3.\4.0/g; - - # Then, remove leading zeroes - s/\b0*([1-9][0-9]*)/\1/g; - - # Truncate those items that have more than three points in the version x.y.z.a rather than x.y.z - s/([^[:space:]]*)[[:space:]]([0-9]+)\.([0-9]+)\.([0-9]+)\..*/\1 \2.\3.\4/; +func (l *AptVersion) Eval(request *proto.EvalRequest, apiHelper runner.ApiHelper) (*proto.EvalResponse, error) { + ctx := context.TODO() - # Add a zero for those items with only x.y rather than x.y.z - s/([^[:space:]]*)[[:space:]]([0-9]+)\.([0-9]+)$/\1 \2.\3.0/; + activities := make([]*proto.Activity, 0) - # Add two zero for those items with only x rather than x.y.z - s/([^[:space:]]*)[[:space:]]([0-9]+)$/\1 \2.0.0/; + data, getInstalledPackagesSteps, err := internal.GetInstalledPackages(l.logger) + l.logger.Trace(fmt.Sprintf("Packages output: %s", data)) + if err != nil { + return nil, fmt.Errorf("error getting installed packages: %w", err) + } - # Now, turn that into a json object: - s/^(.*)[[:space:]](.*)/"\1": "\2"/; - ' | - awk ' - # Turn that into a json document - BEGIN { print "{" } { print (NR>1?",":"") $0 } END { print "}" } - ' | - tr '\n' ' ' - ` - l.logger.Debug(fmt.Sprintf("RUNNING COMMAND: %s", command)) - dpkgCmd := exec.Command("bash", "-c", command) + activities = append(activities, &proto.Activity{ + Title: "Collect OS packages installed", + Description: "Collect OS packages installed on the host machine, and prepare collected data for validation in policy engine", + Steps: getInstalledPackagesSteps, + }) - var dpkgOutput bytes.Buffer - dpkgCmd.Stdout = &dpkgOutput - dpkgCmd.Stderr = &dpkgOutput - if err := dpkgCmd.Run(); err != nil { - return nil, "", fmt.Errorf("error running dpkg-query: %w", err) + observations, findings, err := l.evaluatePolicies(ctx, activities, data, request) + if err != nil { + return &proto.EvalResponse{ + Status: proto.ExecutionStatus_FAILURE, + }, err } - output := fmt.Sprintf("%s", dpkgOutput.String()) - l.logger.Debug(fmt.Sprintf("Installed Packages JSON:\n%s\n", output)) + if err = apiHelper.CreateObservations(ctx, observations); err != nil { + l.logger.Error("Failed to send observations", "error", err) + return &proto.EvalResponse{ + Status: proto.ExecutionStatus_FAILURE, + }, err + } - // Parse the JSON output into a map - var packages map[string]interface{} - if err := json.Unmarshal([]byte(output), &packages); err != nil { - return nil, output, fmt.Errorf("error parsing JSON output: %w", err) + if err = apiHelper.CreateFindings(ctx, findings); err != nil { + l.logger.Error("Failed to send findings", "error", err) + return &proto.EvalResponse{ + Status: proto.ExecutionStatus_FAILURE, + }, err } - return packages, output, nil + return &proto.EvalResponse{ + Status: proto.ExecutionStatus_SUCCESS, + }, err } -func (l *AptVersion) Eval(request *proto.EvalRequest, apiHelper runner.ApiHelper) (*proto.EvalResponse, error) { - - // Eval is used to run policies against the data you've collected in PrepareForEval. - // Eval will be called N times for every scheduled plugin execution where N is the amount of matching policies - // passed to the agent. - - // When a user passes multiple policy bundles to the agent, each will be passed to Eval in turn to run against the - // same data collected in PrepareForEval. - - ctx := context.TODO() +func (l *AptVersion) evaluatePolicies(ctx context.Context, activities []*proto.Activity, packageData map[string]interface{}, req *proto.EvalRequest) ([]*proto.Observation, []*proto.Finding, error) { startTime := time.Now() + var accumulatedErrors error - data, output, err := GetInstalledPackages(l) - l.logger.Debug(fmt.Sprintf("JSON OUTPUT 0.1.6: %s", output)) - if err != nil { - return nil, fmt.Errorf("error getting installed packages: %w", err) - } + findings := make([]*proto.Finding, 0) + observations := make([]*proto.Observation, 0) - for _, policyPath := range request.GetPolicyPaths() { - // The Policy Manager aggregates much of the policy execution and output structuring. - results, err := policyManager. - New(ctx, l.logger, policyPath). - Execute(ctx, "apt_version", data) + l.logger.Debug("config", l.config) + for _, policyPath := range req.GetPolicyPaths() { + steps := make([]*proto.Step, 0) + steps = append(steps, &proto.Step{ + Title: "Compile policy bundle", + Description: "Using a locally addressable policy path, compile the policy files to an in memory executable.", + }) + steps = append(steps, &proto.Step{ + Title: "Execute policy bundle", + Description: "Using previously collected JSON-formatted installed OS package data, execute the compiled policies", + }) + results, err := policyManager.New(ctx, l.logger, policyPath).Execute(ctx, "apt_version", packageData) if err != nil { l.logger.Error("Failed to evaluate against policy bundle", "error", err) - return &proto.EvalResponse{ - Status: proto.ExecutionStatus_FAILURE, - }, err + accumulatedErrors = errors.Join(accumulatedErrors, err) + return observations, findings, accumulatedErrors } hostname := os.Getenv("HOSTNAME") + subjectAttributeMap := map[string]string{ + "type": "machine-instance", + "hostname": hostname, + } + subjects := []*proto.SubjectReference{ + { + Type: "machine-instance", + Attributes: subjectAttributeMap, + Title: internal.StringAddressed("Machine Instance"), + Remarks: internal.StringAddressed("A machine instance where we've retrieved the installed packages."), + Props: []*proto.Property{ + { + Name: "hostname", + Value: hostname, + Remarks: internal.StringAddressed("The local hostname of the machine where the plugin has been executed"), + }, + }, + }, + } + actors := []*proto.OriginActor{ + { + Title: "The Continuous Compliance Framework", + Type: "assessment-platform", + Links: []*proto.Link{ + { + Href: "https://compliance-framework.github.io/docs/", + Rel: internal.StringAddressed("reference"), + Text: internal.StringAddressed("The Continuous Compliance Framework"), + }, + }, + Props: nil, + }, + { + Title: "Continuous Compliance Framework - Local APT Installed Packages Plugin", + Type: "tool", + Links: []*proto.Link{ + { + Href: "https://github.com/compliance-framework/plugin-apt-versions", + Rel: internal.StringAddressed("reference"), + Text: internal.StringAddressed("The Continuous Compliance Framework' Local APT Installed Packages Plugin"), + }, + }, + Props: nil, + }, + } + components := []*proto.ComponentReference{ + { + Identifier: "common-components/package", + }, + } - response := runner.NewCallableAssessmentResult() - response.Title = fmt.Sprintf("Package Version compliance for host: %s", hostname) + activities = append(activities, &proto.Activity{ + Title: "Compile Results", + Description: "Using the output from policy execution, compile the resulting output to Observations and Findings, marking any violations, risks, and other OSCAL-familiar data", + Steps: steps, + }) - for _, policyResult := range results { + for _, result := range results { + // Observation UUID should differ for each individual subject, but remain consistent when validating the same policy for the same subject. + // This acts as an identifier to show the history of an observation. + observationUUIDMap := internal.MergeMaps(subjectAttributeMap, map[string]string{ + "policy": result.Policy.Package.PurePackage(), + "policy_file": result.Policy.File, + "policy_path": policyPath, + }) + observationUUID, err := sdk.SeededUUID(observationUUIDMap) + if err != nil { + accumulatedErrors = errors.Join(accumulatedErrors, err) + // We've been unable to do much here, but let's try the next one regardless. + continue + } - // There are no violations reported from the policies. - // We'll send the observation back to the agent - if len(policyResult.Violations) == 0 { - response.AddObservation(&proto.Observation{ - Uuid: uuid.New().String(), - Title: protolang.String("The plugin succeeded. No compliance issues to report."), - Description: "The plugin policies did not return any violations. The configuration is in compliance with policies.", - Collected: timestamppb.New(time.Now()), - Expires: timestamppb.New(time.Now().AddDate(0, 1, 0)), // Add one month for the expiration - RelevantEvidence: []*proto.RelevantEvidence{ - { - Description: fmt.Sprintf("Policy %v was evaluated, and no violations were found on machineId: %s", policyResult.Policy.Package.PurePackage(), "ARN:12345"), - }, - }, - }) + // Finding UUID should differ for each individual subject, but remain consistent when validating the same policy for the same subject. + // This acts as an identifier to show the history of a finding. + findingUUIDMap := internal.MergeMaps(subjectAttributeMap, map[string]string{ + "policy": result.Policy.Package.PurePackage(), + "policy_file": result.Policy.File, + "policy_path": policyPath, + }) + findingUUID, err := sdk.SeededUUID(findingUUIDMap) + if err != nil { + accumulatedErrors = errors.Join(accumulatedErrors, err) + // We've been unable to do much here, but let's try the next one regardless. + continue + } - response.AddFinding(&proto.Finding{ - Title: fmt.Sprintf("No violations found on %s", policyResult.Policy.Package.PurePackage()), - Description: fmt.Sprintf("No violations found on the %s policy within the Apt Versions Plugin.", policyResult.Policy.Package.PurePackage()), - Target: &proto.FindingTarget{ - Status: &proto.ObjectiveStatus{ - State: runner.FindingTargetStatusSatisfied, - }, + observation := proto.Observation{ + ID: uuid.New().String(), + UUID: observationUUID.String(), + Collected: timestamppb.New(startTime), + Expires: timestamppb.New(startTime.Add(24 * time.Hour)), + Origins: []*proto.Origin{{Actors: actors}}, + Subjects: subjects, + Activities: activities, + Components: components, + RelevantEvidence: []*proto.RelevantEvidence{ + { + Description: fmt.Sprintf("Policy %v was executed against the local APT installed packages, using the Local APT Packages Compliance Plugin", result.Policy.Package.PurePackage()), }, - }) + }, } - // There are violations in the policy checks. - // We'll send these observations back to the agent - if len(policyResult.Violations) > 0 { - observation := &proto.Observation{ - Uuid: uuid.New().String(), - Title: protolang.String(fmt.Sprintf("The plugin found violations for policy %s on machineId: %s", policyResult.Policy.Package.PurePackage(), "ARN:12345")), - Description: fmt.Sprintf("Observed %d violation(s) for policy %s within the Plugin on machineId: %s.", len(policyResult.Violations), policyResult.Policy.Package.PurePackage(), "ARN:12345"), - Collected: timestamppb.New(time.Now()), - Expires: timestamppb.New(time.Now().AddDate(0, 1, 0)), // Add one month for the expiration - RelevantEvidence: []*proto.RelevantEvidence{ - { - Description: fmt.Sprintf("Policy %v was evaluated, and %d violations were found on machineId: %s", policyResult.Policy.Package.PurePackage(), len(policyResult.Violations), "ARN:12345"), - }, + newFinding := func() *proto.Finding { + return &proto.Finding{ + ID: uuid.New().String(), + UUID: findingUUID.String(), + Collected: timestamppb.New(time.Now()), + Labels: map[string]string{ + "type": "package", + "host": hostname, + "_policy": result.Policy.Package.PurePackage(), + "_policy_path": result.Policy.File, }, + Origins: []*proto.Origin{{Actors: actors}}, + Subjects: subjects, + Components: components, + RelatedObservations: []*proto.RelatedObservation{{ObservationUUID: observation.ID}}, + Controls: nil, } - response.AddObservation(observation) - - for _, violation := range policyResult.Violations { - response.AddFinding(&proto.Finding{ - Uuid: uuid.New().String(), - Title: violation.Title, - Description: violation.Description, - Remarks: protolang.String(violation.Remarks), - RelatedObservations: []*proto.RelatedObservation{ - { - ObservationUuid: observation.Uuid, - }, - }, - Target: &proto.FindingTarget{ - Status: &proto.ObjectiveStatus{ - State: runner.FindingTargetStatusNotSatisfied, - }, - }, - }) - } - } - } - endTime := time.Now() - response.Start = timestamppb.New(startTime) - response.End = timestamppb.New(endTime) - response.AddLogEntry(&proto.AssessmentLog_Entry{ - Title: protolang.String("Plugin checks completed"), - Start: timestamppb.New(startTime), - End: timestamppb.New(endTime), - }) + if len(result.Violations) == 0 { + observation.Title = internal.StringAddressed(fmt.Sprintf("Local APT package validation on %s passed.", result.Policy.Package.PurePackage())) + observation.Description = fmt.Sprintf("Observed no violations on the %s policy within the Local APT Installed Package Compliance Plugin.", result.Policy.Package.PurePackage()) + observations = append(observations, &observation) - streamId, err := sdk.SeededUUID(map[string]string{ - "type": "apt-versions", - "_hostname": hostname, - "_policy": policyPath, - }) - if err != nil { - return nil, err - } - if err := apiHelper.CreateResult(streamId.String(), map[string]string{ - "type": "apt-versions", - "_hostname": hostname, - "_policy": policyPath, - }, policyPath, response.Result()); err != nil { - l.logger.Error("Failed to add assessment result", "error", err) - return &proto.EvalResponse{ - Status: proto.ExecutionStatus_FAILURE, - }, err + finding := newFinding() + finding.Title = fmt.Sprintf("No violations found on %s", result.Policy.Package.PurePackage()) + finding.Description = fmt.Sprintf("No violations found on the %s policy within the Local APT Packages Compliance Plugin.", result.Policy.Package.PurePackage()) + finding.Status = &proto.FindingStatus{ + State: runner.FindingTargetStatusSatisfied, + } + findings = append(findings, finding) + } else { + observation.Title = internal.StringAddressed(fmt.Sprintf("Validation on %s failed.", result.Policy.Package.PurePackage())) + observation.Description = fmt.Sprintf("Observed %d violation(s) on the %s policy within the Local APT Packaged Compliance Plugin.", len(result.Violations), result.Policy.Package.PurePackage()) + observations = append(observations, &observation) + + for _, violation := range result.Violations { + finding := newFinding() + finding.Title = violation.Title + finding.Description = violation.Description + finding.Remarks = internal.StringAddressed(violation.Remarks) + finding.Status = &proto.FindingStatus{ + State: runner.FindingTargetStatusNotSatisfied, + } + findings = append(findings, finding) + } + } } } - return &proto.EvalResponse{ - Status: proto.ExecutionStatus_SUCCESS, - }, nil + return observations, findings, nil } func main() {