From 540fa2b3b2c215a4c43a8e2cef936b9973ffee23 Mon Sep 17 00:00:00 2001 From: Cameron Stokes Date: Mon, 9 Jun 2025 10:27:41 -0400 Subject: [PATCH 1/2] format output with hujsonfmt Updates #29 --- Makefile | 4 +- go.mod | 5 +- go.sum | 2 + main.go | 24 +- testdata/output-file-to-compare-to.hujson | 434 +++++++++++----------- 5 files changed, 242 insertions(+), 227 deletions(-) diff --git a/Makefile b/Makefile index 1f5d9ba..9eaf038 100644 --- a/Makefile +++ b/Makefile @@ -4,5 +4,5 @@ testdata: -v \ -f testdata/input-parent.hujson \ -d testdata/departments/ \ - -o testdata/output-file-to-compare-to.hujson \ - -allow=acls,autoApprovers,grants,groups,ipsets,ssh,tests,sshTests + -allow=acls,autoApprovers,grants,groups,ipsets,ssh,tests,sshTests \ + -o testdata/output-file-to-compare-to.hujson diff --git a/go.mod b/go.mod index 40fcb91..1d6449a 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,11 @@ module github.com/tailscale-dev/tailscale-acl-combiner -go 1.21 +go 1.23 + +toolchain go1.23.10 require github.com/creachadair/jtree v0.0.0-20231211041502-6ba355703cad +require github.com/tailscale/hujson v0.0.0-20250605163823-992244df8c5a require ( go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect diff --git a/go.sum b/go.sum index 5fcf109..d561e70 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw= github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8= +github.com/tailscale/hujson v0.0.0-20250605163823-992244df8c5a h1:a6TNDN9CgG+cYjaeN8l2mc4kSz2iMiCDQxPEyltUV/I= +github.com/tailscale/hujson v0.0.0-20250605163823-992244df8c5a/go.mod h1:EbW0wDK/qEUYI0A5bqq0C2kF8JTQwWONmGDBbzsxxHo= go4.org/mem v0.0.0-20220726221520-4f986261bf13 h1:CbZeCBZ0aZj8EfVgnqQcYZgf0lpZ3H9rmp5nkDTAst8= go4.org/mem v0.0.0-20220726221520-4f986261bf13/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 h1:/yRP+0AN7mf5DkD3BAI6TOFnd51gEoDEb8o35jIFtgw= diff --git a/main.go b/main.go index 451a6c4..d51f875 100644 --- a/main.go +++ b/main.go @@ -13,6 +13,7 @@ import ( "github.com/creachadair/jtree/ast" "github.com/creachadair/jtree/jwcc" + "github.com/tailscale/hujson" ) var ( @@ -304,6 +305,17 @@ func gatherChildren(path string) ([]*ParsedDocument, error) { } func outputFile(doc *jwcc.Object) error { + var sb strings.Builder + err := jwcc.Format(&sb, doc) + if err != nil { + return err + } + + formatted, err := hujson.Format([]byte(sb.String())) + if err != nil { + return err + } + if *outFile != "" { f, err := os.Create(*outFile) if err != nil { @@ -312,18 +324,10 @@ func outputFile(doc *jwcc.Object) error { defer f.Close() w := bufio.NewWriter(f) - err = jwcc.Format(w, doc) - if err != nil { - return err - } - w.WriteString("\n") + w.Write(formatted) w.Flush() } else { - err := jwcc.Format(os.Stdout, doc) - if err != nil { - return err - } - fmt.Printf("\n") + fmt.Print(string(formatted)) } return nil } diff --git a/testdata/output-file-to-compare-to.hujson b/testdata/output-file-to-compare-to.hujson index 934b857..7a13910 100644 --- a/testdata/output-file-to-compare-to.hujson +++ b/testdata/output-file-to-compare-to.hujson @@ -1,216 +1,222 @@ { - // from `testdata/input-parent.hujson` - "RandomizeClientPort": true, // inline comment - - "acls": [ - // from `testdata/departments/engineering/acls.hujson` - { - // engineering1 - "action": "accept", - - "src": ["engineering1@example.com"], - "dst": ["tag:demo-infra:22"], - "srcPosture": ["posture:latestMac"], - }, - { - // engineering2 - "action": "accept", - - "src": ["engineering2@example.com"], - "dst": ["tag:demo-infra:22"], - "srcPosture": ["posture:latestMac"], - }, - { - // engineering3 - "action": "accept", - - "src": ["engineering3@example.com"], - "dst": ["tag:demo-infra:22"], - "srcPosture": ["posture:latestMac"], - }, - // from `testdata/departments/engineering/acls.json` - { - "action": "accept", - "src": ["engineering@example.com"], - "dst": ["tag:json-rule:22"], - "srcPosture": ["posture:latestMac"], - }, - // from `testdata/departments/finance/acls.hujson` - { - // finance1 - "action": "accept", - - "src": ["finance1@example.com"], - "dst": ["tag:demo-infra:22"], - }, - { - // finance2 - "action": "accept", - - "src": ["finance2@example.com"], - "dst": ["tag:demo-infra:22"], - }, - ], - - "autoApprovers": { - "exitNode": [ - // from `testdata/departments/engineering/autoApprovers.hujson` - "tag:engineering", - ], - - "routes": { - // from `testdata/departments/engineering/autoApprovers.hujson` - "10.0.0.0/32": ["tag:engineering"], - - // from `testdata/departments/finance/autoApprovers.hujson` - "10.0.10.0/32": ["tag:finance"], - }, - }, - - "extraDNSRecords": [ - // from `testdata/input-parent.hujson` - { - "Name": "exra.dns.records", - "Value": "100.100.100.100", - }, - ], - - "grants": [ - // from `testdata/departments/engineering/grants.hujson` - { - //"src": ["group:prod"], - "src": ["engineering@example.com"], - - "dst": ["tag:k8s-operator"], - "app": {"tailscale.com/cap/kubernetes": [{"impersonate":{"groups":["system:masters"]}}]}, - }, - ], - - "groups": { - // from `testdata/input-parent.hujson` - "group:parent": ["from-parent"], - - // from `testdata/departments/engineering/groups.hujson` - "group:engineering": ["user1@example.com"], - - // from `testdata/departments/finance/acls.hujson` - "group:finance": ["finance@example.com"], - }, - - "ipsets": { - // from `testdata/input-parent.hujson` - "ipset:parent": ["192.0.2.0"], - - // from `testdata/departments/finance/ipsets.hujson` - "ipset:finance": ["192.0.2.1"], - }, - - "nodeAttrs": [ - // from `testdata/input-parent.hujson` - { - "target": ["*"], - - "app": { - "tailscale.com/app-connectors": [ - { - "name": "github", - "connectors": ["tag:demo-appconnector"], - "domains": ["github.com", "*.github.com"], - }, - ], - }, - }, - { - // mullvad for all admins - "attr": ["mullvad"], - - "target": ["autogroup:admin"], - }, - { - "target": ["user4@example.com", "tag:server"], - "attr": ["nextdns:abc123", "nextdns:no-device-info"], - }, - ], - - "postures": { - // from `testdata/input-parent.hujson` - "posture:latestMac": ["node:os IN ['macos', 'linux']", "node:tsReleaseTrack == 'stable'", "node:tsVersion >= '1.40'"], - }, - - "ssh": [ - // from `testdata/input-parent.hujson` - { - "action": "accept", - "src": ["autogroup:member"], - "dst": ["autogroup:self"], - "users": ["root", "autogroup:nonroot"], - }, - // from `testdata/departments/engineering/acls.hujson` - { - "action": "accept", - "src": ["group:engineering"], - "dst": ["autogroup:self"], - "users": ["root", "autogroup:nonroot"], - }, - // from `testdata/departments/engineering/acls.json` - { - "action": "accept", - "src": ["engineering@example.com"], - "dst": ["autogroup:self"], - "users": ["root", "autogroup:nonroot"], - }, - // from `testdata/departments/finance/ssh.hujson` - { - "action": "accept", - "src": ["autogroup:member"], - "dst": ["tag:finance"], - "users": ["root", "autogroup:nonroot"], - }, - { - "action": "accept", - "src": ["tag:finance"], - "dst": ["tag:finance"], - "users": ["root", "autogroup:nonroot"], - }, - ], - - "sshTests": [ - // from `testdata/input-parent.hujson` - { - "src": ["autogroup:member"], - "dst": ["autogroup:self"], - "accept": ["root", "autogroup:nonroot"], - }, - // from `testdata/departments/engineering/acls.json` - { - "src": ["engineering@example.com"], - "dst": ["autogroup:self"], - "accept": ["root", "autogroup:nonroot"], - }, - ], - - "tagOwners": { - // from `testdata/input-parent.hujson` - "tag:parent": [], - - "tag:user1": ["autogroup:member"], - "tag:dave": [], - "tag:jane": [], - }, - - "tests": [ - // from `testdata/departments/engineering/acls.hujson` - { - "src": "engineering@example.com", - "accept": ["tag:dev:22"], - }, - // from `testdata/departments/finance/acls.hujson` - { - "src": "finance@example.com", - "srcPostureAttrs": {"node:os": "windows"}, - "proto": "tcp", - "accept": ["example-host-1:22", "vega:80"], - "deny": ["1.2.3.4:443"], - }, - ], + // from `testdata/input-parent.hujson` + "RandomizeClientPort": true, // inline comment + + "acls": [ + // from `testdata/departments/engineering/acls.hujson` + { + // engineering1 + "action": "accept", + + "src": ["engineering1@example.com"], + "dst": ["tag:demo-infra:22"], + "srcPosture": ["posture:latestMac"], + }, + { + // engineering2 + "action": "accept", + + "src": ["engineering2@example.com"], + "dst": ["tag:demo-infra:22"], + "srcPosture": ["posture:latestMac"], + }, + { + // engineering3 + "action": "accept", + + "src": ["engineering3@example.com"], + "dst": ["tag:demo-infra:22"], + "srcPosture": ["posture:latestMac"], + }, + // from `testdata/departments/engineering/acls.json` + { + "action": "accept", + "src": ["engineering@example.com"], + "dst": ["tag:json-rule:22"], + "srcPosture": ["posture:latestMac"], + }, + // from `testdata/departments/finance/acls.hujson` + { + // finance1 + "action": "accept", + + "src": ["finance1@example.com"], + "dst": ["tag:demo-infra:22"], + }, + { + // finance2 + "action": "accept", + + "src": ["finance2@example.com"], + "dst": ["tag:demo-infra:22"], + }, + ], + + "autoApprovers": { + "exitNode": [ + // from `testdata/departments/engineering/autoApprovers.hujson` + "tag:engineering", + ], + + "routes": { + // from `testdata/departments/engineering/autoApprovers.hujson` + "10.0.0.0/32": ["tag:engineering"], + + // from `testdata/departments/finance/autoApprovers.hujson` + "10.0.10.0/32": ["tag:finance"], + }, + }, + + "extraDNSRecords": [ + // from `testdata/input-parent.hujson` + { + "Name": "exra.dns.records", + "Value": "100.100.100.100", + }, + ], + + "grants": [ + // from `testdata/departments/engineering/grants.hujson` + { + //"src": ["group:prod"], + "src": ["engineering@example.com"], + + "dst": ["tag:k8s-operator"], + "app": { + "tailscale.com/cap/kubernetes": [{"impersonate": {"groups": ["system:masters"]}}], + }, + }, + ], + + "groups": { + // from `testdata/input-parent.hujson` + "group:parent": ["from-parent"], + + // from `testdata/departments/engineering/groups.hujson` + "group:engineering": ["user1@example.com"], + + // from `testdata/departments/finance/acls.hujson` + "group:finance": ["finance@example.com"], + }, + + "ipsets": { + // from `testdata/input-parent.hujson` + "ipset:parent": ["192.0.2.0"], + + // from `testdata/departments/finance/ipsets.hujson` + "ipset:finance": ["192.0.2.1"], + }, + + "nodeAttrs": [ + // from `testdata/input-parent.hujson` + { + "target": ["*"], + + "app": { + "tailscale.com/app-connectors": [ + { + "name": "github", + "connectors": ["tag:demo-appconnector"], + "domains": ["github.com", "*.github.com"], + }, + ], + }, + }, + { + // mullvad for all admins + "attr": ["mullvad"], + + "target": ["autogroup:admin"], + }, + { + "target": ["user4@example.com", "tag:server"], + "attr": ["nextdns:abc123", "nextdns:no-device-info"], + }, + ], + + "postures": { + // from `testdata/input-parent.hujson` + "posture:latestMac": [ + "node:os IN ['macos', 'linux']", + "node:tsReleaseTrack == 'stable'", + "node:tsVersion >= '1.40'", + ], + }, + + "ssh": [ + // from `testdata/input-parent.hujson` + { + "action": "accept", + "src": ["autogroup:member"], + "dst": ["autogroup:self"], + "users": ["root", "autogroup:nonroot"], + }, + // from `testdata/departments/engineering/acls.hujson` + { + "action": "accept", + "src": ["group:engineering"], + "dst": ["autogroup:self"], + "users": ["root", "autogroup:nonroot"], + }, + // from `testdata/departments/engineering/acls.json` + { + "action": "accept", + "src": ["engineering@example.com"], + "dst": ["autogroup:self"], + "users": ["root", "autogroup:nonroot"], + }, + // from `testdata/departments/finance/ssh.hujson` + { + "action": "accept", + "src": ["autogroup:member"], + "dst": ["tag:finance"], + "users": ["root", "autogroup:nonroot"], + }, + { + "action": "accept", + "src": ["tag:finance"], + "dst": ["tag:finance"], + "users": ["root", "autogroup:nonroot"], + }, + ], + + "sshTests": [ + // from `testdata/input-parent.hujson` + { + "src": ["autogroup:member"], + "dst": ["autogroup:self"], + "accept": ["root", "autogroup:nonroot"], + }, + // from `testdata/departments/engineering/acls.json` + { + "src": ["engineering@example.com"], + "dst": ["autogroup:self"], + "accept": ["root", "autogroup:nonroot"], + }, + ], + + "tagOwners": { + // from `testdata/input-parent.hujson` + "tag:parent": [], + + "tag:user1": ["autogroup:member"], + "tag:dave": [], + "tag:jane": [], + }, + + "tests": [ + // from `testdata/departments/engineering/acls.hujson` + { + "src": "engineering@example.com", + "accept": ["tag:dev:22"], + }, + // from `testdata/departments/finance/acls.hujson` + { + "src": "finance@example.com", + "srcPostureAttrs": {"node:os": "windows"}, + "proto": "tcp", + "accept": ["example-host-1:22", "vega:80"], + "deny": ["1.2.3.4:443"], + }, + ], } From 7c0bdde2f03bd67e33d50b2245a473d4688d363f Mon Sep 17 00:00:00 2001 From: Cameron Stokes Date: Mon, 9 Jun 2025 10:29:18 -0400 Subject: [PATCH 2/2] go mod tidy --- go.mod | 1 + go.sum | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 1d6449a..25e1384 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.23 toolchain go1.23.10 require github.com/creachadair/jtree v0.0.0-20231211041502-6ba355703cad + require github.com/tailscale/hujson v0.0.0-20250605163823-992244df8c5a require ( diff --git a/go.sum b/go.sum index d561e70..7385989 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,6 @@ github.com/creachadair/jtree v0.0.0-20231211041502-6ba355703cad h1:2MMMgC7ORRjJH github.com/creachadair/jtree v0.0.0-20231211041502-6ba355703cad/go.mod h1:WP8iLZIRvdwzYE3ahHTQVJa3AvAjQLnSUHl/IfXPzeQ= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw= -github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8= github.com/tailscale/hujson v0.0.0-20250605163823-992244df8c5a h1:a6TNDN9CgG+cYjaeN8l2mc4kSz2iMiCDQxPEyltUV/I= github.com/tailscale/hujson v0.0.0-20250605163823-992244df8c5a/go.mod h1:EbW0wDK/qEUYI0A5bqq0C2kF8JTQwWONmGDBbzsxxHo= go4.org/mem v0.0.0-20220726221520-4f986261bf13 h1:CbZeCBZ0aZj8EfVgnqQcYZgf0lpZ3H9rmp5nkDTAst8=