Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions policyfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,32 @@ func (pr *PolicyFileResource) Set(ctx context.Context, acl any, etag string) err
return pr.do(req, nil)
}

// Set sets the [ACL] for the tailnet and returns the resulting [ACL].
// etag is an optional value that, if supplied, will be used in the "If-Match" HTTP request header.
func (pr *PolicyFileResource) SetAndGet(ctx context.Context, acl ACL, etag string) (*ACL, error) {
headers := make(map[string]string)
if etag != "" {
headers["If-Match"] = fmt.Sprintf("%q", etag)
}

reqOpts := []requestOption{
requestHeaders(headers),
requestBody(acl),
}

req, err := pr.buildRequest(ctx, http.MethodPost, pr.buildTailnetURL("acl"), reqOpts...)
if err != nil {
return nil, err
}

out, header, err := bodyWithResponseHeader[ACL](pr, req)
if err != nil {
return nil, err
}
out.ETag = header.Get("Etag")
return out, nil
}

// Validate validates the provided ACL via the API. acl can either be an [ACL], or a HuJSON string.
func (pr *PolicyFileResource) Validate(ctx context.Context, acl any) error {
reqOpts := []requestOption{
Expand Down
56 changes: 56 additions & 0 deletions policyfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,62 @@ func TestClient_SetACL(t *testing.T) {
assert.EqualValues(t, expectedACL, actualACL)
}

func TestClient_SetAndGetACL(t *testing.T) {
t.Parallel()

client, server := NewTestHarness(t)
server.ResponseCode = http.StatusOK
server.ResponseHeader.Set("ETag", "abcdefg")
in := ACL{
ACLs: []ACLEntry{
{
Action: "accept",
Ports: []string{"*:*"},
Users: []string{"*"},
},
},
TagOwners: map[string][]string{
"tag:example": {"group:example"},
},
Hosts: map[string]string{
"example-host-1": "100.100.100.100",
"example-host-2": "100.100.101.100/24",
},
Groups: map[string][]string{
"group:example": {
"[email protected]",
"[email protected]",
},
},
Tests: []ACLTest{
{
User: "[email protected]",
Allow: []string{"example-host-1:22", "example-host-2:80"},
Deny: []string{"exapmle-host-2:100"},
},
{
User: "[email protected]",
Allow: []string{"100.60.3.4:22"},
},
},
ETag: "abcdefg",
}
server.ResponseBody = in

out, err := client.PolicyFile().SetAndGet(context.Background(), in, "abcdefg")
assert.NoError(t, err)
assert.Equal(t, http.MethodPost, server.Method)
assert.Equal(t, "/api/v2/tailnet/example.com/acl", server.Path)
assert.Equal(t, `"abcdefg"`, server.Header.Get("If-Match"))
assert.EqualValues(t, "application/json", server.Header.Get("Content-Type"))
assert.EqualValues(t, &in, out)

var actualACL ACL
assert.NoError(t, json.Unmarshal(server.Body.Bytes(), &actualACL))
in.ETag = ""
assert.EqualValues(t, in, actualACL)
}

func TestClient_SetACL_HuJSON(t *testing.T) {
t.Parallel()

Expand Down
Loading