From 4f44d4add24283a6d666b78f221208efc503bc19 Mon Sep 17 00:00:00 2001 From: Sam Sherar Date: Fri, 11 Jul 2025 10:27:57 +0100 Subject: [PATCH 1/6] Rewrite the plugin to move to evidence gathering Remove the findings structure to follow the 0.2.0 SDK structure, with gathering of inventory items alongside No NIC information gathered at the moment wuth the new structure of gathering data in a cleaner format and letting rego make decisions across the whole data structure instead of making decisions in the plugin code --- go.mod | 43 ++--- go.sum | 207 ++++++++++---------- main.go | 586 ++++++++++++++++---------------------------------------- 3 files changed, 289 insertions(+), 547 deletions(-) diff --git a/go.mod b/go.mod index 3ffe64a..2361ce8 100644 --- a/go.mod +++ b/go.mod @@ -5,16 +5,9 @@ go 1.23.2 require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute v1.0.0 - github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.0.0 - github.com/aws/aws-sdk-go-v2 v1.36.3 - github.com/aws/aws-sdk-go-v2/config v1.29.9 - github.com/aws/aws-sdk-go-v2/service/ec2 v1.209.0 - 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/compliance-framework/agent v0.2.0 github.com/hashicorp/go-hclog v1.5.0 github.com/hashicorp/go-plugin v1.6.2 - google.golang.org/protobuf v1.35.2 ) require ( @@ -23,28 +16,19 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect github.com/OneOfOne/xxhash v1.2.8 // indirect github.com/agnivade/levenshtein v1.2.0 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.62 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 // indirect - github.com/aws/smithy-go v1.22.2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/compliance-framework/configuration-service v0.2.12-0.20250708103936-23c66564a854 // indirect github.com/defenseunicorns/go-oscal v0.6.2 // indirect github.com/fatih/color v1.15.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/go-viper/mapstructure/v2 v2.3.0 // indirect github.com/gobwas/glob v0.2.3 // indirect - github.com/golang-jwt/jwt/v5 v5.2.1 // indirect + github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang/protobuf v1.5.4 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/kylelemons/godebug v1.1.0 // indirect @@ -65,16 +49,17 @@ require ( 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 v1.35.0 // indirect + go.opentelemetry.io/otel/metric v1.35.0 // indirect go.opentelemetry.io/otel/sdk v1.33.0 // indirect - go.opentelemetry.io/otel/trace v1.33.0 // indirect - golang.org/x/crypto v0.33.0 // indirect - golang.org/x/net v0.35.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect + go.opentelemetry.io/otel/trace v1.35.0 // indirect + golang.org/x/crypto v0.37.0 // indirect + golang.org/x/net v0.38.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.24.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect google.golang.org/grpc v1.69.2 // indirect + google.golang.org/protobuf v1.36.1 // 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 f990dee..df40f11 100644 --- a/go.sum +++ b/go.sum @@ -1,17 +1,27 @@ -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute v1.0.0 h1:/Di3vB4sNeQ+7A8efjUVENvyB945Wruvstucqp7ZArg= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute v1.0.0/go.mod h1:gM3K25LQlsET3QR+4V74zxCsFAy0r6xMNN9n80SZn+4= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.0.0 h1:lMW1lD/17LUA5z1XTURo7LcVG2ICBPlyMHjIUrcFZNQ= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.0.0/go.mod h1:ceIuwmxDWptoW3eCqSXlnPsZFKh4X+R38dWPv7GS9Vs= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.0.0 h1:nBy98uKOIfun5z6wx6jwWLrULcM0+cjBalBFZlEZ7CA= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.0.0/go.mod h1:243D9iHbcQXoFUtgHJwL7gl2zx1aDuDMjvBZVGr2uW0= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0 h1:ECsQtyERDVz3NP3kvDOTLvbQhqWp/x9EsGKtb4ogUr8= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0/go.mod h1:s1tW/At+xHqjNFvWU4G0c0Qv33KOhvbGNj0RCTQDV8s= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 h1:H5xDQaE3XowWfhZRUpnfC+rGZMEVoSiji+b+/HFAPU4= github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= @@ -28,34 +38,6 @@ github.com/agnivade/levenshtein v1.2.0 h1:U9L4IOT0Y3i0TIlUIDJ7rVUziKi/zPbrJGaFrt github.com/agnivade/levenshtein v1.2.0/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/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM= -github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= -github.com/aws/aws-sdk-go-v2/config v1.29.9 h1:Kg+fAYNaJeGXp1vmjtidss8O2uXIsXwaRqsQJKXVr+0= -github.com/aws/aws-sdk-go-v2/config v1.29.9/go.mod h1:oU3jj2O53kgOU4TXq/yipt6ryiooYjlkqqVaZk7gY/U= -github.com/aws/aws-sdk-go-v2/credentials v1.17.62 h1:fvtQY3zFzYJ9CfixuAQ96IxDrBajbBWGqjNTCa79ocU= -github.com/aws/aws-sdk-go-v2/credentials v1.17.62/go.mod h1:ElETBxIQqcxej++Cs8GyPBbgMys5DgQPTwo7cUPDKt8= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.209.0 h1:WpLv8X3/Ct0ZRvx8QL91V9ndnIOi1WDfz0+F4ZEKwns= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.209.0/go.mod h1:ouvGEfHbLaIlWwpDpOVWPWR+YwO0HDv3vm5tYLq8ImY= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 h1:8JdC7Gr9NROg1Rusk25IcZeTO59zLxsKgE0gkh5O6h0= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.1/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1 h1:KwuLovgQPcdjNMfFt9OhUd9a2OwcOKhxfvF4glTzLuA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 h1:PZV5W8yk4OtH1JAuhV2PXwwO9v5G5Aoj+eMCn4T+1Kc= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.17/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4= -github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= -github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= @@ -68,16 +50,10 @@ 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/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.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/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.24 h1:zxszGrGjrra1yYJW/6rhm9cJ1ZQ8rkKBR48brqsa7nA= -github.com/containerd/containerd v1.7.24/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw= +github.com/compliance-framework/agent v0.2.0 h1:cnX0w/HLFpCwxIQWzPBMiqvfsqDrRT5K3umPDQPLO30= +github.com/compliance-framework/agent v0.2.0/go.mod h1:K9tKkawU6Bp0xmtcCsHRL29tj0eJQRtK4lFbq7ALzKs= +github.com/compliance-framework/configuration-service v0.2.12-0.20250708103936-23c66564a854 h1:SJnaFykNrKhH1SpJhufQSghI0EmtF2P89K9hyFsLpqo= +github.com/compliance-framework/configuration-service v0.2.12-0.20250708103936-23c66564a854/go.mod h1:iLh9bNKJHRIk2OrfpcoEz3VuX+rXyo7PA3Qh/pxeWLg= 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= @@ -94,18 +70,22 @@ github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0 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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= 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= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= -github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v28.0.1+incompatible h1:FCHjSRdXhNRFjlHMTv4jUNlIBbTeRjrWfeFuJp7jpo0= +github.com/docker/docker v28.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 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/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I= +github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= 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= @@ -115,6 +95,8 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI= github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= @@ -142,15 +124,16 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg= github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus= -github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= -github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk= +github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= -github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= -github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= 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= @@ -162,8 +145,8 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW 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/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= @@ -176,10 +159,24 @@ github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8Ei 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/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= +github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= +github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= 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/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -196,8 +193,8 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= -github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= -github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 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= @@ -223,8 +220,6 @@ github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= -github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= -github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= 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= @@ -235,8 +230,10 @@ github.com/open-policy-agent/opa v1.0.0 h1:fZsEwxg1knpPvUn0YDJuJZBcbVg4G3zKpWa3+ github.com/open-policy-agent/opa v1.0.0/go.mod h1:+JyoH12I0+zqyC1iX7a2tmoQlipwAEGvOhVJMhmy+rM= 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= -github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -256,19 +253,33 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= 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/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= +github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= -github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4= -github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= -github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= -github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= +github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= +github.com/shirou/gopsutil/v4 v4.25.1 h1:QSWkTc+fu9LTAWfkZwZ6j8MSUk4A2LV7rbH0ZqmLjXs= +github.com/shirou/gopsutil/v4 v4.25.1/go.mod h1:RoUCUpndaJFtT+2zsZzzmhvbfGoDCJ7nFXKJf8GqJbI= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= +github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= +github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/swaggo/echo-swagger v1.4.1 h1:Yf0uPaJWp1uRtDloZALyLnvdBeoEL5Kc7DtnjzO/TUk= github.com/swaggo/echo-swagger v1.4.1/go.mod h1:C8bSi+9yH2FLZsnhqMZLIZddpUxZdBYuNHbtaS1Hljc= github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw= @@ -277,8 +288,10 @@ 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/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/testcontainers/testcontainers-go v0.37.0 h1:L2Qc0vkTw2EHWQ08djon0D2uw7Z/PtHS/QzZZ5Ra/hg= +github.com/testcontainers/testcontainers-go v0.37.0/go.mod h1:QPzbxZhQ6Bclip9igjLFj6z0hs01bU8lrl2dHQmgFGM= +github.com/testcontainers/testcontainers-go/modules/postgres v0.37.0 h1:hsVwFkS6s+79MbKEO+W7A1wNIw1fmkMtF4fg83m6kbc= +github.com/testcontainers/testcontainers-go/modules/postgres v0.37.0/go.mod h1:Qj/eGbRbO/rEYdcRLmN+bEojzatP/+NS1y8ojl2PQsc= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= @@ -287,62 +300,48 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= -github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= -github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= -github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/yashtewari/glob-intersection v0.2.0 h1:8iuHdN88yYuCzCdjt0gDe+6bAhUwBeEWqThExu54RFg= github.com/yashtewari/glob-intersection v0.2.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok= -github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= -github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= -github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= -github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM= -go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= 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 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.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/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.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/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.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= 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.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= 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/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -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.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.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= @@ -352,26 +351,22 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/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/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.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/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= 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/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/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 h1:TqExAhdPaB60Ux47Cn0oLV07rGnxZzIsaRhQaqS666A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= 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/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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= @@ -380,5 +375,15 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/datatypes v1.2.5 h1:9UogU3jkydFVW1bIVVeoYsTpLRgwDVW3rHfJG6/Ek9I= +gorm.io/datatypes v1.2.5/go.mod h1:I5FUdlKpLb5PMqeMQhm30CQ6jXP8Rj89xkTeCSAaAD4= +gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8= +gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM= +gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/main.go b/main.go index 69c9a7f..ddd0c0a 100644 --- a/main.go +++ b/main.go @@ -4,22 +4,18 @@ import ( "context" "errors" "fmt" - "os" - "time" - - "github.com/compliance-framework/plugin-azure-vms/internal" + "iter" + "slices" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute" - "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork" + 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" - "github.com/google/uuid" + "github.com/compliance-framework/plugin-azure-vms/internal" "github.com/hashicorp/go-hclog" goplugin "github.com/hashicorp/go-plugin" - "google.golang.org/protobuf/types/known/timestamppb" ) type CompliancePlugin struct { @@ -27,6 +23,24 @@ type CompliancePlugin struct { config map[string]string } +type AzureVMInstance struct { + Instance *armcompute.VirtualMachine `json:"instance"` +} + +func (i *AzureVMInstance) ID() string { + if i.Instance == nil || i.Instance.ID == nil { + return "" + } + return *i.Instance.ID +} + +func (i *AzureVMInstance) Name() string { + if i.Instance == nil || i.Instance.Name == nil { + return "" + } + return *i.Instance.Name +} + type Tag struct { Key string `json:"Key"` Value string `json:"Value"` @@ -38,453 +52,191 @@ func (l *CompliancePlugin) Configure(req *proto.ConfigureRequest) (*proto.Config } func (l *CompliancePlugin) Eval(request *proto.EvalRequest, apiHelper runner.ApiHelper) (*proto.EvalResponse, error) { + l.logger.Debug("Eval called with request", "request", request) ctx := context.TODO() - startTime := time.Now() evalStatus := proto.ExecutionStatus_SUCCESS var accumulatedErrors error + activities := make([]*proto.Activity, 0) + activities = append(activities, &proto.Activity{ + Title: "Collect Azure VM configurations", + Description: "Collect Azure VM configurations using the Azure SDK for Go.", + Steps: []*proto.Step{ + { + Title: "Initialize Azure SDK", + Description: "Initialize the Azure SDK with the provided credentials and subscription ID.", + }, + { + Title: "List Azure VMs", + Description: "List all Azure VMs in the specified subscription.", + }, + }, + }) + + // create credential service for azure cred, err := azidentity.NewDefaultAzureCredential(nil) if err != nil { l.logger.Error("unable to get Azure credentials", "error", err) - evalStatus = proto.ExecutionStatus_FAILURE - accumulatedErrors = errors.Join(accumulatedErrors, err) + return &proto.EvalResponse{ + Status: proto.ExecutionStatus_FAILURE, + }, err } - client, err := armcompute.NewVirtualMachinesClient(os.Getenv("AZURE_SUBSCRIPTION_ID"), cred, nil) + vmClient, err := armcompute.NewVirtualMachinesClient(l.config["subscription_id"], cred, nil) if err != nil { l.logger.Error("unable to create Azure VM client", "error", err) - evalStatus = proto.ExecutionStatus_FAILURE - accumulatedErrors = errors.Join(accumulatedErrors, err) + return &proto.EvalResponse{ + Status: proto.ExecutionStatus_FAILURE, + }, err } - // Get VM instances - pager := client.NewListAllPager(nil) - var vmInstances []map[string]interface{} - for pager.More() { - page, err := pager.NextPage(ctx) + for vm, err := range l.GetVMs(ctx, vmClient) { if err != nil { - l.logger.Error("unable to list VM instances", "error", err) - evalStatus = proto.ExecutionStatus_FAILURE + l.logger.Error("Error getting VM", "error", err) accumulatedErrors = errors.Join(accumulatedErrors, err) + evalStatus = proto.ExecutionStatus_FAILURE break } - // Parse VM instances - for _, vm := range page.Value { - var tags []Tag - for key, value := range vm.Tags { - tags = append(tags, Tag{Key: key, Value: *value}) - } - - // Extract networking details - networkDetails := map[string]interface{}{ - "publicIPAddress": nil, - "privateIPAddress": nil, - "virtualNetwork": nil, - "dnsName": nil, - "securityGroup": nil, - } - if vm.Properties.NetworkProfile != nil { - for _, nic := range vm.Properties.NetworkProfile.NetworkInterfaces { - nicClient, err := armnetwork.NewInterfacesClient(os.Getenv("AZURE_SUBSCRIPTION_ID"), cred, nil) - if err != nil { - l.logger.Error("unable to create NIC client", "error", err) - evalStatus = proto.ExecutionStatus_FAILURE - accumulatedErrors = errors.Join(accumulatedErrors, err) - break - } - - // Extract resource group and NIC name from NIC ID - nicIDParts, parseErr := internal.ParseAzureResourceID(*nic.ID) - if parseErr != nil { - l.logger.Error("unable to parse NIC ID", "nicID", *nic.ID, "error", parseErr) - evalStatus = proto.ExecutionStatus_FAILURE - accumulatedErrors = errors.Join(accumulatedErrors, parseErr) - break - } - - resourceGroup, ok := nicIDParts["resourceGroups"] - if !ok { - err := errors.New("resource group not found in NIC ID") - l.logger.Error("unable to extract resource group from NIC ID", "nicID", *nic.ID, "error", err) - evalStatus = proto.ExecutionStatus_FAILURE - accumulatedErrors = errors.Join(accumulatedErrors, err) - break - } - - nicName, ok := nicIDParts["networkInterfaces"] - if !ok { - err := errors.New("NIC name not found in NIC ID") - l.logger.Error("unable to extract NIC name from NIC ID", "nicID", *nic.ID, "error", err) - evalStatus = proto.ExecutionStatus_FAILURE - accumulatedErrors = errors.Join(accumulatedErrors, err) - break - } - - nicResp, err := nicClient.Get(ctx, resourceGroup, nicName, nil) - if err != nil { - l.logger.Error("unable to get NIC details", "resourceGroup", resourceGroup, "nicName", nicName, "error", err) - evalStatus = proto.ExecutionStatus_FAILURE - accumulatedErrors = errors.Join(accumulatedErrors, err) - break - } - - if nicResp.Properties != nil { - if nicResp.Properties.IPConfigurations != nil { - for _, ipConfig := range nicResp.Properties.IPConfigurations { - if ipConfig.Properties != nil { - if ipConfig.Properties.PrivateIPAddress != nil { - networkDetails["privateIPAddress"] = *ipConfig.Properties.PrivateIPAddress - } - if ipConfig.Properties.PublicIPAddress != nil { - publicIPClient, err := armnetwork.NewPublicIPAddressesClient(os.Getenv("AZURE_SUBSCRIPTION_ID"), cred, nil) - if err != nil { - l.logger.Error("unable to create Public IP client", "error", err) - evalStatus = proto.ExecutionStatus_FAILURE - accumulatedErrors = errors.Join(accumulatedErrors, err) - break - } - - // Extract resource group and public IP name from Public IP ID - publicIPIDParts, parseErr := internal.ParseAzureResourceID(*ipConfig.Properties.PublicIPAddress.ID) - if parseErr != nil { - l.logger.Error("unable to parse Public IP ID", "publicIPID", *ipConfig.Properties.PublicIPAddress.ID, "error", parseErr) - evalStatus = proto.ExecutionStatus_FAILURE - accumulatedErrors = errors.Join(accumulatedErrors, parseErr) - break - } - publicIPResourceGroup := publicIPIDParts["resourceGroups"] - publicIPName := publicIPIDParts["publicIPAddresses"] - - publicIPResp, err := publicIPClient.Get(ctx, publicIPResourceGroup, publicIPName, nil) - if err != nil { - l.logger.Error("unable to get Public IP details", "error", err) - evalStatus = proto.ExecutionStatus_FAILURE - accumulatedErrors = errors.Join(accumulatedErrors, err) - break - } - - if publicIPResp.Properties != nil && publicIPResp.Properties.IPAddress != nil { - networkDetails["publicIPAddress"] = *publicIPResp.Properties.IPAddress - } - } - } - } - } - if nicResp.Properties.DNSSettings != nil && nicResp.Properties.DNSSettings.InternalDomainNameSuffix != nil { - networkDetails["dnsName"] = *nicResp.Properties.DNSSettings.InternalDomainNameSuffix - } - if nicResp.Properties.NetworkSecurityGroup != nil { - securityGroupClient, err := armnetwork.NewSecurityGroupsClient(os.Getenv("AZURE_SUBSCRIPTION_ID"), cred, nil) - if err != nil { - l.logger.Error("unable to create Security Group client", "error", err) - evalStatus = proto.ExecutionStatus_FAILURE - accumulatedErrors = errors.Join(accumulatedErrors, err) - break - } - - // Extract resource group and security group name from Security Group ID - securityGroupIDParts, parseErr := internal.ParseAzureResourceID(*nicResp.Properties.NetworkSecurityGroup.ID) - if parseErr != nil { - l.logger.Error("unable to parse Security Group ID", "securityGroupID", *nicResp.Properties.NetworkSecurityGroup.ID, "error", parseErr) - evalStatus = proto.ExecutionStatus_FAILURE - accumulatedErrors = errors.Join(accumulatedErrors, parseErr) - break - } - securityGroupResourceGroup := securityGroupIDParts["resourceGroups"] - securityGroupName := securityGroupIDParts["networkSecurityGroups"] - - securityGroupResp, err := securityGroupClient.Get(ctx, securityGroupResourceGroup, securityGroupName, nil) - if err != nil { - l.logger.Error("unable to get Security Group details", "error", err) - evalStatus = proto.ExecutionStatus_FAILURE - accumulatedErrors = errors.Join(accumulatedErrors, err) - break - } - - if securityGroupResp.Properties != nil { - networkDetails["securityGroup"] = map[string]interface{}{ - "id": *nicResp.Properties.NetworkSecurityGroup.ID, - "rules": securityGroupResp.Properties.SecurityRules, - "defaultRules": securityGroupResp.Properties.DefaultSecurityRules, - } - } - } - } - } - } - - // Retrieve disk encryption settings - diskEncryptionSettings := map[string]interface{}{ - "osDisk": nil, - "dataDisks": nil, - } - if vm.Properties.StorageProfile != nil { - if vm.Properties.StorageProfile.OSDisk != nil && vm.Properties.StorageProfile.OSDisk.EncryptionSettings != nil { - diskEncryptionSettings["osDisk"] = vm.Properties.StorageProfile.OSDisk.EncryptionSettings - } - } - - // Retrieve disk details - diskDetails := map[string]interface{}{ - "osDiskName": nil, - "encryptionAtHost": nil, - "azureDiskEncryption": nil, - "ephemeralOSDisk": nil, - "dataDisksCount": 0, - } - if vm.Properties.StorageProfile != nil { - // OS Disk details - if vm.Properties.StorageProfile.OSDisk != nil { - diskDetails["osDiskName"] = vm.Properties.StorageProfile.OSDisk.Name - diskDetails["encryptionAtHost"] = vm.Properties.StorageProfile.OSDisk.EncryptionSettings != nil - diskDetails["azureDiskEncryption"] = vm.Properties.StorageProfile.OSDisk.ManagedDisk != nil && - vm.Properties.StorageProfile.OSDisk.ManagedDisk.DiskEncryptionSet != nil - if vm.Properties.StorageProfile.OSDisk.Caching != nil { - diskDetails["ephemeralOSDisk"] = *vm.Properties.StorageProfile.OSDisk.Caching == armcompute.CachingTypesReadWrite - } - } - - // Data Disks details - if vm.Properties.StorageProfile.DataDisks != nil { - diskDetails["dataDisksCount"] = len(vm.Properties.StorageProfile.DataDisks) - } - } - - properties := map[string]interface{}{ - "hardwareProfile": vm.Properties.HardwareProfile, - "storageProfile": vm.Properties.StorageProfile, - "osProfile": vm.Properties.OSProfile, - "networkProfile": vm.Properties.NetworkProfile, - "provisioningState": vm.Properties.ProvisioningState, - "networkDetails": networkDetails, - "diskEncryptionSettings": diskEncryptionSettings, - "diskDetails": diskDetails, - } + labels := map[string]string{ + "provider": "azure", + "type": "virtual-machine", + "instance-id": vm.ID(), + } - subjectAttributeMap := map[string]string{ - "type": "azure", - "service": "virtual-machine", - "instance-id": *vm.ID, - "instance-name": *vm.Name, - } - subjects := []*proto.SubjectReference{ - { - Type: "azure-virtual-machine", - Attributes: subjectAttributeMap, - Title: internal.StringAddressed("Azure Virtual Machine"), - Props: []*proto.Property{ - { - Name: "vm-id", - Value: *vm.ID, - }, - { - Name: "vm-name", - Value: *vm.Name, - }, + 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"), }, }, - } - 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"), - }, + }, + { + Title: "Continuous Compliance Framework - Azure VM Plugin", + Type: "tool", + Links: []*proto.Link{ + { + Href: "https://github.com/compliance-framework/plugin-azure-vms", + Rel: internal.StringAddressed("reference"), + Text: internal.StringAddressed("The Continuous Compliance Framework' Azure VM Plugin"), }, }, - { - Title: "Continuous Compliance Framework - Local SSH Plugin", - Type: "tool", - Links: []*proto.Link{ - { - Href: "https://github.com/compliance-framework/plugin-local-ssh", - Rel: internal.StringAddressed("reference"), - Text: internal.StringAddressed("The Continuous Compliance Framework' Local SSH Plugin"), - }, + }, + } + + compoents := []*proto.Component{ + { + Identifier: "common-components/azure-virtual-machine", + Type: "service", + Title: "Azure Virtual Machine", + Description: "An Azure Virtual Machine (VM) is a scalable compute resource that runs on the Azure cloud platform.", + Purpose: "Virtual compute infrastructure for compute based applications", + }, + } + + inventory := []*proto.InventoryItem{ + { + Identifier: "azure-vm/" + vm.ID(), + Type: "virtual-machine", + Title: fmt.Sprintf("Azure VM [%s]", vm.ID()), + Props: []*proto.Property{ + { + Name: "vm-id", + Value: vm.ID(), + }, + { + Name: "vm-name", + Value: vm.Name(), }, }, - } - components := []*proto.ComponentReference{ - { - Identifier: "common-components/azure-virtual-machine", - }, - } - - activities := make([]*proto.Activity, 0) - findings := make([]*proto.Finding, 0) - observations := make([]*proto.Observation, 0) - - for _, policyPath := range request.GetPolicyPaths() { - // Explicitly reset steps to make things readable - 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 SSH configuration, execute the compiled policies", - }) - activities = append(activities, &proto.Activity{ - Title: "Execute policy", - Description: "Prepare and compile policy bundles, and execute them using the prepared SSH configuration data", - Steps: steps, - }) - results, err := policyManager.New(ctx, l.logger, policyPath).Execute(ctx, "compliance_plugin", map[string]interface{}{ - "VMID": *vm.ID, - "Location": *vm.Location, - "Name": *vm.Name, - "Properties": properties, - "Tags": tags, - "Type": *vm.Type, - "HardwareProfile": vm.Properties.HardwareProfile, - "StorageProfile": vm.Properties.StorageProfile, - "OSProfile": vm.Properties.OSProfile, - "NetworkProfile": vm.Properties.NetworkProfile, - "ProvisioningState": vm.Properties.ProvisioningState, - }) - if err != nil { - l.logger.Error("policy evaluation failed", "error", err) - evalStatus = proto.ExecutionStatus_FAILURE - accumulatedErrors = errors.Join(accumulatedErrors, err) - continue - } + }, + } - 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{ - "type": "observation", - "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 - } - - // 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{ - "type": "finding", - "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 - } - - 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 Azure Security Group configuration, using the Azure Security Group Compliance Plugin", result.Policy.Package.PurePackage()), - }, - }, - } - - newFinding := func() *proto.Finding { - return &proto.Finding{ - ID: uuid.New().String(), - UUID: findingUUID.String(), - Collected: timestamppb.New(time.Now()), - Labels: map[string]string{ - "type": "azure", - "service": "virtual-machine", - "instance-id": *vm.ID, - "instance-name": *vm.Name, - "_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, - } - } - - // There are no violations reported from the policies. - // We'll send the observation back to the agent - if len(result.Violations) == 0 { - - observation.Title = internal.StringAddressed("The plugin succeeded. No compliance issues to report.") - observation.Description = "The plugin policies did not return any violations. The configuration is in compliance with policies." - observations = append(observations, &observation) - - finding := newFinding() - finding.Title = fmt.Sprintf("No violations found on %s", result.Policy.Package.PurePackage()) - finding.Description = fmt.Sprintf("No violations were found on the %s policy within the Azure Security Groups Compliance Plugin.", result.Policy.Package.PurePackage()) - finding.Status = &proto.FindingStatus{ - State: runner.FindingTargetStatusSatisfied, - } - findings = append(findings, finding) - continue - } - - // There are violations in the policy checks. - // We'll send these observations back to the agent - if len(result.Violations) > 0 { - 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 Azure Security groups 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) - } - } - } + subjects := []*proto.Subject{ + { + Type: proto.SubjectType_SUBJECT_TYPE_COMPONENT, + Identifier: "common-components/azure-virtual-machine", + }, + { + Type: proto.SubjectType_SUBJECT_TYPE_INVENTORY_ITEM, + Identifier: "azure-vm/" + vm.ID(), + }, + } - } - 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 - } + evidences := make([]*proto.Evidence, 0) + for _, policyPath := range request.GetPolicyPaths() { - 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 + processor := policyManager.NewPolicyProcessor( + l.logger, + internal.MergeMaps( + labels, + map[string]string{ + "_policy_path": policyPath, + }, + ), + subjects, + compoents, + inventory, + actors, + activities, + ) + + evidence, err := processor.GenerateResults(ctx, policyPath, vm) + evidences = slices.Concat(evidences, evidence) + + if err != nil { + l.logger.Error("Error processing policy", "error", err, "policyPath", policyPath, "vm_id", vm.ID()) + accumulatedErrors = errors.Join(accumulatedErrors, err) } + } + if err = apiHelper.CreateEvidence(ctx, evidences); err != nil { + l.logger.Error("Failed to send evidences", "error", err) + evalStatus = proto.ExecutionStatus_FAILURE + accumulatedErrors = errors.Join(accumulatedErrors, err) + continue } } - l.logger.Debug("evaluating data", vmInstances) + // For now, we will just return a success response. return &proto.EvalResponse{ Status: evalStatus, }, accumulatedErrors } +func (l *CompliancePlugin) GetVMs(ctx context.Context, client *armcompute.VirtualMachinesClient) iter.Seq2[*AzureVMInstance, error] { + + return func(yield func(*AzureVMInstance, error) bool) { + l.logger.Debug("Getting Azure Virtual Machines") + + pager := client.NewListAllPager(nil) + + for pager.More() { + page, err := pager.NextPage(ctx) + if err != nil { + l.logger.Error("unable to list VM instances", "error", err) + yield(nil, err) + return + } + + for _, vm := range page.Value { + azureInstance := &AzureVMInstance{ + Instance: vm, + } + if !yield(azureInstance, nil) { + return + } + } + } + } + +} + func main() { logger := hclog.New(&hclog.LoggerOptions{ Level: hclog.Debug, From cd78bfacc4ae92dc3d712754ecea80382459e2f2 Mon Sep 17 00:00:00 2001 From: Sam Sherar Date: Fri, 11 Jul 2025 15:25:40 +0100 Subject: [PATCH 2/6] Add network configuration to the rego data --- go.mod | 1 + main.go | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 121 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 2361ce8..aeb95a3 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.23.2 require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute v1.0.0 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.0.0 github.com/compliance-framework/agent v0.2.0 github.com/hashicorp/go-hclog v1.5.0 github.com/hashicorp/go-plugin v1.6.2 diff --git a/main.go b/main.go index ddd0c0a..c302366 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork" policyManager "github.com/compliance-framework/agent/policy-manager" "github.com/compliance-framework/agent/runner" @@ -19,12 +20,14 @@ import ( ) type CompliancePlugin struct { - logger hclog.Logger - config map[string]string + logger hclog.Logger + config map[string]string + azureCredentials *azidentity.DefaultAzureCredential } type AzureVMInstance struct { - Instance *armcompute.VirtualMachine `json:"instance"` + Instance *armcompute.VirtualMachine `json:"instance"` + NetworkInterfaces []*AzureVMNetworkInterface `json:"network_interfaces"` } func (i *AzureVMInstance) ID() string { @@ -41,6 +44,12 @@ func (i *AzureVMInstance) Name() string { return *i.Instance.Name } +type AzureVMNetworkInterface struct { + Config *armnetwork.InterfacesClientGetResponse `json:"config"` + PublicIPs []*armnetwork.PublicIPAddressesClientGetResponse `json:"public_ips,omitempty"` + SecurityGroup *armnetwork.SecurityGroupsClientGetResponse `json:"security_group,omitempty"` +} + type Tag struct { Key string `json:"Key"` Value string `json:"Value"` @@ -70,19 +79,32 @@ func (l *CompliancePlugin) Eval(request *proto.EvalRequest, apiHelper runner.Api Title: "List Azure VMs", Description: "List all Azure VMs in the specified subscription.", }, + { + Title: "Get Attached Network Interfaces", + Description: "For each VM, retrieve the attached network interfaces and their details.", + }, + { + Title: "Get Public IP Addresses", + Description: "For each network interface, retrieve the associated public IP addresses.", + }, + { + Title: "Get Attached Security Groups", + Description: "For each network interface, retrieve the associated security groups and their rules.", + }, }, }) // create credential service for azure - cred, err := azidentity.NewDefaultAzureCredential(nil) + creds, err := azidentity.NewDefaultAzureCredential(nil) if err != nil { l.logger.Error("unable to get Azure credentials", "error", err) return &proto.EvalResponse{ Status: proto.ExecutionStatus_FAILURE, }, err } + l.azureCredentials = creds - vmClient, err := armcompute.NewVirtualMachinesClient(l.config["subscription_id"], cred, nil) + vmClient, err := armcompute.NewVirtualMachinesClient(l.config["subscription_id"], l.azureCredentials, nil) if err != nil { l.logger.Error("unable to create Azure VM client", "error", err) return &proto.EvalResponse{ @@ -228,6 +250,16 @@ func (l *CompliancePlugin) GetVMs(ctx context.Context, client *armcompute.Virtua azureInstance := &AzureVMInstance{ Instance: vm, } + if vm.Properties.NetworkProfile != nil { + config, err := l.GetNetworkConfig(ctx, vm.Properties.NetworkProfile) + if err != nil { + l.logger.Error("unable to get network interfaces", "error", err) + yield(nil, err) + return + } + azureInstance.NetworkInterfaces = config + } + if !yield(azureInstance, nil) { return } @@ -237,6 +269,89 @@ func (l *CompliancePlugin) GetVMs(ctx context.Context, client *armcompute.Virtua } +func (l *CompliancePlugin) GetNetworkConfig(ctx context.Context, networkProfile *armcompute.NetworkProfile) ([]*AzureVMNetworkInterface, error) { + l.logger.Debug("Getting network configuration for Azure VM") + nicClient, err := armnetwork.NewInterfacesClient(l.config["subscription_id"], l.azureCredentials, nil) + networkInterfaces := make([]*AzureVMNetworkInterface, len(networkProfile.NetworkInterfaces)) + + if err != nil { + l.logger.Error("unable to create Azure NIC client", "error", err) + return nil, err + } + + for i, nicRef := range networkProfile.NetworkInterfaces { + nicInterface := &AzureVMNetworkInterface{ + PublicIPs: make([]*armnetwork.PublicIPAddressesClientGetResponse, 0), + } + + nicParts, err := internal.ParseAzureResourceID(*nicRef.ID) + if err != nil { + l.logger.Error("unable to parse NIC ID", "error", err, "nic_id", *nicRef.ID) + return nil, err + } + + resp, err := nicClient.Get(ctx, nicParts["resourceGroups"], nicParts["networkInterfaces"], nil) + if err != nil { + l.logger.Error("unable to get NIC details", "error", err, "nic_id", *nicRef.ID) + return nil, err + } + + nicInterface.Config = &resp + + if resp.Properties.IPConfigurations != nil { + for _, ipConfig := range resp.Properties.IPConfigurations { + if ipConfig.Properties.PublicIPAddress != nil && ipConfig.Properties.PublicIPAddress.ID != nil { + l.logger.Debug("Found Public IP configuration", "nic_id", *nicRef.ID, "ip_config_id", *ipConfig.ID, "public_ip_id", *ipConfig.Properties.PublicIPAddress.ID) + ipParts, err := internal.ParseAzureResourceID(*ipConfig.Properties.PublicIPAddress.ID) + if err != nil { + l.logger.Error("unable to parse Public IP ID", "error", err, "public_ip_id", *ipConfig.Properties.PublicIPAddress.ID) + return nil, err + } + + publicIPClient, err := armnetwork.NewPublicIPAddressesClient(l.config["subscription_id"], l.azureCredentials, nil) + if err != nil { + l.logger.Error("unable to create Azure Public IP client", "error", err) + return nil, err + } + + publicIPResp, err := publicIPClient.Get(ctx, ipParts["resourceGroups"], ipParts["publicIPAddresses"], nil) + if err != nil { + l.logger.Error("unable to get Public IP details", "error", err, "public_ip_id", *ipConfig.Properties.PublicIPAddress.ID) + return nil, err + } + l.logger.Debug("Found Public IP", "public_ip_id", *ipConfig.Properties.PublicIPAddress.ID, "ip_address", *publicIPResp.Properties.IPAddress) + nicInterface.PublicIPs = append(nicInterface.PublicIPs, &publicIPResp) + } + } + } + + if resp.Properties.NetworkSecurityGroup != nil && resp.Properties.NetworkSecurityGroup.ID != nil { + sgParts, err := internal.ParseAzureResourceID(*resp.Properties.NetworkSecurityGroup.ID) + if err != nil { + l.logger.Error("unable to parse Network Security Group ID", "error", err, "nsg_id", *resp.Properties.NetworkSecurityGroup.ID) + return nil, err + } + + securityGroupClient, err := armnetwork.NewSecurityGroupsClient(l.config["subscription_id"], l.azureCredentials, nil) + if err != nil { + l.logger.Error("unable to create Azure Security Group client", "error", err) + return nil, err + } + + securityGroupResp, err := securityGroupClient.Get(ctx, sgParts["resourceGroups"], sgParts["networkSecurityGroups"], nil) + if err != nil { + l.logger.Error("unable to get Network Security Group details", "error", err, "nsg_id", *resp.Properties.NetworkSecurityGroup.ID) + return nil, err + } + nicInterface.SecurityGroup = &securityGroupResp + + } + + networkInterfaces[i] = nicInterface + } + return networkInterfaces, nil +} + func main() { logger := hclog.New(&hclog.LoggerOptions{ Level: hclog.Debug, From 59c77ca5ff3de2f47f59ec81422851f7024b2f9d Mon Sep 17 00:00:00 2001 From: Sam Sherar Date: Fri, 11 Jul 2025 15:43:47 +0100 Subject: [PATCH 3/6] Update readme with req'd information --- README.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index af26d5f..a22079a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,50 @@ # Plugin Azure VM -## Assumptions +## Configuration -- That the agent running this plugin has access to the classic Azure env vars in order to use SDK methods -- There is a set of policies specfically scoped to Azure that the config in the agent is pointing to -- Ensure you set AZURE_SUBSCRIPTION_ID as an env var before you run the agent +> [!NOTE] +> Requires the typical Azure credentials to be set in your environment for the client to work. This can either be set manually or using the `az` tool + +| Name | Environment Variable | Required | Description | +| --- | --- |:---:| --- | +| `subscription_id` | `$CCF_PLUGINS_AZURE_CONFIG_SUBSCRIPTION_ID` | ✅ | Subscription ID for the Azure instance | + +## Building the plugin + +```shell +$ mkdir -p dist +$ go build -o dist/plugin main.go +``` + +## Data structure passed to the policy manager + +The plugin does not do any manipulation of the structures provided back from `azure-go-sdk`, so anything that is passed back can be queried in rego. However, due to the linked nature of azure with IDs through the API, the plugin saturates the data that is passed back and places them in a wrapper around structures. + +The golang definition can be found below: + +```golang +type AzureVMInstance struct { + Instance *armcompute.VirtualMachine `json:"instance"` + NetworkInterfaces []*AzureVMNetworkInterface `json:"network_interfaces"` +} + +type AzureVMNetworkInterface struct { + Config *armnetwork.InterfacesClientGetResponse `json:"config"` + PublicIPs []*armnetwork.PublicIPAddressesClientGetResponse `json:"public_ips,omitempty"` + SecurityGroup *armnetwork.SecurityGroupsClientGetResponse `json:"security_group,omitempty"` +} +``` + +To see what data is available, the recommendation is to look at the golang documentation for the different types: + +* [`armcompute.VirtualMachine`](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/arm/compute#VirtualMachine) +* [`armnetwork.InterfacesClientGetResponse`](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v7#InterfacesClientGetResponse) +* [`armnetwork.PublicIPAddressesClientGetResponse`](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v7#PublicIPAddressesClientGetResponse) +* [`armnetwork.SecurityGroupsClientGetResponse`](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v7#SecurityGroupsClientGetResponse) + +To see the data in action, have a look at the unit tests found in the [policies repo](https://github.com/compliance-framework/plugin-azure-vm-policies/tree/main/policies) + + +## Licence + +[AGPL v3](./LICENSE) \ No newline at end of file From 286d69d55626b3fedcd38a2b9ff544f62f7a49f5 Mon Sep 17 00:00:00 2001 From: Sam Sherar Date: Fri, 11 Jul 2025 16:11:09 +0100 Subject: [PATCH 4/6] Minor bug fixes * Change slices.Concat to append(...) * Add more labels from the VM for better searching * Spelling mistake in the actors description --- main.go | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/main.go b/main.go index c302366..cd6bc2f 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "iter" - "slices" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute" @@ -120,10 +119,21 @@ func (l *CompliancePlugin) Eval(request *proto.EvalRequest, apiHelper runner.Api break } + idParts, err := internal.ParseAzureResourceID(vm.ID()) + if err != nil { + l.logger.Error("unable to parse VM ID", "error", err, "vm_id", vm.ID()) + accumulatedErrors = errors.Join(accumulatedErrors, err) + evalStatus = proto.ExecutionStatus_FAILURE + break + } + labels := map[string]string{ - "provider": "azure", - "type": "virtual-machine", - "instance-id": vm.ID(), + "provider": "azure", + "type": "virtual-machine", + "instance-id": vm.ID(), + "resource-group": idParts["resourceGroups"], + "location": *vm.Instance.Location, + "subscription-id": idParts["subscriptions"], } actors := []*proto.OriginActor{ @@ -145,7 +155,7 @@ func (l *CompliancePlugin) Eval(request *proto.EvalRequest, apiHelper runner.Api { Href: "https://github.com/compliance-framework/plugin-azure-vms", Rel: internal.StringAddressed("reference"), - Text: internal.StringAddressed("The Continuous Compliance Framework' Azure VM Plugin"), + Text: internal.StringAddressed("The Continuous Compliance Framework's Azure VM Plugin"), }, }, }, @@ -209,7 +219,7 @@ func (l *CompliancePlugin) Eval(request *proto.EvalRequest, apiHelper runner.Api ) evidence, err := processor.GenerateResults(ctx, policyPath, vm) - evidences = slices.Concat(evidences, evidence) + evidences = append(evidences, evidence...) if err != nil { l.logger.Error("Error processing policy", "error", err, "policyPath", policyPath, "vm_id", vm.ID()) From c65f665c9d3bb2d1cdc64cc6c1ebf10a4324c2e1 Mon Sep 17 00:00:00 2001 From: Sam Sherar Date: Fri, 11 Jul 2025 16:58:39 +0100 Subject: [PATCH 5/6] Fix comments from PR --- main.go | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/main.go b/main.go index cd6bc2f..1b20c58 100644 --- a/main.go +++ b/main.go @@ -161,7 +161,7 @@ func (l *CompliancePlugin) Eval(request *proto.EvalRequest, apiHelper runner.Api }, } - compoents := []*proto.Component{ + components := []*proto.Component{ { Identifier: "common-components/azure-virtual-machine", Type: "service", @@ -205,14 +205,9 @@ func (l *CompliancePlugin) Eval(request *proto.EvalRequest, apiHelper runner.Api processor := policyManager.NewPolicyProcessor( l.logger, - internal.MergeMaps( - labels, - map[string]string{ - "_policy_path": policyPath, - }, - ), + labels, subjects, - compoents, + components, inventory, actors, activities, From ac5ab34a1313dc23fd63a949f1150a9d211231b6 Mon Sep 17 00:00:00 2001 From: Sam Sherar Date: Fri, 11 Jul 2025 21:20:09 +0100 Subject: [PATCH 6/6] virtual-server -> web-server --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 1b20c58..0c9d3be 100644 --- a/main.go +++ b/main.go @@ -174,7 +174,7 @@ func (l *CompliancePlugin) Eval(request *proto.EvalRequest, apiHelper runner.Api inventory := []*proto.InventoryItem{ { Identifier: "azure-vm/" + vm.ID(), - Type: "virtual-machine", + Type: "web-server", Title: fmt.Sprintf("Azure VM [%s]", vm.ID()), Props: []*proto.Property{ {