From 5542e63c62e3c4a296932ddeaa7e4a9ec7da57f1 Mon Sep 17 00:00:00 2001 From: Gustavo Carvalho Date: Tue, 5 May 2026 09:51:24 -0300 Subject: [PATCH 1/3] feat: add checks for ip whitelist feat: add checks for sso fix: use new configurations endpoint for dependabot and secret scanning Signed-off-by: Gustavo Carvalho --- internal/data.go | 178 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 174 insertions(+), 4 deletions(-) diff --git a/internal/data.go b/internal/data.go index 4d0869f..3cdc0cb 100644 --- a/internal/data.go +++ b/internal/data.go @@ -2,6 +2,8 @@ package internal import ( "context" + "fmt" + "net/http" policy_manager "github.com/compliance-framework/agent/policy-manager" @@ -10,9 +12,24 @@ import ( "github.com/hashicorp/go-hclog" ) +type OrgSSO struct { + Enabled bool `json:"enabled"` + SSOURL string `json:"sso_url"` + IDPIssuer string `json:"idp_issuer"` +} + +type IPAllowListEntry struct { + AllowListValue string `json:"allow_list_value"` + IsActive bool `json:"is_active"` + Name string `json:"name"` +} + type GithubData struct { - Settings *github.Organization `json:"settings"` - Teams []*github.Team `json:"teams"` + Settings *github.Organization `json:"settings"` + Teams []*github.Team `json:"teams"` + Members []*github.User `json:"members"` + SSO *OrgSSO `json:"sso"` + IPAllowList []IPAllowListEntry `json:"ip_allow_list"` } type DataFetcher struct { @@ -47,6 +64,24 @@ func (df DataFetcher) FetchData(ctx context.Context, organization string) (*Gith Remarks: policy_manager.Pointer("More information about data being sent back can be found here: https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#list-teams"), }) + steps = append(steps, &proto.Step{ + Title: "Get Admin Members", + Description: "Using the client's native APIs, list organization members with the owner/admin role", + Remarks: policy_manager.Pointer("More information about data being sent back can be found here: https://docs.github.com/en/rest/orgs/members?apiVersion=2022-11-28#list-organization-members"), + }) + + steps = append(steps, &proto.Step{ + Title: "Get SSO Configuration", + Description: "Fetches the SAML SSO configuration for the organization to verify identity provider enforcement", + Remarks: policy_manager.Pointer("More information: https://docs.github.com/en/rest/orgs/orgs?apiVersion=2022-11-28#get-an-organization"), + }) + + steps = append(steps, &proto.Step{ + Title: "Get IP Allow-List", + Description: "Fetches the IP allow-list entries for the organization via the GitHub GraphQL API", + Remarks: policy_manager.Pointer("More information: https://docs.github.com/en/graphql/reference/objects#ipallowlistentry"), + }) + org, _, err := df.client.Organizations.Get(ctx, organization) if err != nil { df.logger.Error("Error getting organization information", "org", organization, "error", err) @@ -70,8 +105,143 @@ func (df DataFetcher) FetchData(ctx context.Context, organization string) (*Gith paginationOpt.Page = resp.NextPage } + var allAdminMembers []*github.User + memberOpt := &github.ListMembersOptions{ + Role: "admin", + ListOptions: github.ListOptions{PerPage: 100}, + } + + for { + members, resp, err := df.client.Organizations.ListMembers(ctx, organization, memberOpt) + if err != nil { + df.logger.Error("Error getting admin members", "org", organization, "error", err) + return nil, nil, err + } + + allAdminMembers = append(allAdminMembers, members...) + if resp.NextPage == 0 { + break + } + memberOpt.Page = resp.NextPage + } + + ssoData, err := df.fetchSSO(ctx, organization) + if err != nil { + df.logger.Warn("Could not fetch SSO configuration; marking SSO as disabled", "org", organization, "error", err) + ssoData = &OrgSSO{Enabled: false} + } + + var ipAllowList []IPAllowListEntry + if org.Plan != nil && org.Plan.Name != nil && *org.Plan.Name == "enterprise" { + ipAllowList, err = df.fetchIPAllowList(ctx, organization) + if err != nil { + df.logger.Warn("Could not fetch IP allow-list; treating as empty", "org", organization, "error", err) + ipAllowList = []IPAllowListEntry{} + } + } else { + df.logger.Info("Skipping IP allow-list fetch: requires GitHub Enterprise Cloud", "org", organization, "plan", org.Plan) + ipAllowList = []IPAllowListEntry{} + } + return &GithubData{ - Settings: org, - Teams: allTeams, + Settings: org, + Teams: allTeams, + Members: allAdminMembers, + SSO: ssoData, + IPAllowList: ipAllowList, }, steps, nil } + +func (df DataFetcher) fetchSSO(ctx context.Context, organization string) (*OrgSSO, error) { + type samlIdentityProvider struct { + SSOURL string `json:"sso_url"` + Issuer string `json:"issuer"` + IDPCertID string `json:"idp_cert_fingerprint"` + } + type ssoResponse struct { + SAMLIdentityProvider *samlIdentityProvider `json:"saml_identity_provider"` + } + + url := fmt.Sprintf("https://api.github.com/orgs/%s/sso", organization) + req, err := df.client.NewRequest(http.MethodGet, url, nil) + if err != nil { + return nil, fmt.Errorf("building SSO request: %w", err) + } + + var ssoResp ssoResponse + httpResp, err := df.client.Do(ctx, req, &ssoResp) + if err != nil { + if httpResp != nil && httpResp.StatusCode == http.StatusNotFound { + return &OrgSSO{Enabled: false}, nil + } + return nil, fmt.Errorf("fetching SSO config: %w", err) + } + + if ssoResp.SAMLIdentityProvider == nil { + return &OrgSSO{Enabled: false}, nil + } + + return &OrgSSO{ + Enabled: true, + SSOURL: ssoResp.SAMLIdentityProvider.SSOURL, + IDPIssuer: ssoResp.SAMLIdentityProvider.Issuer, + }, nil +} + +func (df DataFetcher) fetchIPAllowList(ctx context.Context, organization string) ([]IPAllowListEntry, error) { + type graphqlRequest struct { + Query string `json:"query"` + } + type ipAllowListEntryNode struct { + AllowListValue string `json:"allowListValue"` + IsActive bool `json:"isActive"` + Name string `json:"name"` + } + type ipAllowListEdge struct { + Node ipAllowListEntryNode `json:"node"` + } + type ipAllowListConnection struct { + Edges []ipAllowListEdge `json:"edges"` + } + type orgNode struct { + IPAllowListEntries ipAllowListConnection `json:"ipAllowListEntries"` + } + type graphqlData struct { + Organization orgNode `json:"organization"` + } + type graphqlResponse struct { + Data graphqlData `json:"data"` + Errors []struct { + Message string `json:"message"` + } `json:"errors"` + } + + gqlQuery := graphqlRequest{ + Query: fmt.Sprintf(`{ organization(login: "%s") { ipAllowListEntries(first: 100) { edges { node { allowListValue isActive name } } } } }`, organization), + } + + req, err := df.client.NewRequest(http.MethodPost, "https://api.github.com/graphql", gqlQuery) + if err != nil { + return nil, fmt.Errorf("building IP allow-list GraphQL request: %w", err) + } + + var gqlResp graphqlResponse + _, err = df.client.Do(ctx, req, &gqlResp) + if err != nil { + return nil, fmt.Errorf("executing IP allow-list GraphQL query: %w", err) + } + + if len(gqlResp.Errors) > 0 { + return nil, fmt.Errorf("GraphQL error: %s", gqlResp.Errors[0].Message) + } + + entries := make([]IPAllowListEntry, 0, len(gqlResp.Data.Organization.IPAllowListEntries.Edges)) + for _, edge := range gqlResp.Data.Organization.IPAllowListEntries.Edges { + entries = append(entries, IPAllowListEntry{ + AllowListValue: edge.Node.AllowListValue, + IsActive: edge.Node.IsActive, + Name: edge.Node.Name, + }) + } + return entries, nil +} From e0fb5d75168cd122bd9b649e2bcd3848d7c08841 Mon Sep 17 00:00:00 2001 From: Gustavo Carvalho Date: Tue, 5 May 2026 11:11:43 -0300 Subject: [PATCH 2/3] fix: copilot issues Signed-off-by: Gustavo Carvalho --- internal/data.go | 109 ++++++++++++++++++++----------- internal/data_test.go | 146 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+), 38 deletions(-) create mode 100644 internal/data_test.go diff --git a/internal/data.go b/internal/data.go index 3cdc0cb..dcb9149 100644 --- a/internal/data.go +++ b/internal/data.go @@ -73,7 +73,7 @@ func (df DataFetcher) FetchData(ctx context.Context, organization string) (*Gith steps = append(steps, &proto.Step{ Title: "Get SSO Configuration", Description: "Fetches the SAML SSO configuration for the organization to verify identity provider enforcement", - Remarks: policy_manager.Pointer("More information: https://docs.github.com/en/rest/orgs/orgs?apiVersion=2022-11-28#get-an-organization"), + Remarks: policy_manager.Pointer("More information: https://docs.github.com/en/enterprise-cloud@latest/organizations/managing-saml-single-sign-on-for-your-organization/about-identity-and-access-management-with-saml-single-sign-on"), }) steps = append(steps, &proto.Step{ @@ -127,20 +127,14 @@ func (df DataFetcher) FetchData(ctx context.Context, organization string) (*Gith ssoData, err := df.fetchSSO(ctx, organization) if err != nil { - df.logger.Warn("Could not fetch SSO configuration; marking SSO as disabled", "org", organization, "error", err) - ssoData = &OrgSSO{Enabled: false} + df.logger.Error("Error getting SSO configuration", "org", organization, "error", err) + return nil, nil, err } - var ipAllowList []IPAllowListEntry - if org.Plan != nil && org.Plan.Name != nil && *org.Plan.Name == "enterprise" { - ipAllowList, err = df.fetchIPAllowList(ctx, organization) - if err != nil { - df.logger.Warn("Could not fetch IP allow-list; treating as empty", "org", organization, "error", err) - ipAllowList = []IPAllowListEntry{} - } - } else { - df.logger.Info("Skipping IP allow-list fetch: requires GitHub Enterprise Cloud", "org", organization, "plan", org.Plan) - ipAllowList = []IPAllowListEntry{} + ipAllowList, err := df.fetchIPAllowList(ctx, organization) + if err != nil { + df.logger.Error("Error getting IP allow-list", "org", organization, "error", err) + return nil, nil, err } return &GithubData{ @@ -162,7 +156,7 @@ func (df DataFetcher) fetchSSO(ctx context.Context, organization string) (*OrgSS SAMLIdentityProvider *samlIdentityProvider `json:"saml_identity_provider"` } - url := fmt.Sprintf("https://api.github.com/orgs/%s/sso", organization) + url := fmt.Sprintf("orgs/%s/sso", organization) req, err := df.client.NewRequest(http.MethodGet, url, nil) if err != nil { return nil, fmt.Errorf("building SSO request: %w", err) @@ -190,7 +184,8 @@ func (df DataFetcher) fetchSSO(ctx context.Context, organization string) (*OrgSS func (df DataFetcher) fetchIPAllowList(ctx context.Context, organization string) ([]IPAllowListEntry, error) { type graphqlRequest struct { - Query string `json:"query"` + Query string `json:"query"` + Variables map[string]interface{} `json:"variables"` } type ipAllowListEntryNode struct { AllowListValue string `json:"allowListValue"` @@ -201,7 +196,11 @@ func (df DataFetcher) fetchIPAllowList(ctx context.Context, organization string) Node ipAllowListEntryNode `json:"node"` } type ipAllowListConnection struct { - Edges []ipAllowListEdge `json:"edges"` + Edges []ipAllowListEdge `json:"edges"` + PageInfo struct { + HasNextPage bool `json:"hasNextPage"` + EndCursor *string `json:"endCursor"` + } `json:"pageInfo"` } type orgNode struct { IPAllowListEntries ipAllowListConnection `json:"ipAllowListEntries"` @@ -216,32 +215,66 @@ func (df DataFetcher) fetchIPAllowList(ctx context.Context, organization string) } `json:"errors"` } - gqlQuery := graphqlRequest{ - Query: fmt.Sprintf(`{ organization(login: "%s") { ipAllowListEntries(first: 100) { edges { node { allowListValue isActive name } } } } }`, organization), - } + query := `query($login: String!, $after: String) { + organization(login: $login) { + ipAllowListEntries(first: 100, after: $after) { + edges { + node { + allowListValue + isActive + name + } + } + pageInfo { + hasNextPage + endCursor + } + } + } + }` - req, err := df.client.NewRequest(http.MethodPost, "https://api.github.com/graphql", gqlQuery) - if err != nil { - return nil, fmt.Errorf("building IP allow-list GraphQL request: %w", err) - } + var entries []IPAllowListEntry + var after *string + for { + gqlQuery := graphqlRequest{ + Query: query, + Variables: map[string]interface{}{ + "login": organization, + "after": after, + }, + } - var gqlResp graphqlResponse - _, err = df.client.Do(ctx, req, &gqlResp) - if err != nil { - return nil, fmt.Errorf("executing IP allow-list GraphQL query: %w", err) - } + req, err := df.client.NewRequest(http.MethodPost, "graphql", gqlQuery) + if err != nil { + return nil, fmt.Errorf("building IP allow-list GraphQL request: %w", err) + } - if len(gqlResp.Errors) > 0 { - return nil, fmt.Errorf("GraphQL error: %s", gqlResp.Errors[0].Message) - } + var gqlResp graphqlResponse + _, err = df.client.Do(ctx, req, &gqlResp) + if err != nil { + return nil, fmt.Errorf("executing IP allow-list GraphQL query: %w", err) + } + + if len(gqlResp.Errors) > 0 { + return nil, fmt.Errorf("GraphQL error: %s", gqlResp.Errors[0].Message) + } + + connection := gqlResp.Data.Organization.IPAllowListEntries + for _, edge := range connection.Edges { + entries = append(entries, IPAllowListEntry{ + AllowListValue: edge.Node.AllowListValue, + IsActive: edge.Node.IsActive, + Name: edge.Node.Name, + }) + } - entries := make([]IPAllowListEntry, 0, len(gqlResp.Data.Organization.IPAllowListEntries.Edges)) - for _, edge := range gqlResp.Data.Organization.IPAllowListEntries.Edges { - entries = append(entries, IPAllowListEntry{ - AllowListValue: edge.Node.AllowListValue, - IsActive: edge.Node.IsActive, - Name: edge.Node.Name, - }) + if !connection.PageInfo.HasNextPage { + break + } + if connection.PageInfo.EndCursor == nil { + return nil, fmt.Errorf("GraphQL response indicated another IP allow-list page without an end cursor") + } + after = connection.PageInfo.EndCursor } return entries, nil } diff --git a/internal/data_test.go b/internal/data_test.go new file mode 100644 index 0000000..2ae5130 --- /dev/null +++ b/internal/data_test.go @@ -0,0 +1,146 @@ +package internal + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/google/go-github/v71/github" + "github.com/hashicorp/go-hclog" +) + +func testGithubClient(t *testing.T, handler http.Handler) (*github.Client, func()) { + t.Helper() + + server := httptest.NewServer(handler) + client := github.NewClient(server.Client()) + + baseURL, err := url.Parse(server.URL + "/") + if err != nil { + t.Fatalf("parsing test server URL: %v", err) + } + client.BaseURL = baseURL + + return client, server.Close +} + +func TestFetchSSOUsesRelativeURL(t *testing.T) { + client, cleanup := testGithubClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + t.Fatalf("method = %s, want GET", r.Method) + } + if r.URL.Path != "/orgs/acme/sso" { + t.Fatalf("path = %s, want /orgs/acme/sso", r.URL.Path) + } + + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write([]byte(`{"saml_identity_provider":{"sso_url":"https://idp.example/sso","issuer":"https://idp.example"}}`)) + })) + defer cleanup() + + fetcher := NewDataFetcher(hclog.NewNullLogger(), client) + sso, err := fetcher.fetchSSO(context.Background(), "acme") + if err != nil { + t.Fatalf("fetchSSO returned error: %v", err) + } + if !sso.Enabled { + t.Fatal("SSO should be enabled") + } + if sso.SSOURL != "https://idp.example/sso" { + t.Fatalf("SSOURL = %q, want https://idp.example/sso", sso.SSOURL) + } + if sso.IDPIssuer != "https://idp.example" { + t.Fatalf("IDPIssuer = %q, want https://idp.example", sso.IDPIssuer) + } +} + +func TestFetchSSONotFoundMeansDisabled(t *testing.T) { + client, cleanup := testGithubClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.NotFound(w, r) + })) + defer cleanup() + + fetcher := NewDataFetcher(hclog.NewNullLogger(), client) + sso, err := fetcher.fetchSSO(context.Background(), "acme") + if err != nil { + t.Fatalf("fetchSSO returned error: %v", err) + } + if sso.Enabled { + t.Fatal("SSO should be disabled when the endpoint returns 404") + } +} + +func TestFetchIPAllowListUsesVariablesAndPaginates(t *testing.T) { + page := 0 + var afterValues []interface{} + client, cleanup := testGithubClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + t.Fatalf("method = %s, want POST", r.Method) + } + if r.URL.Path != "/graphql" { + t.Fatalf("path = %s, want /graphql", r.URL.Path) + } + + var request struct { + Query string `json:"query"` + Variables map[string]interface{} `json:"variables"` + } + if err := json.NewDecoder(r.Body).Decode(&request); err != nil { + t.Fatalf("decoding GraphQL request: %v", err) + } + if request.Variables["login"] != "acme" { + t.Fatalf("login variable = %v, want acme", request.Variables["login"]) + } + afterValues = append(afterValues, request.Variables["after"]) + + w.Header().Set("Content-Type", "application/json") + switch page { + case 0: + _, _ = w.Write([]byte(`{"data":{"organization":{"ipAllowListEntries":{"edges":[{"node":{"allowListValue":"192.0.2.0/24","isActive":true,"name":"office"}}],"pageInfo":{"hasNextPage":true,"endCursor":"cursor-1"}}}}}`)) + case 1: + _, _ = w.Write([]byte(`{"data":{"organization":{"ipAllowListEntries":{"edges":[{"node":{"allowListValue":"198.51.100.0/24","isActive":false,"name":"vpn"}}],"pageInfo":{"hasNextPage":false,"endCursor":null}}}}}`)) + default: + t.Fatalf("unexpected GraphQL page request %d", page) + } + page++ + })) + defer cleanup() + + fetcher := NewDataFetcher(hclog.NewNullLogger(), client) + entries, err := fetcher.fetchIPAllowList(context.Background(), "acme") + if err != nil { + t.Fatalf("fetchIPAllowList returned error: %v", err) + } + if len(entries) != 2 { + t.Fatalf("len(entries) = %d, want 2", len(entries)) + } + if entries[0].AllowListValue != "192.0.2.0/24" || entries[1].AllowListValue != "198.51.100.0/24" { + t.Fatalf("entries = %#v", entries) + } + if len(afterValues) != 2 { + t.Fatalf("after values = %#v, want two requests", afterValues) + } + if afterValues[0] != nil { + t.Fatalf("first after = %#v, want nil", afterValues[0]) + } + if afterValues[1] != "cursor-1" { + t.Fatalf("second after = %#v, want cursor-1", afterValues[1]) + } +} + +func TestFetchIPAllowListErrorsWithoutEndCursor(t *testing.T) { + client, cleanup := testGithubClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write([]byte(`{"data":{"organization":{"ipAllowListEntries":{"edges":[],"pageInfo":{"hasNextPage":true,"endCursor":null}}}}}`)) + })) + defer cleanup() + + fetcher := NewDataFetcher(hclog.NewNullLogger(), client) + _, err := fetcher.fetchIPAllowList(context.Background(), "acme") + if err == nil { + t.Fatal("fetchIPAllowList should error when a next page has no end cursor") + } +} From 1a781bff168121b0686ea6346f840fca261f0089 Mon Sep 17 00:00:00 2001 From: Gustavo Carvalho Date: Tue, 12 May 2026 05:50:40 -0300 Subject: [PATCH 3/3] chore: bump agent version Signed-off-by: Gustavo Carvalho --- .github/workflows/build-and-upload.yml | 2 ++ go.mod | 14 ++++----- go.sum | 40 ++++++++++++++------------ 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build-and-upload.yml b/.github/workflows/build-and-upload.yml index c9e037e..4affeae 100644 --- a/.github/workflows/build-and-upload.yml +++ b/.github/workflows/build-and-upload.yml @@ -9,6 +9,8 @@ jobs: steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 + with: + go-version-file: go.mod - name: Run GoReleaser uses: goreleaser/goreleaser-action@v6 with: diff --git a/go.mod b/go.mod index f51d005..79fc3be 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,9 @@ module github.com/compliance-framework/plugin-github-settings -go 1.25.8 +go 1.26.1 require ( - github.com/compliance-framework/agent v0.3.1 + github.com/compliance-framework/agent v0.6.2 github.com/google/go-github/v71 v71.0.0 github.com/hashicorp/go-hclog v1.6.3 github.com/hashicorp/go-plugin v1.7.0 @@ -13,7 +13,7 @@ require ( require ( github.com/agnivade/levenshtein v1.2.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/compliance-framework/api v0.13.0 // indirect + github.com/compliance-framework/api v0.16.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 // indirect github.com/defenseunicorns/go-oscal v0.7.0 // indirect @@ -52,13 +52,11 @@ require ( go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.48.0 // indirect - golang.org/x/net v0.51.0 // indirect - golang.org/x/oauth2 v0.35.0 // indirect + golang.org/x/crypto v0.49.0 // indirect + golang.org/x/net v0.52.0 // indirect golang.org/x/sync v0.20.0 // indirect golang.org/x/sys v0.42.0 // indirect - golang.org/x/text v0.34.0 // indirect - golang.org/x/tools v0.42.0 // indirect + golang.org/x/text v0.35.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect google.golang.org/grpc v1.79.3 // indirect google.golang.org/protobuf v1.36.11 // indirect diff --git a/go.sum b/go.sum index fd517de..3a1bc40 100644 --- a/go.sum +++ b/go.sum @@ -56,10 +56,10 @@ github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqy github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= 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.3.1 h1:RikYgITNcu5Wc8i4sTzTzfZvbon2/r8Hot6ZcGZ+1UA= -github.com/compliance-framework/agent v0.3.1/go.mod h1:S0x4qpbUdlVZD6NlyGlrsSLUODdtB3M1rOHHcXQdadU= -github.com/compliance-framework/api v0.13.0 h1:pW0JS4e9ZwRIwSZM32ObjdCBIxuxL+TL4nHAcopqMO0= -github.com/compliance-framework/api v0.13.0/go.mod h1:CMHwcOOCcVRf1u/n3BeqbrP09WWCuwnFAlD7dQfIWCA= +github.com/compliance-framework/agent v0.6.2 h1:4Ha3kTDpoAXDsGOnczeVXdf56dl7h2XNxIfawWJc+LI= +github.com/compliance-framework/agent v0.6.2/go.mod h1:k6sNhVQXviFHbz/Fe/jOkfBZ+AFLnRPIuOH2aaaCTNo= +github.com/compliance-framework/api v0.16.0 h1:0HO5a5N80ktJLeLD5GVeTk7cK7PO9Xj5WN4SR+KGBH0= +github.com/compliance-framework/api v0.16.0/go.mod h1:BupcN8mQFgB0/2+YShU/r4BUYoGwzSjbz2esdOUaX/4= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= @@ -113,8 +113,8 @@ github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= -github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= +github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -170,6 +170,8 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 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/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 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.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA= @@ -180,8 +182,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo= -github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw= +github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw= +github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= @@ -306,6 +308,8 @@ github.com/shirou/gopsutil/v4 v4.25.1 h1:QSWkTc+fu9LTAWfkZwZ6j8MSUk4A2LV7rbH0Zqm github.com/shirou/gopsutil/v4 v4.25.1/go.mod h1:RoUCUpndaJFtT+2zsZzzmhvbfGoDCJ7nFXKJf8GqJbI= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= +github.com/slack-go/slack v0.20.0 h1:gbDdbee8+Z2o+DWx05Spq3GzbrLLleiRwHUKs+hZLSU= +github.com/slack-go/slack v0.20.0/go.mod h1:K81UmCivcYd/5Jmz8vLBfuyoZ3B4rQC2GHVXHteXiAE= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= @@ -385,12 +389,12 @@ go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= -golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= -golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= -golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= +golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= @@ -403,12 +407,12 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= -golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= +golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=