diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..2da6d58 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,15 @@ +version: "2" + +run: + build-tags: + - e2e + - unit + +output: + formats: + tab: + path: stdout + sort-order: + - file + - severity + - linter diff --git a/e2e_tests/e2e_test.go b/e2e_tests/e2e_test.go index 089b670..454eaaf 100644 --- a/e2e_tests/e2e_test.go +++ b/e2e_tests/e2e_test.go @@ -64,7 +64,7 @@ func TestMain(m *testing.M) { if err == nil { logger.Info("Performing global image cleanup") for image := range globalImagesToRemove { - dockerCli.ImageRemove(ctx, image, imageApi.RemoveOptions{ + _, _ = dockerCli.ImageRemove(ctx, image, imageApi.RemoveOptions{ Force: true, }) } @@ -121,11 +121,11 @@ func getEnvVars() (*config, error) { if err != nil { return nil, err } - var config config - if err := env.Parse(&config); err != nil { + var cfg config + if err := env.Parse(&cfg); err != nil { return nil, err } - return &config, nil + return &cfg, nil } func pullRequiredImages(t *testing.T, ctx context.Context, dockerApi *dockerApi.Client, containers []Container) { @@ -147,7 +147,7 @@ func pullRequiredImages(t *testing.T, ctx context.Context, dockerApi *dockerApi. } if err := g.Wait(); err != nil { - cleanup(t, dockerApi, containers, nil) + cleanup(dockerApi, containers, nil) t.Fatal(err) } } @@ -209,7 +209,7 @@ func startRequiredContainers(t *testing.T, ctx context.Context, dockerCli *docke }) } if err := g.Wait(); err != nil { - cleanup(t, dockerCli, containers, nil) + cleanup(dockerCli, containers, nil) t.Fatal(err) } } @@ -233,7 +233,7 @@ func setClients(t *testing.T, containers []Container) (*docker.Client, *pihole.C } piholeClient := pihole.NewClient(piholeURL, "password") - logger.Info("Waiting for Pi-hole to be ready...") + logger.Info("Waiting for Pi-Hole to be ready...") piholeLoginTimeout := time.After(60 * time.Second) piholeLoginTicker := time.NewTicker(3 * time.Second) defer piholeLoginTicker.Stop() @@ -241,14 +241,14 @@ PiholeLoginLoop: for { select { case <-piholeLoginTimeout: - t.Fatalf("Timed out waiting for Pi-hole to be ready at %s", piholeURL) + t.Fatalf("Timed out waiting for Pi-Hole to be ready at %s", piholeURL) case <-piholeLoginTicker.C: err = piholeClient.Login() if err == nil { - logger.Info("Successfully logged into Pi-hole") + logger.Info("Successfully logged into Pi-Hole") break PiholeLoginLoop } - logger.Error("Pi-hole not ready, retrying...", "error", err) + logger.Error("Pi-Hole not ready, retrying...", "error", err) } } @@ -284,7 +284,7 @@ func setup(t *testing.T, ctx context.Context, dockerCli *dockerApi.Client, conta return dockerClient, piholeClient, npmClient, adguardHomeClient } -func cleanup(t *testing.T, dockerCli *dockerApi.Client, containers []Container, npmClient *npm.Client) { +func cleanup(dockerCli *dockerApi.Client, containers []Container, npmClient *npm.Client) { logger.Info("In cleanup") // Use background context for cleanup to ensure it completes even if test is canceled @@ -293,7 +293,7 @@ func cleanup(t *testing.T, dockerCli *dockerApi.Client, containers []Container, if npmClient != nil { npmProxyHosts, err := npmClient.GetProxyHosts() if err == nil { - npmClient.DeleteProxyHosts(slices.Collect(maps.Keys(npmProxyHosts))) + _, _ = npmClient.DeleteProxyHosts(slices.Collect(maps.Keys(npmProxyHosts))) } } var wg sync.WaitGroup @@ -360,7 +360,7 @@ func TestE2E(t *testing.T) { dockerClient, piholeClient, npmClient, adguardHomeClient := setup(t, ctx, dockerCli, containers) t.Cleanup(func() { - cleanup(t, dockerCli, containers, npmClient) + cleanup(dockerCli, containers, npmClient) }) time.Sleep(2 * time.Second) @@ -408,9 +408,14 @@ func TestE2E(t *testing.T) { } // Deleting to assert delete functionality - piholeClient.DeleteDnsRecords(urls) - npmClient.DeleteProxyHosts(urls) - adguardHomeClient.DeleteDnsRewrites(urls, npmClient.GetIP()) + _, err = piholeClient.DeleteDnsRecords(urls) + require.NoError(t, err, "Failed to delete Pi-Hole DNS records") + + _, err = npmClient.DeleteProxyHosts(urls) + require.NoError(t, err, "Failed to delete NPM proxy hosts") + + _, err = adguardHomeClient.DeleteDnsRewrites(urls, npmClient.GetIP()) + require.NoError(t, err, "Failed to delete AdGuard Home DNS rewrites") piholeDnsRecords, err := piholeClient.GetDnsRecords() if err != nil { @@ -461,7 +466,7 @@ func TestE2E_CreateOnHealthy(t *testing.T) { dockerClient, piholeClient, npmClient, adguardHomeClient := setup(t, ctx, dockerCli, infraContainers) t.Cleanup(func() { - cleanup(t, dockerCli, infraContainers, npmClient) + cleanup(dockerCli, infraContainers, npmClient) }) proc := processor.New( @@ -502,7 +507,7 @@ func TestE2E_CreateOnHealthy(t *testing.T) { startRequiredContainers(t, ctx, dockerCli, testContainers) t.Cleanup(func() { - dockerCli.ContainerRemove(context.Background(), testContainers[0].id, containerApi.RemoveOptions{Force: true}) + _ = dockerCli.ContainerRemove(context.Background(), testContainers[0].id, containerApi.RemoveOptions{Force: true}) }) // Assert entry DOES NOT exist while unhealthy @@ -521,8 +526,8 @@ func TestE2E_CreateOnHealthy(t *testing.T) { // Wait for Docker to mark it healthy logger.Info("Waiting for Docker to mark container as healthy") require.Eventually(t, func() bool { - inspect, err := dockerCli.ContainerInspect(ctx, testContainers[0].id) - if err != nil { + inspect, inspectErr := dockerCli.ContainerInspect(ctx, testContainers[0].id) + if inspectErr != nil { return false } return inspect.State.Health != nil && inspect.State.Health.Status == "healthy" @@ -577,7 +582,7 @@ func TestE2E_CreateOnHealthy_NoHealthcheck(t *testing.T) { dockerClient, _, npmClient, adguardHomeClient := setup(t, ctx, dockerCli, infraContainers) t.Cleanup(func() { - cleanup(t, dockerCli, infraContainers, npmClient) + cleanup(dockerCli, infraContainers, npmClient) }) proc := processor.New( @@ -614,7 +619,7 @@ func TestE2E_CreateOnHealthy_NoHealthcheck(t *testing.T) { startRequiredContainers(t, ctx, dockerCli, testContainers) t.Cleanup(func() { - dockerCli.ContainerRemove(context.Background(), testContainers[0].id, containerApi.RemoveOptions{Force: true}) + _ = dockerCli.ContainerRemove(context.Background(), testContainers[0].id, containerApi.RemoveOptions{Force: true}) }) // Assert entry NEVER exists diff --git a/e2e_tests/utils.go b/e2e_tests/utils.go index 66909fa..40a5645 100644 --- a/e2e_tests/utils.go +++ b/e2e_tests/utils.go @@ -23,10 +23,9 @@ func pullImage(ctx context.Context, dockerCli *dockerCliClient.Client, img strin return err } - defer reader.Close() + defer reader.Close() //nolint:errcheck termFd, isTerm := term.GetFdInfo(os.Stderr) - jsonmessage.DisplayJSONMessagesStream(reader, os.Stderr, termFd, isTerm, nil) - return nil + return jsonmessage.DisplayJSONMessagesStream(reader, os.Stderr, termFd, isTerm, nil) } func markContainerHealthy(ctx context.Context, dockerCli *dockerCliClient.Client, containerID string) error { diff --git a/pkg/clients/adguardhome/adguardhome.go b/pkg/clients/adguardhome/adguardhome.go index c252b29..fe88365 100644 --- a/pkg/clients/adguardhome/adguardhome.go +++ b/pkg/clients/adguardhome/adguardhome.go @@ -8,12 +8,9 @@ import ( "net/http" "github.com/deepspace2/plugnpin/pkg/clients/common" - "github.com/deepspace2/plugnpin/pkg/logging" "github.com/deepspace2/plugnpin/pkg/metrics" ) -var log = logging.GetLogger("adguardhome") - type Client struct { http.Client baseURL string @@ -42,7 +39,10 @@ func (ad *Client) GetDnsRewrites() (DnsRewrites, error) { return nil, err } var resp []DnsRewrite - json.Unmarshal([]byte(dnsRewritesResponseString), &resp) + err = json.Unmarshal([]byte(dnsRewritesResponseString), &resp) + if err != nil { + return nil, err + } dnsRewrites := DnsRewrites{} for _, rawDnsRewrite := range resp { diff --git a/pkg/clients/adguardhome/adguardhome_test.go b/pkg/clients/adguardhome/adguardhome_test.go index 7d32aaf..8756b71 100644 --- a/pkg/clients/adguardhome/adguardhome_test.go +++ b/pkg/clients/adguardhome/adguardhome_test.go @@ -32,7 +32,7 @@ func TestAddDnsRewrite(t *testing.T) { if r.URL.Path == "/control/rewrite/list" && r.Method == http.MethodGet { w.WriteHeader(http.StatusOK) - fmt.Fprint(w, `[{"domain": "one.com", "answer": "1.1.1.1"}]`) + _, _ = fmt.Fprint(w, `[{"domain": "one.com", "answer": "1.1.1.1"}]`) return } @@ -46,7 +46,7 @@ func TestAddDnsRewrite(t *testing.T) { assert.True(t, payload.Enabled) w.WriteHeader(http.StatusOK) - fmt.Fprint(w, `{}`) + _, _ = fmt.Fprint(w, `{}`) return } @@ -81,13 +81,13 @@ func TestDeleteDnsRewrite(t *testing.T) { assert.True(t, payload.Enabled) w.WriteHeader(http.StatusOK) - fmt.Fprint(w, `{}`) + _, _ = fmt.Fprint(w, `{}`) return } if r.URL.Path == "/control/rewrite/list" && r.Method == http.MethodGet { w.WriteHeader(http.StatusOK) - fmt.Fprint(w, `[]`) + _, _ = fmt.Fprint(w, `[]`) return } @@ -116,7 +116,7 @@ func TestWrongCredentials(t *testing.T) { expectedAuth := "Basic " + base64.StdEncoding.EncodeToString([]byte("testuser:testpass")) if auth != expectedAuth { w.WriteHeader(http.StatusUnauthorized) - fmt.Fprint(w, `{}`) + _, _ = fmt.Fprint(w, `{}`) } return } @@ -126,7 +126,7 @@ func TestWrongCredentials(t *testing.T) { expectedAuth := "Basic " + base64.StdEncoding.EncodeToString([]byte("testuser:testpass")) if auth != expectedAuth { w.WriteHeader(http.StatusUnauthorized) - fmt.Fprint(w, `{}`) + _, _ = fmt.Fprint(w, `{}`) } return } diff --git a/pkg/clients/common/common.go b/pkg/clients/common/common.go index d8a88b4..0335ce1 100644 --- a/pkg/clients/common/common.go +++ b/pkg/clients/common/common.go @@ -51,7 +51,7 @@ func setHeaders(req *http.Request, headers map[string]string) { } } -func Post(client *http.Client, path string, headers map[string]string, data *string) (string, int, error) { +func Post(client *http.Client, path string, headers map[string]string, data *string) (bodyStr string, statusCode int, err error) { req, err := http.NewRequest( http.MethodPost, path, @@ -68,7 +68,11 @@ func Post(client *http.Client, path string, headers map[string]string, data *str return "", 0, err } - defer resp.Body.Close() + defer func() { + if cerr := resp.Body.Close(); cerr != nil && err == nil { + err = cerr + } + }() body, err := io.ReadAll(resp.Body) if err != nil { return "", 0, err @@ -77,7 +81,7 @@ func Post(client *http.Client, path string, headers map[string]string, data *str return string(body), resp.StatusCode, nil } -func Get(client *http.Client, path string, headers map[string]string) (string, int, error) { +func Get(client *http.Client, path string, headers map[string]string) (bodyStr string, statusCode int, err error) { req, err := http.NewRequest( http.MethodGet, path, @@ -94,7 +98,11 @@ func Get(client *http.Client, path string, headers map[string]string) (string, i return "", 0, err } - defer resp.Body.Close() + defer func() { + if cerr := resp.Body.Close(); cerr != nil && err == nil { + err = cerr + } + }() body, err := io.ReadAll(resp.Body) if err != nil { return "", 0, err @@ -102,7 +110,7 @@ func Get(client *http.Client, path string, headers map[string]string) (string, i return string(body), resp.StatusCode, nil } -func Patch(client *http.Client, path string, headers map[string]string, data string) (string, int, error) { +func Patch(client *http.Client, path string, headers map[string]string, data string) (bodyStr string, statusCode int, err error) { req, err := http.NewRequest( http.MethodPatch, path, @@ -119,7 +127,11 @@ func Patch(client *http.Client, path string, headers map[string]string, data str return "", 0, err } - defer resp.Body.Close() + defer func() { + if cerr := resp.Body.Close(); cerr != nil && err == nil { + err = cerr + } + }() body, err := io.ReadAll(resp.Body) if err != nil { return "", 0, err @@ -135,7 +147,11 @@ func doDeleteRequest(req *http.Request, client *http.Client, headers map[string] return "", 0, err } - defer resp.Body.Close() + defer func() { + if cerr := resp.Body.Close(); cerr != nil && err == nil { + err = cerr + } + }() body, err := io.ReadAll(resp.Body) if err != nil { return "", 0, err diff --git a/pkg/clients/npm/npm.go b/pkg/clients/npm/npm.go index 958aeb3..5d15f3e 100644 --- a/pkg/clients/npm/npm.go +++ b/pkg/clients/npm/npm.go @@ -68,9 +68,16 @@ func (n *Client) Login() error { var resp LoginResponse err = json.Unmarshal([]byte(loginResponseString), &resp) - if statusCode >= 400 || err != nil || resp.Token == "" { + if err != nil { + return err + } + + if statusCode >= 400 || resp.Token == "" { var loginError ErrorResponse - json.Unmarshal([]byte(loginResponseString), &loginError) + err = json.Unmarshal([]byte(loginResponseString), &loginError) + if err != nil { + return err + } return errors.New(loginError.Error.Message) } @@ -98,7 +105,10 @@ func (n *Client) GetProxyHosts() (map[string]int, error) { var proxyHosts []ProxyHostReply existingProxyHostsMap := map[string]int{} - json.Unmarshal([]byte(proxyHostsString), &proxyHosts) + err = json.Unmarshal([]byte(proxyHostsString), &proxyHosts) + if err != nil { + return nil, err + } for _, host := range proxyHosts { for _, domainName := range host.DomainNames { @@ -161,14 +171,16 @@ func (n *Client) getCertificates() (Certificates, error) { } var certificates Certificates - json.Unmarshal([]byte(resp), &certificates) + err = json.Unmarshal([]byte(resp), &certificates) + if err != nil { + return nil, err + } return certificates, nil } func (n *Client) GetCertificateIDByName(name string) (int, error) { certificates, err := n.getCertificates() if err != nil { - log.Error("Failed to get certificates", "error", err) return 0, err } for _, certificate := range certificates { @@ -187,14 +199,16 @@ func (n *Client) getAccessLists() (AccessLists, error) { } var accessLists AccessLists - json.Unmarshal([]byte(resp), &accessLists) + err = json.Unmarshal([]byte(resp), &accessLists) + if err != nil { + return nil, err + } return accessLists, nil } func (n *Client) GetAccessListIDByName(name string) (int, error) { accessLists, err := n.getAccessLists() if err != nil { - log.Error("Failed to get access lists", "error", err) return 0, err } for _, accessList := range accessLists { @@ -230,7 +244,10 @@ func (n *Client) AddProxyHost(host ProxyHost) (bool, error) { if statusCode >= 400 { var errorResponse ErrorResponse - json.Unmarshal([]byte(resp), &errorResponse) + err = json.Unmarshal([]byte(resp), &errorResponse) + if err != nil { + return false, err + } return false, errors.New(errorResponse.Error.Message) } return true, nil @@ -264,7 +281,10 @@ func (n *Client) DeleteProxyHosts(domains []string) (bool, error) { if statusCode >= 400 { var errorResponse ErrorResponse - json.Unmarshal([]byte(resp), &errorResponse) + err = json.Unmarshal([]byte(resp), &errorResponse) + if err != nil { + return false, err + } return false, errors.New(errorResponse.Error.Message) } return true, nil diff --git a/pkg/clients/npm/npm_test.go b/pkg/clients/npm/npm_test.go index ac2ad32..872925f 100644 --- a/pkg/clients/npm/npm_test.go +++ b/pkg/clients/npm/npm_test.go @@ -33,7 +33,7 @@ func TestLogin(t *testing.T) { assert.Equal(t, "test-password", req.Secret) w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(LoginResponse{Token: "test-jwt-token", Expires: time.Now().Add(24 * time.Hour).Format(time.RFC3339Nano)}) + _ = json.NewEncoder(w).Encode(LoginResponse{Token: "test-jwt-token", Expires: time.Now().Add(24 * time.Hour).Format(time.RFC3339Nano)}) }) client, server := setupTestServer(handler) @@ -58,7 +58,7 @@ func TestAddProxyHost(t *testing.T) { if r.Method == http.MethodGet { // 1. The function first gets existing hosts. We return an empty list. w.WriteHeader(http.StatusOK) - w.Write([]byte(`[]`)) + _, _ = w.Write([]byte(`[]`)) return } @@ -97,7 +97,7 @@ func TestAddProxyHost(t *testing.T) { {ID: 123, DomainNames: []string{"existing-host.com"}}, } w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(existingHosts) + _ = json.NewEncoder(w).Encode(existingHosts) }) client, server := setupTestServer(handler) @@ -131,7 +131,7 @@ func TestDeleteProxyHosts(t *testing.T) { {ID: 123, DomainNames: []string{"host1.com", "host2.com"}}, } w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(existingHosts) + _ = json.NewEncoder(w).Encode(existingHosts) return } @@ -161,7 +161,7 @@ func TestDeleteProxyHosts(t *testing.T) { assert.Equal(t, http.MethodGet, r.Method) w.WriteHeader(http.StatusOK) - w.Write([]byte(`[]`)) + _, _ = w.Write([]byte(`[]`)) if r.Method == http.MethodDelete { deleteCalled = true @@ -186,7 +186,7 @@ func TestGetCertificateIDByName(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "/api/nginx/certificates", r.URL.Path) w.WriteHeader(http.StatusOK) - w.Write([]byte(`[{"id": 1, "nice_name": "test-cert"}]`)) + _, _ = w.Write([]byte(`[{"id": 1, "nice_name": "test-cert"}]`)) }) client, server := setupTestServer(handler) @@ -202,7 +202,7 @@ func TestGetCertificateIDByName(t *testing.T) { t.Run("not found", func(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) - w.Write([]byte(`[]`)) + _, _ = w.Write([]byte(`[]`)) }) client, server := setupTestServer(handler) @@ -223,7 +223,7 @@ func TestGetAccessListIDByName(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "/api/nginx/access-lists", r.URL.Path) w.WriteHeader(http.StatusOK) - w.Write([]byte(`[{"id": 2, "name": "test-access-list"}]`)) + _, _ = w.Write([]byte(`[{"id": 2, "name": "test-access-list"}]`)) }) client, server := setupTestServer(handler) @@ -239,7 +239,7 @@ func TestGetAccessListIDByName(t *testing.T) { t.Run("not found", func(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) - w.Write([]byte(`[]`)) + _, _ = w.Write([]byte(`[]`)) }) client, server := setupTestServer(handler) diff --git a/pkg/clients/pihole/pihole.go b/pkg/clients/pihole/pihole.go index d1e9d0a..678f7e3 100644 --- a/pkg/clients/pihole/pihole.go +++ b/pkg/clients/pihole/pihole.go @@ -46,7 +46,10 @@ func (p *Client) Login() error { return err } var resp loginResponse - json.Unmarshal([]byte(loginResponseString), &resp) + err = json.Unmarshal([]byte(loginResponseString), &resp) + if err != nil { + return err + } if statusCode >= 400 || resp.Session.Sid == "" { return errors.New(resp.Session.Message) @@ -94,13 +97,18 @@ func (p *Client) GetDnsRecords() (DnsRecords, error) { if p.sid == "" { return nil, errMissingSessionId } + headers["X-FTL-SID"] = p.sid configResponseString, _, err := common.Get(&p.Client, p.baseURL+"/config", headers) if err != nil { return nil, err } + var resp configResponse - json.Unmarshal([]byte(configResponseString), &resp) + err = json.Unmarshal([]byte(configResponseString), &resp) + if err != nil { + return nil, err + } dnsRecords := DnsRecords{} for _, rawDnsRecords := range resp.Config.DNS.Hosts { @@ -155,7 +163,7 @@ func (p *Client) AddDnsRecords(domains []string, ip string) (numOfAddedDnsRecord } if statusCode == 401 { - if err := p.refreshAuth(); err != nil { + if err = p.refreshAuth(); err != nil { return 0, errors.Join(errAuthRefreshFailed, err) } return p.AddDnsRecords(domains, ip) @@ -163,7 +171,11 @@ func (p *Client) AddDnsRecords(domains []string, ip string) (numOfAddedDnsRecord if statusCode >= 400 { var errorResponse ErrorResponse - json.Unmarshal([]byte(resp), &errorResponse) + err = json.Unmarshal([]byte(resp), &errorResponse) + if err != nil { + return 0, err + } + return 0, fmt.Errorf("%v. %v", errorResponse.Error.Message, errorResponse.Error.Hint) } @@ -212,7 +224,7 @@ func (p *Client) DeleteDnsRecords(domains []string) (numOfDeletedDnsRecords int, } if statusCode == 401 { - if err := p.refreshAuth(); err != nil { + if err = p.refreshAuth(); err != nil { return 0, errors.Join(errAuthRefreshFailed, err) } return p.DeleteDnsRecords(domains) @@ -220,8 +232,11 @@ func (p *Client) DeleteDnsRecords(domains []string) (numOfDeletedDnsRecords int, if statusCode >= 400 { var errorResponse ErrorResponse - json.Unmarshal([]byte(resp), &errorResponse) - return numOfDeletedDnsRecords, fmt.Errorf("%v. %v", errorResponse.Error.Message, errorResponse.Error.Hint) + err = json.Unmarshal([]byte(resp), &errorResponse) + if err != nil { + return 0, err + } + return 0, fmt.Errorf("%v. %v", errorResponse.Error.Message, errorResponse.Error.Hint) } return len(deletedDomains), nil @@ -246,13 +261,18 @@ func (p *Client) getCNameRecords() (CNameRecords, error) { if p.sid == "" { return nil, errMissingSessionId } + headers["X-FTL-SID"] = p.sid configResponseString, _, err := common.Get(&p.Client, p.baseURL+"/config", headers) if err != nil { return nil, err } + var resp configResponse - json.Unmarshal([]byte(configResponseString), &resp) + err = json.Unmarshal([]byte(configResponseString), &resp) + if err != nil { + return nil, err + } cNameRecords := CNameRecords{} for _, rawCNameRecord := range resp.Config.DNS.CnameRecords { @@ -262,6 +282,7 @@ func (p *Client) getCNameRecords() (CNameRecords, error) { } cNameRecords[domain] = target } + return cNameRecords, nil } @@ -294,29 +315,34 @@ func (p *Client) AddCNameRecords(domains []string, target string) (numOfAddedCNa payloadString, err := json.Marshal(payload) if err != nil { - return numOfAddedCNameRecords, err + return 0, err } if p.sid == "" { - return numOfAddedCNameRecords, errMissingSessionId + return 0, errMissingSessionId } + headers["X-FTL-SID"] = p.sid resp, statusCode, err := common.Patch(&p.Client, p.baseURL+"/config", headers, string(payloadString)) if err != nil { - return numOfAddedCNameRecords, err + return 0, err } if statusCode == 401 { - if err := p.refreshAuth(); err != nil { - return numOfAddedCNameRecords, errors.Join(errAuthRefreshFailed, err) + if err = p.refreshAuth(); err != nil { + return 0, errors.Join(errAuthRefreshFailed, err) } return p.AddCNameRecords(domains, target) } if statusCode >= 400 { var errorResponse ErrorResponse - json.Unmarshal([]byte(resp), &errorResponse) - return numOfAddedCNameRecords, fmt.Errorf("%v. %v", errorResponse.Error.Message, errorResponse.Error.Hint) + err = json.Unmarshal([]byte(resp), &errorResponse) + if err != nil { + return 0, err + } + + return 0, fmt.Errorf("%v. %v", errorResponse.Error.Message, errorResponse.Error.Hint) } return len(addedDomains), nil @@ -325,7 +351,7 @@ func (p *Client) AddCNameRecords(domains []string, target string) (numOfAddedCNa func (p *Client) DeleteCNameRecords(domains []string) (numOfDeletedCNameRecords int, err error) { existingRecords, err := p.getCNameRecords() if err != nil { - return numOfDeletedCNameRecords, err + return 0, err } deletedDomains := []string{} @@ -338,7 +364,7 @@ func (p *Client) DeleteCNameRecords(domains []string) (numOfDeletedCNameRecords } if len(deletedDomains) == 0 { - return numOfDeletedCNameRecords, nil + return 0, nil } rawRecordsSlice := []string{} @@ -351,29 +377,34 @@ func (p *Client) DeleteCNameRecords(domains []string) (numOfDeletedCNameRecords payloadString, err := json.Marshal(payload) if err != nil { - return numOfDeletedCNameRecords, err + return 0, err } if p.sid == "" { - return numOfDeletedCNameRecords, errMissingSessionId + return 0, errMissingSessionId } + headers["X-FTL-SID"] = p.sid resp, statusCode, err := common.Patch(&p.Client, p.baseURL+"/config", headers, string(payloadString)) if err != nil { - return numOfDeletedCNameRecords, err + return 0, err } if statusCode == 401 { - if err := p.refreshAuth(); err != nil { - return numOfDeletedCNameRecords, errors.Join(errAuthRefreshFailed, err) + if err = p.refreshAuth(); err != nil { + return 0, errors.Join(errAuthRefreshFailed, err) } return p.DeleteCNameRecords(domains) } if statusCode >= 400 { var errorResponse ErrorResponse - json.Unmarshal([]byte(resp), &errorResponse) - return numOfDeletedCNameRecords, fmt.Errorf("%v. %v", errorResponse.Error.Message, errorResponse.Error.Hint) + err = json.Unmarshal([]byte(resp), &errorResponse) + if err != nil { + return 0, err + } + + return 0, fmt.Errorf("%v. %v", errorResponse.Error.Message, errorResponse.Error.Hint) } return len(deletedDomains), nil diff --git a/pkg/clients/pihole/pihole_test.go b/pkg/clients/pihole/pihole_test.go index 2027991..16b5226 100644 --- a/pkg/clients/pihole/pihole_test.go +++ b/pkg/clients/pihole/pihole_test.go @@ -27,13 +27,13 @@ func TestLogin(t *testing.T) { assert.Equal(t, "/api/auth", r.URL.Path) assert.Equal(t, "POST", r.Method) var payload map[string]string - json.NewDecoder(r.Body).Decode(&payload) + _ = json.NewDecoder(r.Body).Decode(&payload) assert.Equal(t, "test-password", payload["password"]) // Send response w.WriteHeader(http.StatusOK) // The actual API response is more complex, so we mock the whole thing - fmt.Fprint(w, `{"session": {"sid": "test-sid", "message": "Login successful"}}`) + _, _ = fmt.Fprint(w, `{"session": {"sid": "test-sid", "message": "Login successful"}}`) }) client, server := setupTestServer(handler, "test-password") defer server.Close() @@ -47,7 +47,7 @@ func TestLogin(t *testing.T) { t.Run("api error on login", func(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusUnauthorized) - fmt.Fprint(w, `{"session": {"sid": "", "message": "Invalid password"}}`) + _, _ = fmt.Fprint(w, `{"session": {"sid": "", "message": "Invalid password"}}`) }) client, server := setupTestServer(handler, "wrong-password") defer server.Close() @@ -69,7 +69,7 @@ func TestLogout(t *testing.T) { assert.Equal(t, "test-sid", r.Header.Get("X-FTL-SID")) deleteCalled = true w.WriteHeader(http.StatusOK) - fmt.Fprint(w, `{"session": {"sid": "", "message": "Session deleted"}}`) + _, _ = fmt.Fprint(w, `{"session": {"sid": "", "message": "Session deleted"}}`) }) client, server := setupTestServer(handler, "test-password") defer server.Close() @@ -99,7 +99,7 @@ func TestLogout(t *testing.T) { assert.Equal(t, "/api/auth", r.URL.Path) assert.Equal(t, "DELETE", r.Method) w.WriteHeader(http.StatusNotFound) - fmt.Fprint(w, `{}`) + _, _ = fmt.Fprint(w, `{}`) }) client, server := setupTestServer(handler, "test-password") defer server.Close() @@ -123,7 +123,7 @@ func TestAddDnsRecords(t *testing.T) { // 1. First, the function gets the existing records. w.WriteHeader(http.StatusOK) // Respond with one existing record. - fmt.Fprint(w, `{"config": {"dns": {"hosts": ["1.1.1.1 one.com"]}}}`) + _, _ = fmt.Fprint(w, `{"config": {"dns": {"hosts": ["1.1.1.1 one.com"]}}}`) return } @@ -138,7 +138,7 @@ func TestAddDnsRecords(t *testing.T) { assert.ElementsMatch(t, expectedRecords, payload.Config.DNS.Hosts) w.WriteHeader(http.StatusOK) - fmt.Fprint(w, `{"success": true}`) + _, _ = fmt.Fprint(w, `{"success": true}`) return } @@ -168,7 +168,7 @@ func TestDeleteDnsRecords(t *testing.T) { if r.Method == http.MethodGet { w.WriteHeader(http.StatusOK) // Respond with three existing records, two of which we will delete. - fmt.Fprint(w, `{"config": {"dns": {"hosts": ["1.1.1.1 one.com", "2.2.2.2 two.com", "3.3.3.3 three.com"]}}}`) + _, _ = fmt.Fprint(w, `{"config": {"dns": {"hosts": ["1.1.1.1 one.com", "2.2.2.2 two.com", "3.3.3.3 three.com"]}}}`) return } @@ -183,7 +183,7 @@ func TestDeleteDnsRecords(t *testing.T) { assert.ElementsMatch(t, expectedRecords, payload.Config.DNS.Hosts) w.WriteHeader(http.StatusOK) - fmt.Fprint(w, `{"success": true}`) + _, _ = fmt.Fprint(w, `{"success": true}`) return } t.Fatalf("Received unexpected request: %s %s", r.Method, r.URL.Path) @@ -206,7 +206,7 @@ func TestDeleteDnsRecords(t *testing.T) { assert.Equal(t, http.MethodGet, r.Method) w.WriteHeader(http.StatusOK) - fmt.Fprint(w, `{"config": {"dns": {"hosts": ["1.1.1.1 one.com"]}}}`) + _, _ = fmt.Fprint(w, `{"config": {"dns": {"hosts": ["1.1.1.1 one.com"]}}}`) if r.Method == http.MethodPatch { patchCalled = true @@ -277,7 +277,7 @@ func TestAddCNameRecords(t *testing.T) { // 1. First, the function gets the existing cname records. w.WriteHeader(http.StatusOK) // Respond with one existing cname record. - fmt.Fprint(w, `{"config": {"dns": {"cnameRecords": ["one.com,one.two.com"]}}}`) + _, _ = fmt.Fprint(w, `{"config": {"dns": {"cnameRecords": ["one.com,one.two.com"]}}}`) return } @@ -292,7 +292,7 @@ func TestAddCNameRecords(t *testing.T) { assert.ElementsMatch(t, expectedCNames, payload.Config.DNS.CnameRecords) w.WriteHeader(http.StatusOK) - fmt.Fprint(w, `{"success": true}`) + _, _ = fmt.Fprint(w, `{"success": true}`) return } @@ -322,7 +322,7 @@ func TestDeleteCNameRecords(t *testing.T) { if r.Method == http.MethodGet { w.WriteHeader(http.StatusOK) // Respond with three existing cname records, two of which we will delete. - fmt.Fprint(w, `{"config": {"dns": {"cnameRecords": ["one.com,one.two.com", "two.com,two.two.com", "three.com,three.two.com"]}}}`) + _, _ = fmt.Fprint(w, `{"config": {"dns": {"cnameRecords": ["one.com,one.two.com", "two.com,two.two.com", "three.com,three.two.com"]}}}`) return } @@ -337,7 +337,7 @@ func TestDeleteCNameRecords(t *testing.T) { assert.ElementsMatch(t, expectedCNames, payload.Config.DNS.CnameRecords) w.WriteHeader(http.StatusOK) - fmt.Fprint(w, `{"success": true}`) + _, _ = fmt.Fprint(w, `{"success": true}`) return } t.Fatalf("Received unexpected request: %s %s", r.Method, r.URL.Path) @@ -360,7 +360,7 @@ func TestDeleteCNameRecords(t *testing.T) { assert.Equal(t, http.MethodGet, r.Method) w.WriteHeader(http.StatusOK) - fmt.Fprint(w, `{"config": {"dns": {"cname": ["one.com,one.two.com"]}}}`) + _, _ = fmt.Fprint(w, `{"config": {"dns": {"cnameRecords": ["one.com,one.two.com"]}}}`) if r.Method == http.MethodPatch { patchCalled = true diff --git a/pkg/clients/pihole/types.go b/pkg/clients/pihole/types.go index b6092d4..6952c45 100644 --- a/pkg/clients/pihole/types.go +++ b/pkg/clients/pihole/types.go @@ -28,17 +28,20 @@ type configResponse struct { Hosts []string `json:"hosts"` DomainNeeded bool `json:"domainNeeded"` ExpandHosts bool `json:"expandHosts"` - Domain string `json:"domain"` - BogusPriv bool `json:"bogusPriv"` - Dnssec bool `json:"dnssec"` - Interface string `json:"interface"` - HostRecord string `json:"hostRecord"` - ListeningMode string `json:"listeningMode"` - QueryLogging bool `json:"queryLogging"` - CnameRecords []any `json:"cnameRecords"` - Port int `json:"port"` - RevServers []any `json:"revServers"` - Cache struct { + Domain struct { + Name string `json:"name"` + Local bool `json:"local"` + } `json:"domain"` + BogusPriv bool `json:"bogusPriv"` + Dnssec bool `json:"dnssec"` + Interface string `json:"interface"` + HostRecord string `json:"hostRecord"` + ListeningMode string `json:"listeningMode"` + QueryLogging bool `json:"queryLogging"` + CnameRecords []any `json:"cnameRecords"` + Port int `json:"port"` + RevServers []any `json:"revServers"` + Cache struct { Size int `json:"size"` Optimizer int `json:"optimizer"` UpstreamBlockedTTL int `json:"upstreamBlockedTTL"` diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index e8d0b32..7214326 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -103,7 +103,7 @@ func TestGetConfig_EnvVars(t *testing.T) { "NGINX_PROXY_MANAGER_USERNAME": "user", "PIHOLE_HOST": "pihole.example.com", "PIHOLE_PASSWORD": "pihole_pass", - "METRICS_SERVER_PORT": "0", + "METRICS_SERVER_PORT": "0", }, expectedConfig: nil, expectErr: true, @@ -405,7 +405,7 @@ func unsetAllConfigEnvVars() { field := typ.Field(i) envName := field.Tag.Get("env") if envName != "" { - os.Unsetenv(envName) + _ = os.Unsetenv(envName) } } }