Skip to content
Merged
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
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.PHONY: testdata
testdata:
go run . \
-v \
-f testdata/input-parent.hujson \
-d testdata/departments/ \
-o testdata/output-file-to-compare-to.hujson \
Expand Down
38 changes: 23 additions & 15 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,23 +138,17 @@ func handleArray() SectionHandler {
if childSection == nil {
return
}
parentProps := parent.FindKey(ast.TextEqual(sectionKey))
if parentProps != nil && len(parentProps.Value.(*jwcc.Array).Values) > 0 {
pathComment(parentProps.Value.(*jwcc.Array).Values[0], parentPath)
}

newArr := existingOrNewArray(*parent, sectionKey)
childArrValues := childSection.Value.(*jwcc.Array).Values

pathCommentAlreadyAdded := false
for i := range childArrValues {
newArr.Values = append(newArr.Values, childArrValues[i])
for _, v := range childSection.Value.(*jwcc.Array).Values {
newArr.Values = append(newArr.Values, v)

if !pathCommentAlreadyAdded {
pathComment(childArrValues[i], childPath)
pathComment(v, childPath)
pathCommentAlreadyAdded = true
}

}

upsertMember(parent, sectionKey, newArr)
Expand All @@ -166,10 +160,6 @@ func handleObject() SectionHandler {
if childSection == nil {
return
}
parentProps := parent.FindKey(ast.TextEqual(sectionKey))
if parentProps != nil {
pathComment(parentProps.Value.(*jwcc.Object).Members[0], parentPath)
}

newObj := existingOrNewObject(*parent, sectionKey)

Expand Down Expand Up @@ -222,13 +212,31 @@ func upsertMember[V *jwcc.Object | *jwcc.Array](doc *jwcc.Object, key string, va
}

func pathComment(val jwcc.Value, path string) {
// TODO: preserve existing comments
val.Comments().Before = []string{fmt.Sprintf("from `%s`", path)}
}

func mergeDocs(sections map[string]SectionHandler, parentDoc *ParsedDocument, childDocs []*ParsedDocument) error {
func addParentPathComments(parentDoc *ParsedDocument) error {
for _, parentSection := range parentDoc.Object.Members {
pathComment(parentSection, parentDoc.Path)
logVerbose("adding parent path comment to [%s]\n", parentSection.Key)
switch parentSection.Value.(type) {
default:
pathComment(parentSection, parentDoc.Path)
case *jwcc.Array:
pathComment(parentSection.Value.(*jwcc.Array).Values[0], parentDoc.Path)
case *jwcc.Object:
pathComment(parentSection.Value.(*jwcc.Object).Members[0], parentDoc.Path)
}
}
return nil
}

func mergeDocs(sections map[string]SectionHandler, parentDoc *ParsedDocument, childDocs []*ParsedDocument) error {
err := addParentPathComments(parentDoc)
if err != nil {
log.Fatal(err)
}

for _, child := range childDocs {
if child.Path == parentDoc.Path {
logVerbose("skipping [%s], same doc as parent\n", child.Path)
Expand Down
143 changes: 143 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"os"
"strings"
"testing"

Expand Down Expand Up @@ -163,6 +164,141 @@ func TestMergeDocsParentWithSameMember(t *testing.T) {
}
}

func TestPathCommentsForObject(t *testing.T) {
parent, err := jwcc.Parse(strings.NewReader(`{
"goodpath": {"bar":"foo"}
}`))
if err != nil {
t.Fatalf("expected no error, got [%v]", err)
}
parentDoc := &ParsedDocument{
Object: parent.Value.(*jwcc.Object),
Path: "parent",
}

child, err := jwcc.Parse(strings.NewReader(`{
"goodpath": {"foo":"bar"}
}`))
if err != nil {
t.Fatalf("expected no error, got [%v]", err)
}
childDoc := &ParsedDocument{
Object: child.Value.(*jwcc.Object),
Path: "child",
}

sections := map[string]SectionHandler{
"goodpath": handleObject(),
}

err = mergeDocs(sections, parentDoc, []*ParsedDocument{childDoc})
if err != nil {
t.Fatalf("expected no error, got [%v]", err)
}

if len(parentDoc.Object.Members) != 1 {
t.Fatalf("parent members length should be [1], got [%v]", len(parentDoc.Object.Members))
}

memberIndexKey := parentDoc.Object.IndexKey(ast.TextEqual("goodpath"))
if memberIndexKey != 0 {
t.Fatalf("section index key length should be [0], got [%v]", memberIndexKey)
}

member := parentDoc.Object.Members[memberIndexKey]
memberObjectMembers := member.Value.(*jwcc.Object).Members
if len(memberObjectMembers) != 2 {
t.Fatalf("member object keys length should be [2], got [%v]", len(memberObjectMembers))
}

barMember := member.Value.(*jwcc.Object).Find("bar")
if barMember.Value.String() != "foo" {
t.Fatalf("member value should be [foo], got [%v]", barMember.Value.String())
}
barMemberComments := barMember.Comments().Before
if barMemberComments[0] != "from `parent`" {
t.Fatalf("member comment should be [from `parent`], got [%v]", barMemberComments[0])
}

fooMember := member.Value.(*jwcc.Object).Find("foo")
if fooMember.Value.String() != "bar" {
t.Fatalf("member value should be [bar], got [%v]", fooMember.Value.String())
}
fooMemberComments := fooMember.Comments().Before
if fooMemberComments[0] != "from `child`" {
t.Fatalf("member comment should be [from `child`], got [%v]", fooMemberComments[0])
}
}

func TestPathCommentsForArray(t *testing.T) {
parent, err := jwcc.Parse(strings.NewReader(`{
"things": [{"thing1":"foo"}],
}`))
if err != nil {
t.Fatalf("expected no error, got [%v]", err)
}
parentDoc := &ParsedDocument{
Object: parent.Value.(*jwcc.Object),
Path: "parent",
}

child, err := jwcc.Parse(strings.NewReader(`{
"things": [{"thing2":"bar"}],
}`))
if err != nil {
t.Fatalf("expected no error, got [%v]", err)
}
childDoc := &ParsedDocument{
Object: child.Value.(*jwcc.Object),
Path: "child",
}

sections := map[string]SectionHandler{
"things": handleArray(),
}

err = mergeDocs(sections, parentDoc, []*ParsedDocument{childDoc})
if err != nil {
t.Fatalf("expected no error, got [%v]", err)
}

if len(parentDoc.Object.Members) != 1 {
t.Fatalf("parent members length should be [1], got [%v]", len(parentDoc.Object.Members))
}

thingsMember := parentDoc.Object.Find("things")
if thingsMember == nil {
t.Fatalf("section index key length should be not nil, got [%v]", thingsMember)
}

thingsMemberValues := thingsMember.Value.(*jwcc.Array).Values
if len(thingsMemberValues) != 2 {
t.Fatalf("members length should be [2], got [%v]", len(thingsMemberValues))
}

barMember := thingsMemberValues[0].(*jwcc.Object)
if barMember.Members[0].Key.String() != "thing1" {
t.Fatalf("member key should be [thing1], got [%v]", barMember.Members[0].Key.String())
}
if barMember.Members[0].Value.String() != "foo" {
t.Fatalf("member value should be [foo], got [%v]", barMember.Members[0].Value.String())
}
if barMember.Comments().Before[0] != "from `parent`" {
t.Fatalf("member comment should be [from `parent`], got [%v]", barMember.Comments().Before[0])
}

fooMember := thingsMemberValues[1].(*jwcc.Object)
if fooMember.Members[0].Key.String() != "thing2" {
t.Fatalf("member key should be [thing2], got [%v]", fooMember.Members[0].Key.String())
}
if fooMember.Members[0].Value.String() != "bar" {
t.Fatalf("member value should be [bar], got [%v]", fooMember.Members[0].Value.String())
}
if fooMember.Comments().Before[0] != "from `child`" {
t.Fatalf("member comment should be [from `parent`], got [%v]", fooMember.Comments().Before[0])
}
}

func TestExistingOrNewObject(t *testing.T) {
child, err := jwcc.Parse(strings.NewReader(`{
"goodpath": {"foo":"bar"}
Expand Down Expand Up @@ -423,3 +559,10 @@ func TestSort(t *testing.T) {
}
}
}

func printDocument(doc *ParsedDocument) {
err := jwcc.Format(os.Stdout, doc.Object)
if err != nil {
panic(err)
}
}
12 changes: 6 additions & 6 deletions testdata/departments/engineering/acls.hujson
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{ // engineering1
"action": "accept",
"src": [
"engineering1@tsjustworks.net",
"engineering1@example.com",
],
"dst": [
"tag:demo-infra:22",
Expand All @@ -22,7 +22,7 @@
{ // engineering2
"action": "accept",
"src": [
"engineering2@tsjustworks.net",
"engineering2@example.com",
],
"dst": [
"tag:demo-infra:22",
Expand All @@ -34,7 +34,7 @@
{ // engineering3
"action": "accept",
"src": [
"engineering3@tsjustworks.net",
"engineering3@example.com",
],
"dst": [
"tag:demo-infra:22",
Expand All @@ -46,14 +46,14 @@
],
"tests": [
{
"src": "cameron@example.com",
"accept": ["tag:cameron:22"],
"src": "engineering@example.com",
"accept": ["tag:dev:22"],
},
],
"ssh": [
{
"action": "accept",
"src": ["group:finance"],
"src": ["group:engineering"],
"dst": ["autogroup:self"],
"users": ["root", "autogroup:nonroot"],
},
Expand Down
2 changes: 1 addition & 1 deletion testdata/departments/engineering/acls.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{
"action": "accept",
"src": [
"[email protected]"
"[email protected]"
],
"dst": [
"tag:json-rule:22"
Expand Down
4 changes: 2 additions & 2 deletions testdata/departments/engineering/autoApprovers.hujson
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
"autoApprovers": {
"routes": {
"10.0.0.0/32": [
"tag:example"
"tag:engineering"
]
},
"exitNode": ["tag:example"],
"exitNode": ["tag:engineering"],
},
}
2 changes: 1 addition & 1 deletion testdata/departments/engineering/grants.hujson
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"grants": [
{
//"src": ["group:prod"],
"src": ["[email protected]"],
"src": ["[email protected]"],
"dst": ["tag:k8s-operator"],
"app": {
"tailscale.com/cap/kubernetes": [{
Expand Down
4 changes: 2 additions & 2 deletions testdata/departments/engineering/groups.hujson
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"groups": {
"group:group1": [
"[email protected]",
"group:engineering": [
"[email protected]",
],
},
}
10 changes: 5 additions & 5 deletions testdata/departments/finance/acls.hujson
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{ // finance1
"action": "accept",
"src": [
"finance1@tsjustworks.net",
"finance1@example.com",
],
"dst": [
"tag:demo-infra:22",
Expand All @@ -12,21 +12,21 @@
{ // finance2
"action": "accept",
"src": [
"finance2@tsjustworks.net",
"finance2@example.com",
],
"dst": [
"tag:demo-infra:22",
],
},
],
"groups": {
"group:group2": [
"[email protected]",
"group:finance": [
"[email protected]",
],
},
"tests": [
{
"src": "dave@example.com",
"src": "finance@example.com",
"srcPostureAttrs": {
"node:os": "windows",
},
Expand Down
2 changes: 1 addition & 1 deletion testdata/departments/finance/autoApprovers.hujson
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"autoApprovers": {
"routes": {
"10.0.10.0/32": [
"tag:example"
"tag:finance"
]
}
}
Expand Down
6 changes: 3 additions & 3 deletions testdata/departments/finance/ssh.hujson
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
{
"action": "accept",
"src": ["autogroup:member"],
"dst": ["tag:prod"],
"dst": ["tag:finance"],
"users": ["root", "autogroup:nonroot"],
},
{
"action": "accept",
"src": ["tag:logging"],
"dst": ["tag:prod"],
"src": ["tag:finance"],
"dst": ["tag:finance"],
"users": ["root", "autogroup:nonroot"],
},
],
Expand Down
Loading
Loading