Skip to content

Commit 44874cc

Browse files
committed
feat(cloudflare): add access helpers and scoped retry controls
- Add Scope and AccessService helpers for account and zone Access endpoints - Add request-level retry controls for unsafe methods via explicit opt-in - Add zone pagination handling and use per_page=1 for zone lookup requests - Expand lint config and add tests for Access flows and transport retries Improves Cloudflare client safety by making non-idempotent retries explicit. Adds first-class Access API workflows with account and zone scoping.
1 parent f6bca35 commit 44874cc

7 files changed

Lines changed: 847 additions & 33 deletions

File tree

.golangci.yaml

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,76 @@
1-
---
21
version: "2"
3-
42
run:
53
timeout: 5m
6-
4+
concurrency: 4
75
linters:
86
enable:
7+
- asciicheck
8+
- asasalint
9+
- bidichk
10+
- bodyclose
11+
- contextcheck
12+
- copyloopvar
13+
- durationcheck
914
- errcheck
15+
- errchkjson
16+
- errorlint
17+
- exhaustive
1018
- govet
19+
- gocheckcompilerdirectives
20+
- gochecksumtype
21+
- gosec
22+
- gosmopolitan
1123
- ineffassign
24+
- loggercheck
25+
- makezero
26+
- musttag
27+
- nilerr
28+
- nilnesserr
29+
- noctx
30+
- protogetter
31+
- reassign
32+
- recvcheck
33+
- revive
34+
- rowserrcheck
35+
- spancheck
1236
- staticcheck
37+
- sqlclosecheck
38+
- testifylint
39+
- unparam
1340
- unused
14-
41+
- zerologlint
42+
exclusions:
43+
generated: lax
44+
presets:
45+
- comments
46+
- common-false-positives
47+
- legacy
48+
- std-error-handling
49+
rules:
50+
- path: (.+)\.go$
51+
text: should not use dot imports
52+
paths:
53+
- .github
54+
- third_party$
55+
- builtin$
56+
- examples$
57+
settings:
58+
revive:
59+
confidence: 0.1
60+
staticcheck:
61+
checks:
62+
- all
63+
- '-QF1008'
64+
formatters:
65+
enable:
66+
- gofmt
67+
exclusions:
68+
generated: lax
69+
paths:
70+
- .github
71+
- third_party$
72+
- builtin$
73+
- examples$
1574
issues:
1675
max-issues-per-linter: 0
1776
max-same-issues: 0

cloudflare/access.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package cloudflare
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"net/http"
8+
"net/url"
9+
"strings"
10+
)
11+
12+
// AccessService provides Cloudflare Access and Zero Trust API operations.
13+
type AccessService struct {
14+
client *Client
15+
}
16+
17+
// Access returns the Access service API.
18+
func (c *Client) Access() *AccessService {
19+
return &AccessService{client: c}
20+
}
21+
22+
// Do performs a scoped Access API request.
23+
func (a *AccessService) Do(
24+
ctx context.Context,
25+
scope Scope,
26+
method string,
27+
endpoint string,
28+
params url.Values,
29+
requestBody any,
30+
out any,
31+
reqOpts ...RequestOption,
32+
) error {
33+
prefix, err := scope.PathPrefix()
34+
if err != nil {
35+
return err
36+
}
37+
38+
cleanEndpoint := strings.TrimPrefix(strings.TrimSpace(endpoint), "/")
39+
if cleanEndpoint == "" {
40+
return errors.New("access endpoint must not be empty")
41+
}
42+
43+
return a.client.DoWithOptions(
44+
ctx,
45+
method,
46+
fmt.Sprintf("/%s/%s", prefix, cleanEndpoint),
47+
params,
48+
requestBody,
49+
out,
50+
reqOpts...,
51+
)
52+
}
53+
54+
// CreateIdentityProvider creates an Access identity provider (login method).
55+
func (a *AccessService) CreateIdentityProvider(
56+
ctx context.Context,
57+
accountID string,
58+
requestBody any,
59+
out any,
60+
reqOpts ...RequestOption,
61+
) error {
62+
return a.Do(
63+
ctx,
64+
AccountScope(accountID),
65+
http.MethodPost,
66+
"/access/identity_providers",
67+
nil,
68+
requestBody,
69+
out,
70+
reqOpts...,
71+
)
72+
}
73+
74+
// CreateApplication creates an Access application at account or zone scope.
75+
func (a *AccessService) CreateApplication(
76+
ctx context.Context,
77+
scope Scope,
78+
requestBody any,
79+
out any,
80+
reqOpts ...RequestOption,
81+
) error {
82+
return a.Do(
83+
ctx,
84+
scope,
85+
http.MethodPost,
86+
"/access/apps",
87+
nil,
88+
requestBody,
89+
out,
90+
reqOpts...,
91+
)
92+
}
93+
94+
// CreateReusablePolicy creates a reusable Access policy at account scope.
95+
func (a *AccessService) CreateReusablePolicy(
96+
ctx context.Context,
97+
accountID string,
98+
requestBody any,
99+
out any,
100+
reqOpts ...RequestOption,
101+
) error {
102+
return a.Do(
103+
ctx,
104+
AccountScope(accountID),
105+
http.MethodPost,
106+
"/access/policies",
107+
nil,
108+
requestBody,
109+
out,
110+
reqOpts...,
111+
)
112+
}
113+
114+
// CreateApplicationPolicy creates an application-scoped Access policy.
115+
func (a *AccessService) CreateApplicationPolicy(
116+
ctx context.Context,
117+
scope Scope,
118+
appID string,
119+
requestBody any,
120+
out any,
121+
reqOpts ...RequestOption,
122+
) error {
123+
cleanAppID := strings.TrimSpace(appID)
124+
if cleanAppID == "" {
125+
return errors.New("app ID must not be empty")
126+
}
127+
128+
return a.Do(
129+
ctx,
130+
scope,
131+
http.MethodPost,
132+
fmt.Sprintf("/access/apps/%s/policies", url.PathEscape(cleanAppID)),
133+
nil,
134+
requestBody,
135+
out,
136+
reqOpts...,
137+
)
138+
}

0 commit comments

Comments
 (0)